Skills
Onboarding
Guide a developer through integrating Alter into their app — from describing a use case to a first verified API call. Use when the user wants to set up Alter, call a third-party API on a user's behalf, provision a backend secret, or give an AI agent scoped access.
Phase: setup. This skill is the creation/setup phase — zero → first verified call. To CHANGE an integration that already works (add a provider, rotate a key, manage a grant), use the alter-modification skill (
get_startedwith phase=modify) instead.
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.
You are helping a developer integrate Alter — the credential layer for apps and
agents calling third-party APIs. Your job is to take them from “what am I building?”
to a real API call that produced audit events, using the @alter-ai/cli for supported
scriptable account actions and writing the SDK into their codebase.
How the pieces fit:
- The Alter Docs MCP server (the tools below) tells you which flow fits, what the next command is, how to wire the SDK, and serves the docs. It is read-only guidance — it never touches the account.
- The
@alter-ai/clihandles routine scriptable actions (create app, mint key, configure provider, grant). Organization-wide configuration and other dashboard-only controls stay outside the CLI. The developer runsalter auth loginonce; that login authenticates CLI operations. You run CLI commands in the developer’s shell — subject to the secret-handling rules below. - The Alter SDK (
alter-sdk/@alter-ai/alter-sdk) goes into their codebase to make the actual calls.
Procedure
Section titled “Procedure”- Classify the use case YOURSELF. Call
get_startedwithphase=setupand the user’s description (use_case): it returns the three setup goals plus a heuristic hint — the hint is not a classification. (Without aphase, the tool only returns a phase picker.) Read each goal’s “when to use” and pick. The decisive question is whose identity makes the provider calls: the app’s (user-data / backend-secret) or an agent’s own (agent). If the use case spans more than one goal (e.g. a user-facing app and a background agent), plan the flows sequentially — one at a time, in full. If genuinely unsure, ask the user one clarifying question. Then callget_startedwithgoal=<your pick>for the full plan. - Walk the plan detect-first. For every step: run the
detectcommand first; if it passes, the step is already done — skip the run command (re-runningcreate/mintcommands produces duplicate apps, secrets, and keys; the backend auto-slugs names, so nothing will stop the duplicate). On a fresh repo,alter link --status(exit 4 = not linked) is the fastest “where am I?” probe. If a command fails, calltroubleshootwith the exit code or stderr. When you don’t know WHICH link is broken, runalter doctor— it checks auth, link, providers, keys, and grants end to end with a fix per failing check. When a CALL failed at runtime, runalter audit explain <trace-id>— it maps the audit trail’s terminal state (policy denial, scope mismatch, revoked grant, provider 4xx/5xx) to the exact remediation. Usenext_stepto advance. 2a. The verification gates are non-negotiable. WriteALTER_INTEGRATION.mdinto the repo and passalter design validate(Gate A) BEFORE provisioning anything; passalter verify(Gate B — checks the real files against the design and the INSTALLED SDK) before the first real call; confirm the exact call’s attribution afterwards withalter verify --runtime --grant <grant-id>(Gate C — agent designs also pass--agent <agent-id>;--grantpins the verifying call instead of sampling history). Do not declare onboarding done with any gate failing — the gates exist because coding agents (you) hallucinate SDK usage and confuse identities. - Hand off human steps explicitly. OAuth consent happens in a browser, by the
human — you cannot click it. Say so plainly: “I’ve started the Connect flow; please
complete the provider consent in the browser — I’ll wait.” The same applies to
operator-owned setup: IDP creation is an org-trust decision the human confirms (they
may run
alter identity-providers createor use the dashboard; IDP updates/deletion stay dashboard-only). Never pretend a human step completed. - Wire the SDK. Call
sdk_integrationwith the developer’s language and the goal; write the returned client-init + request code into their actual files (adapted to their framework). - Verify. A real call from their code must produce audit events
(
alter audit list --limit 1 --output json). That — not “an app was created” — is the definition of done for the first call.
Secret handling (non-negotiable)
Section titled “Secret handling (non-negotiable)”- Minted keys:
alter keys mint,alter agents mint-key, andalter agents createprint the plaintext once, to stdout — if you run them bare, the key lands in the conversation.agents createis the one people miss: it reads like a create-only command, but it returns the new agent’s FIRST api_key, shown once and unrecoverable. Always 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 nevercatit. Add.alter-key.json,.alter-agent-key.json, and.envto.gitignorefirst. - Provider secrets going IN (
--credential-value,--client-secret): use@fileor-(stdin) — never inline argv, and never ask the user to paste a secret into the chat; have them write it to a file you reference. - Never print any plaintext credential into the conversation: scoped keys
(
alter_rk_…runtime,alter_ak_…agent), legacyalter_key_…, or PATs (alter_pat_…).
Scopes (zero-trust)
Section titled “Scopes (zero-trust)”alter keys mint requires --scopes. Mint the minimum the use case needs — for a
first provider call that is tokens:retrieve,proxy:execute,audit:emit. Code that creates OAuth Connect
sessions also needs connect:initiate,grants:write; code that creates managed-secret delegation
sessions needs connect:initiate,secrets:write. Never use a wildcard scope.
The three goals
Section titled “The three goals”| Goal | Whose identity calls? | When | Guide (via fetch_doc) |
|---|---|---|---|
| user-data | The app’s, under user-consented grants | Act for an end user against a provider they authorize (OAuth) — e.g. post to a user’s Slack. | guides/call-apis-on-behalf-of-users |
| backend-secret | The app’s | A server/cron/worker needs its own key, no end user — e.g. a Stripe key. | guides/provision-secrets-for-backend-services |
| agent | The named agent’s OWN identity (a per-agent key, currently alter_key_…) | An autonomous agent/bot/assistant calls providers itself, reaching only credentials bound to it (user delegation or agent-bound secrets). | guides/give-an-agent-scoped-access |
Identity discipline: an app-scoped call must never silently stand in for a named agent. Use the
agent’s bound key when its access set is the security boundary. The SDK’s app-key-plus-agent-ID
construction (app.get_agent / app.getAgent) is attribution-only impersonation: it reuses the
app key and does not restrict explicit-grant calls to the named agent’s grants. The user and the
agent are distinct principals; never conflate them.
Tools available on this server
Section titled “Tools available on this server”list_phases()/list_skills()— discover what this server covers.get_started(phase?, use_case?, goal?)— withphase=setup: the three setup goals + a heuristic hint (you classify); withoutphaseorgoal: a phase picker. With agoal: that flow’s full detect-first plan.next_step(goal, after?)— the next step; errors on unknown step ids (don’t guess).sdk_integration(language, goal)— the SDK wiring to write into the codebase.troubleshoot(exit_code? | error?)— map a CLI failure to a remediation (exit codes 1–8).fetch_doc(slug)— fetch a bundled onboarding doc page.
Guardrails (non-negotiable)
Section titled “Guardrails (non-negotiable)”- Confirm before mutating. Surface what a
create/mintcommand will do before running it; detection output counts as the “what exists already” half of that story. - Happy path only. This flow covers create/configure/mint/verify. Deletes, archival,
and org-wide config are out of scope — direct the user to the dashboard for those. IDP
setup (needed for JWT-based user resolution) chooses which JWT issuer the app trusts:
list it as a human-confirmed step (the human may run
alter identity-providers createor use the dashboard; IDP updates/deletion stay dashboard-only). - Honest handoffs. Browser consent and dashboard steps are the developer’s; say what you are waiting on.