# Integration Access Layer

## Secrets resolve through `lisa-secrets-access`

Credentials follow the same chokepoint discipline as vendor integrations: every secret a session needs resolves through the `lisa-secrets-access` skill, which owns the supported provider list (Bitwarden, 1Password, AWS, Doppler, Vault, env), the note format attached to each secret, the `tool:` declaration of which CLIs a credential drives, and the resolution and verification order.

That contract is deliberately **not restated here or anywhere else.** A second copy of the note format is a copy that drifts, and a drifted copy of a credential contract is worse than no copy, because it is followed. Read the skill.

The one operational consequence worth stating in an always-loaded rule: **do not ask a human to paste a value the configured provider can supply**, and do not read keychains, `.env` files, or provider CLIs directly to work around the skill. If resolution fails, the failure is a bug in the provider bootstrap and gets reported as one.

Every Lisa skill or rule that consumes an external integration MUST route through
the integration's `*-access` skill instead of calling that vendor's MCP tools or
REST API directly.

The access skill owns substrate resolution. **The ordering is not this rule's to
define** — it is the single shared contract in `credential-substrate-precedence`,
cited identically by every `*-access` skill:

1. **Configured-provider token/CLI substrate** — the path fed by
   `lisa-secrets-access` — when its bootstrap credential is present AND the
   resolved substrate identity-matches the configured tenant/workspace/account.
2. **Interactive MCP**, as a first-class fallback, when the provider path is
   genuinely unavailable (no bootstrap, no adapter for the operation, provider
   outage).
3. Loud failure naming the exact credential to set.

Identity-match verification is mandatory on **every** substrate, in both
directions; one authenticated as a different tenant is skipped, never used. See the
`credential-substrate-precedence` rule for the rationale (headless parity, tenant
safety, determinism), the guarded-fallback protocol, and what "genuinely
unavailable" means.

Do not blind-retry a failed or absent substrate, and never silently no-op when no
tier is available.

Some MCPs authenticate headlessly from an env token — such an MCP **is** the
configured-provider substrate on both developer machines and cloud routines, so it
sits at tier 1 with nothing above it to demote. The official SonarQube MCP is one
such case (`SONARQUBE_CLI_TOKEN` [+ `SONARQUBE_CLI_ORG`/`SONARQUBE_CLI_SERVER`]):
`lisa-sonarcloud-access` prefers it and falls back to the token-authenticated Sonar
Web API for reads on a surface where it is not wired. Reserve the browser-OAuth
demotion for vendors whose MCP is keychain-bound and therefore dead headless.

Being top of the ladder is not the same as being the whole ladder. An access layer
may say "prefer this substrate"; it may not say "this is the only one" while the
vendor exposes a token-authenticated API the same credential already opens.

## Access Skills

| Vendor | Access skill | Headless env var | REST/token substrate |
|---|---|---|---|
| Atlassian | `lisa-atlassian-access` | `ATLASSIAN_API_TOKEN` | Atlassian Cloud REST |
| Notion | `lisa-notion-access` | `NOTION_API_TOKEN` | Notion REST |
| Linear | `lisa-linear-access` | `LINEAR_API_KEY` | Linear GraphQL |
| Jam | `lisa-jam-access` | `JAM_PAT` | Jam CLI |
| SonarCloud | `lisa-sonarcloud-access` | `SONARQUBE_CLI_TOKEN` (+ `SONARQUBE_CLI_ORG`/`SONARQUBE_CLI_SERVER`) | Official SonarQube MCP (headless via token) |
| Sentry | `lisa-sentry-access` | `SENTRY_AUTH_TOKEN` | Sentry REST API |
| PostHog | `lisa-posthog-access` | `POSTHOG_PERSONAL_API_KEY` | PostHog REST API |
| Google Play | `lisa-expo:play-store-access` | `GOOGLE_PLAY_SERVICE_ACCOUNT_JSON` or `GOOGLE_PLAY_SERVICE_ACCOUNT_KEY_BASE64` | Google Play Developer API |

## Current Coupling Matrix

Source audit date: 2026-06-23. Scope: `plugins/src/**/skills/**` and
`plugins/src/**/rules/**`.

| Vendor | Direct source MCP references | Current route | Retrofit status |
|---|---:|---|---|
| Atlassian | setup-only references plus legacy stack-generated sources | `atlassian-access` for base runtime paths | Done for base hot paths; stack overlays still need sync from base patterns when touched. |
| Notion | setup-only references | `notion-access` | Done. |
| Linear | Multiple base queue/read/write/verify skills | Raw Linear MCP | Access layer added; consumers still need migration to `linear-access`. |
| Jam | None in `plugins/src` at audit time | No access layer | Access layer added for host rules that include Jam triage. |
| SonarCloud | Routed through `sonarcloud-access` | Official SonarQube MCP preferred; token-authed Web API as the read-only fallback | Migrated to the official token-authed SonarQube MCP; the bespoke REST *dispatch* was removed, which is not the same as forbidding a Web API read. |
| Sentry | No Sentry MCP references in `plugins/src`; CLI/REST mentions only | CLI/REST scattered in observability docs | Access layer added for future MCP-backed consumers. |
| PostHog | No PostHog MCP references in `plugins/src`; observability docs mention PostHog detection | No access layer | Access layer added for future MCP-backed consumers. |
| Google Play | No MCP surface; EAS submit docs only | `play-store-access` for Expo post-submit release visibility | Done for Expo stack. |

## Migration Rule For Consumers

When editing any skill listed in the matrix:

- Replace direct `mcp__<vendor>__*` calls in `allowed-tools` with `Skill` and
  delegate to the matching access skill.
- Keep operation names coarse and vendor-native. Add new operation rows to the
  access skill instead of embedding REST details in the consumer.
- Put the documented token/CLI substrate first and keep the MCP as an explicit,
  fully supported fallback tier — `credential-substrate-precedence`. Preserving
  the MCP adapters is required; re-ordering them is not the same as removing them.
- If a vendor has no documented token substrate, keep the MCP-only behavior and
  fail with a clear "no documented headless substrate" message.
