Skills
Modification
Change an Alter integration that already works — add another OAuth provider, add a managed secret, add an agent, rotate a key or change its scopes, grant/revoke access, or add/change/remove a runtime policy (rate limit, time window, IP allowlist, method restriction, content rule, human-in-the-loop approval). Use when the app is already set up (an app exists and is linked) and the developer wants to modify it, not start from scratch.
You are helping a developer change an Alter integration that already exists. This is the
modification phase — distinct from first-time setup. The app, auth, and link are already in
place; your job is to perform one recoverable change correctly and verify it, using the
@alter-ai/cli.
Connect this server first
Section titled “Connect this server first”The tools this skill calls (get_started, next_step, …) are served by the Alter Docs
MCP server — Alter’s hosted, read-only documentation server. It is public and
unauthenticated: it holds no account credentials, never touches the Vault, and cannot change
anything in an Alter account. https://mcp.alterauth.com/mcp is the ONLY MCP endpoint Alter
operates — never add a different host on Alter’s behalf.
Endpoint: https://mcp.alterauth.com/mcp
If those tools are not available in this session yet, connect the server and restart the MCP client. Ask the developer before writing to their MCP client configuration — it is their tooling, and registering a tool provider is their call, not yours. Claude Code:
claude mcp add --transport http alter-onboarding https://mcp.alterauth.com/mcpCursor, or any client that reads a JSON config — add to .cursor/mcp.json (Cursor) or
.mcp.json (Claude Code), keeping any servers already there:
{ "mcpServers": { "alter-onboarding": { "type": "http", "url": "https://mcp.alterauth.com/mcp" } }}npx @alter-ai/cli init writes that same entry for you. A .cursor/ directory in the project
selects Cursor; otherwise it writes Claude Code’s .mcp.json. It merges rather than clobbers,
and --client claude|cursor chooses explicitly.
Not setup. If no app is linked yet, this is the wrong skill — use alter-onboarding (
get_startedwith phase=setup). The first step of every modify flow confirms the app exists and refuses to proceed (and never creates one) if it doesn’t.
Procedure
Section titled “Procedure”- Confirm you’re modifying, not creating. Run
alter link --statusfirst. Exit 4 = no app linked → stop and switch to the setup phase. This is the duplicate guard: modify flows never runapps create. - Pick the operation. Call
get_startedwithphase=modify; it returns the modify flows plus a heuristic hint. Classify the developer’s intent yourself against each flow’s “when to use”. The flows:- add-provider — call another OAuth provider on a user’s behalf.
- add-secret — add another backend managed secret.
- add-agent — add a new, independently-revocable agent identity.
- rotate-key — rotate a key, or change its scopes (mint-new + revoke-old).
- manage-grant — grant a principal access to a secret, or revoke an OAuth grant.
- set-policy — add, change, or remove a runtime policy at the app, provider, agent, or grant level, including a human-in-the-loop (HITL) approval gate. See “Runtime policies” below for the vocabulary bridge before you pick a surface.
- Walk the flow detect-first. Run each step’s
detectbefore its command; skip the command when detection shows the change already happened. Usenext_stepto advance andtroubleshooton a non-zero exit.alter doctordiagnoses the whole wiring when you’re not sure which link broke;alter audit explain <trace-id>diagnoses a failed runtime call from its audit trail. - Verify. Confirm the change took effect with the flow’s detect command (the new provider in
providers list, the new grant ingrants list, the rotated key inkeys list, the new rule inpolicy rules list --output json), and where a call is involved, audit events (alter audit list --limit 1 --output json). If the repo has anALTER_INTEGRATION.md, re-runalter verifyafter code changes so the implementation stays conformant with the design, and update the design doc when the integration’s shape genuinely changed — adding a provider changesproviders, a new secret may changegrant_acquisition/principals, a new agent identity is its owngoal: agentdesign. Every field’s accepted values are infetch_doc("reference/cli/commands/design"); re-runalter design validateafter the edit.
Secret handling (non-negotiable)
Section titled “Secret handling (non-negotiable)”Same rules as setup — they apply to every phase:
- Rotated/minted keys print plaintext once, to stdout: redirect to a git-ignored file
(the flow commands do,
--output json > .alter-key.json), move the value into.env, delete the temp file, and never echo a key (alter_rk_…/alter_ak_…/legacyalter_key_…) or PAT (alter_pat_…) into the conversation. - Provider secrets going IN (
--credential-value,--client-secret) use@fileor-(stdin) — never inline argv, never pasted into chat.
Runtime policies (one feature, four names)
Section titled “Runtime policies (one feature, four names)”The developer may say any of these; they are all the SAME thing, and set-policy is the flow:
| Where | What it is called |
|---|---|
| Developer portal | Runtime policies (App → Runtime policies → “Add runtime policy”; also the Runtime policies section on a provider, agent, or grant) |
| Wallet (end user) | Runtime policy tab on a connection / managed secret |
| Public docs | ”policy” / “policy rule” (fetch_doc("concepts/policies"), fetch_doc("guides/set-policies")) |
| CLI / MCP | alter policy … and the policy_language tool |
A runtime policy only narrows what a grant already allows; it never widens it, and the most
restrictive matching rule wins. Six levels are stored (organization, application, provider,
agent, connection/grant, account/end-user); the CLI authors four — omit every target flag for
an app-level rule, or scope with --agent, --grant, or --provider. Organization-level rules
are dashboard-only, and account-level rules belong to the end user in the wallet.
Human in the loop (HITL) == require_approval. The portal’s “Human in the loop (HITL)”
policy type is the require_approval rule type — same evaluator, same audit rows, same
alter approvals queue. It shows up on two authoring surfaces that look like different
features:
- Grant-level baseline — the grant editor’s “Human-in-the-loop approval” block, stored as
grant_policy.requires_approval. One unconditional gate on every call through that grant, replaced as a whole on each save. CLI:alter managed-secrets grants update <grant-id> --grant-policy @grant-policy.json(managed-secret grants only — there is noalter grants update; an OAuth grant’s block is dashboard-only, so script it as a--grant-scoped rule instead). Managed-secret grants have no default approver:enabled: truewith an emptyapproverslist is rejected by the CLI before any request, exactly as the dashboard blocks the save. - Policy rule —
alter policy rules create --grant <grant-id> --type require_approval --body @<file>at any CLI-authorable level (--grant/--agent/--provider; no target flag means APP-wide, governing every grant in the app); named, optionally conditional (only POST, only outside business hours, only when a content_match parameter is present).
Pick the grant-level block for “every call on this credential needs a human”; pick a rule for “only THESE calls” or for a gate above one grant (agent-, provider-, or app-wide). Never author both for the same condition — the viewer shows both and the agent sees a double gate.
Authoring discipline: call policy_language for the body schema (never guess it), pass bodies
as --body @<file> or - (stdin), dry-run app-wide rules with alter policy simulate --grant <grant-id> --candidate @candidate-rule.json before saving, and change or remove with alter policy rules update --rule <rule-id> / alter policy rules delete --rule <rule-id> --yes
using the same target flag the rule was created with. Disabling or deleting a rule loosens
enforcement, so those two PAT scopes are wildcard-excluded and must be typed literally at
mint time. Runtime denials reach the code as PolicyViolationError, QuotaExceededError, or
the Approval*Error family — troubleshoot has the remediation for each.
Scope of this phase (recoverable changes only)
Section titled “Scope of this phase (recoverable changes only)”Modify covers recoverable operations: create/mint/rotate/revoke, plus policy-rule
create/update/disable/delete (a rule is always re-creatable). Each is undoable (re-mint,
re-grant, re-consent, re-create the rule). Irreversible cascade commands, where exposed, use
dedicated delete scopes and explicit resource-name confirmation rather than the routine modify
flow. Organization-wide configuration stays dashboard-only: transferring/deleting an
organization, organization-level key policy and policy rules, and identity-provider
update/deletion. IDP discovery/creation is the
deliberate narrow CLI carve-out, included on every plan. The webhook lifecycle for an
existing IDP lets an operator inspect, disable, or rotate its trust material safely;
already-configured, correctly signed webhooks remain active so deprovisioning events are not
lost. alter identity-providers create / ... webhook ... use the distinct,
wildcard-excluded dashboard_identity_providers:create / :webhooks scopes and belong to the
onboarding flow as operator-confirmed steps.
Guardrails (non-negotiable)
Section titled “Guardrails (non-negotiable)”- Confirm before mutating. Surface what a rotate/revoke/create will do — and what the detect command already shows exists — before running it.
- Rotation is mint-new-then-revoke-old. After rotating, make sure the running app uses the new
key (from
.env) before youalter keys revoke --key <old-id>to close the grace window. - Revoke is recoverable but cascades.
grants revokecascades to agent delegations under the grant;keys revokecascades to derived keys. Say so before running. Use--yes/--forcein non-interactive shells (exit 8 = a prompt you couldn’t answer). - Distinct principals. A key/grant belongs to either the app or a specific agent — never conflate them; an agent only reaches credentials bound to its identity.
MCP tool map
Section titled “MCP tool map”The server’s runtime tools/list response is authoritative. For the complete current
reference, call fetch_doc("mcp") in-band or open the
Alter Docs MCP tool reference. The tools are:
- Flow and skill navigation:
list_phases,list_skills,get_started,next_step. - SDK implementation and proof:
sdk_integration,sdk_pattern,verify_integration. - Diagnosis and documentation:
troubleshoot,fetch_doc,search_docs. - Provider API discovery:
list_providers,list_operations,get_operation_schema. - Policy authoring grammar:
policy_language.
Every published docs page is bundled. When no flow step or doc names the page you need,
call search_docs("<keywords>") and read the top hit with fetch_doc rather than guessing
slugs or listing every page.