plugins/lisa/skills/lisa-sentry-access/SKILL.md
Vendor-neutral access layer for Sentry. Sentry-oriented skills MUST delegate through this skill rather than calling Sentry MCP tools, sentry-cli, or REST directly. Per the credential-substrate-precedence contract, resolves SENTRY_AUTH_TOKEN (REST, or sentry-cli authenticated from the same token) first when present and identity-matched to the configured org/project, then falls back to the Sentry MCP.
npx skillsauth add codyswanngt/lisa lisa-sentry-accessInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Single chokepoint for Sentry operations. Caller skills MUST NOT call
mcp__sentry__*, sentry-cli, or https://sentry.io/api/ directly.
operation: list-issues org:<ORG> project:<PROJECT> query:<QUERY> [environment:<ENV>]
operation: get-issue issue_id:<ID>
operation: events org:<ORG> project:<PROJECT> query:<QUERY>
operation: releases org:<ORG> project:<PROJECT>
Return parsed JSON in a <result> block.
Probe in order — the ordering is the shared credential-substrate-precedence
contract, not a Sentry-local choice. The first tier that is ready and
identity-matches the configured org/project is used; a substrate authenticated
against a different org is skipped, never used.
SENTRY_AUTH_TOKEN bearer token
against Sentry REST, resolved through lisa-secrets-access.sentry-cli, if installed and authenticated to the requested
org/project from that same token (the CLI arm of the provider substrate).SENTRY_AUTH_TOKEN, no REST/CLI adapter for the operation, or a Sentry outage.Sentry documents API auth tokens for REST API calls, and the same token works interactively and headlessly — which is why it leads. The REST tier uses:
# Resolve the token through the chokepoint before giving up on the environment.
# `$SENTRY_AUTH_TOKEN` is the documented fallback, not the only rung: without
# this, a project that keeps its credentials in Bitwarden, Doppler, or AWS has
# no tier 1 path at all and silently resolves through the interactive MCP —
# the exact divergence `credential-substrate-precedence` exists to remove.
# Mirrors `linear-access`, `atlassian-access`, and `notion-access`.
read_sentry_token() {
[ -n "${SENTRY_AUTH_TOKEN:-}" ] && { echo "$SENTRY_AUTH_TOKEN"; return; }
#
# Ordered across trusted machine-managed substrates, ending at the installed
# package. Checkout-local paths are deliberately absent: a familiar generated
# destination is still repository-controlled executable code. The plugin
# rungs are the floor: `resolve-secret.mjs` ships beside this skill, so a rung
# pointing at it is reachable from anywhere the plugin itself is installed.
# Without one, a consumer repository that vendors none of the leading paths
# never reaches a resolver at all — the ladder exits without having asked
# anything, which is what pushed agents into improvising their own credential
# lookups. This LADDER is identical in every skill that resolves a credential
# and `credential-resolver-ladder` fails if any copy diverges. Only what
# happens AFTER the ladder may differ between them.
# Execute only machine-managed plugin/package resolvers. Checkout-local
# candidates are repository-controlled code, not trusted merely by path.
local candidates=()
if [ -n "${CLAUDE_PLUGIN_ROOT:-}" ]; then
candidates+=("$CLAUDE_PLUGIN_ROOT/skills/lisa-secrets-access/scripts/resolve-secret.mjs")
fi
if [ -n "${PLUGIN_ROOT:-}" ]; then
candidates+=("$PLUGIN_ROOT/skills/lisa-secrets-access/scripts/resolve-secret.mjs")
fi
# Last rung deliberately needs no environment variable: an agent that was
# never handed a plugin root still has the installed package to fall back on.
candidates+=(node_modules/@codyswann/lisa/plugins/lisa/skills/lisa-secrets-access/scripts/resolve-secret.mjs)
local resolver
local tried=()
for resolver in "${candidates[@]}"; do
tried+=("$resolver")
if [ -f "$resolver" ]; then
local via_lisa
via_lisa=$(node "$resolver" get SENTRY_AUTH_TOKEN 2>/dev/null) \
&& [ -n "$via_lisa" ] && { echo "$via_lisa"; return; }
# Empty/error means this substrate had no answer; try the next trusted one.
fi
done
# Name every path. A bare `return 1` sends the next reader hunting for a
# resolver they cannot see the absence of; the enumeration turns that into a
# seconds-long diagnosis. Paths and store coordinates only — never any
# resolved value, on any path.
echo "Error: could not resolve SENTRY_AUTH_TOKEN through lisa-secrets-access." >&2
echo "Tried, in order (relative paths are from $PWD):" >&2
printf ' %s\n' "${tried[@]}" >&2
return 1
}
sentry_api() {
local path="$1"
local token
token=$(read_sentry_token) || {
echo "Error: no Sentry auth token. Set SENTRY_AUTH_TOKEN, or store it as" >&2
echo "SENTRY_AUTH_TOKEN in this project's secrets provider." >&2
return 1
}
curl -sS "https://sentry.io/api/0${path}" \
-H "Authorization: Bearer $token"
}
Tier 1a authenticates sentry-cli from the same resolved token
(SENTRY_AUTH_TOKEN=$(read_sentry_token) sentry-cli …) — never from a second
credential store, and never from an interactive sentry-cli login keychain.
If neither tier works, fail with:
Error: no Sentry access substrate available. Authenticate Sentry MCP/CLI or set SENTRY_AUTH_TOKEN.
Every operation in the Invocation Contract is read-only — issue, event, and
release retrieval. So the credential-substrate-precedence guarded fallback for
mutating operations (write, read back, assert the tenant from the response, roll
back on mismatch) is not engaged here, and a failed tier is simply skipped. Any
future operation that mutates Sentry state — resolving an issue, editing a
release — is a write and MUST reconcile by read-back under that protocol before
any retry; do not add one to the contract without it.
credential-substrate-precedence: SENTRY_AUTH_TOKEN first, the
Sentry MCP as a preserved first-class fallback. Identity-match against the
configured org/project is mandatory on every tier.lisa-secrets-access, with the bare
SENTRY_AUTH_TOKEN environment variable as the documented fallback. Never read
a second credential store (OS keychain, ~/.sentryclirc token) directly — the
one-store rule lives at the chokepoint..sentryclirc, .lisa.config.json, or explicit
operation args; never infer by searching all accessible orgs.development
Prepare a machine — a fresh laptop or a throwaway container — to run coding agents, before any repository exists. Detects which of Lisa's supported agents (Claude Code, Codex, Cursor, OpenCode, Antigravity, Copilot) are already installed, asks which credential manager the machine uses (Bitwarden, 1Password, Doppler, Vault, AWS, or none), and installs only what is missing, each by its vendor's own preferred method. Idempotent, headless by default, and emits a Dockerfile for a spin-up/spin-down environment. Run it on a new machine, in a container, or before cloning anything.
tools
Provision and verify a remote execution environment for a host project — Codex Cloud today, other remote surfaces as they are added. Generates a repository-owned setup script that installs the declared toolchain, materializes secrets through lisa-secrets-access, and runs the project's own hook. Provisions by API where one exists, by driving the vendor console where one does not, and by emitting exact config otherwise — then proves the result with the same read-back regardless of which tier did the work. Use before dispatching any work with executionEnv.
tools
Bring a developer's machine in line with the toolchain the project declares. Reports every tool in remoteEnv.tools that is missing, outdated, or unpinned for this platform, and installs the missing ones into ~/.local/bin from the same pinned, checksummed entries the remote surfaces use — but only when asked. Same manifest, same pins, same installers as lisa-setup-remote-env; what differs is consent and that the pin is a floor rather than an equality. Run it on a fresh checkout, after a manifest change, or when a tool fails at the moment of use.
tools
Route one unit of work to a remote execution surface. Reads the executionEnv parameter (local by default, codex-cloud or claude-web today), verifies the environment is provisioned and bound to this repository, submits a thin skill invocation, records the task identifier to .lisa/remote-dispatch.json, and exits without polling. Routing only — the remote runs the identical skill from the identical repository. Composable and inline: other skills invoke it via the Skill tool rather than users calling it directly.