Skills
Skill 6 of 22
Operate the Clerk CLI (clerk binary) for authentication, user/org/session management, impersonation, local webhook testing, deploy verification, instance config, security audits…
9 minutes · 2,069 words · 13 sections
Install
npx skills add clerk/skills --skill clerk-clinpx skills add clerk/skills/plugin marketplace add clerk/skillsThe first command installs just this skill, by the name in its SKILL.md; the second installs the whole repository.
The clerk binary is a pre-authenticated gateway to Clerk’s Backend API and Platform API, plus project-level tooling (auth, linking, env pulls, instance config). When the user asks anything that touches a Clerk resource, reach for clerk first instead of hand-rolling curl.
For setup or init requests, use the clerk-setup skill as the source of truth. Its package-runner, accountless, migration, and init-first guidance takes precedence over the general operational prerequisites below.
This skill targets clerk
latest. Ifclerk --versiondisagrees with the latest available CLI, refresh it withclerk update, or invoke the latest through a package runner such asbunx clerk@latest. The binary is always the source of truth, so runclerk <command> --helpto verify anything this skill claims.
Most AI coding agents default to running shell commands in a sandbox where the user’s home directory, OS keychain, browser launch, localhost callback binding, or network access may be blocked. The Clerk CLI depends on all of those host capabilities:
clerk auth login stores the OAuth token in the
system keychain. A sandbox without keychain access reports “not logged in”
even when the host is authenticated..env* files: publishable and secret keys materialized by
clerk env pull.clerk auth login needs both.In agent mode, the CLI now does a best-effort warn-once check at the host-sensitive library boundaries. When it detects that host-only Clerk state or system capabilities are unavailable, it emits:
Host-only Clerk state or system capabilities may be unavailable in agent mode. This may be a sandboxed run.
Re-run this command on the host shell before trusting auth, link, env, or API failures.Treat that warning as authoritative. The command may continue, but any auth, link, env, config, API, browser, or OAuth callback failure from that invocation is untrusted until you rerun the same command on the host.
Prefer these commands on the user’s host shell, not in a sandbox:
clerk doctor, clerk whoami, clerk auth login, clerk link, clerk env pull,
clerk apps ..., clerk config ..., clerk api ....
If a command was accidentally run in a sandbox and it reports Not logged in,
auth_required, not linked, missing env, keychain/file permission errors,
or network failures, do not treat the result as authoritative. Rerun it on
the host before acting on it or reporting it to the user.
Before running any clerk command, figure out which binary to invoke and bind that choice for the rest of the session:
# 1. Prefer a globally installed binary when it matches the skill's target version.
command -v clerk >/dev/null 2>&1 && clerk --versionIf that prints latest or any version you trust, use bare clerk for the rest of the session.
Otherwise fall back to a package runner, in this order (matches the CLI’s own preferredRunner logic, which prefers the runner that matches the project’s lockfile):
| Project package manager | Invocation |
|---|---|
bun (bun.lock*) | bunx clerk@latest |
npm (package-lock.json) | npx -y clerk@latest |
pnpm (pnpm-lock.yaml) | pnpm dlx clerk@latest |
yarn >= 2 (yarn.lock) | yarn dlx clerk@latest |
Yarn Classic (v1) has no dlx; treat those projects as “no preferred runner” and fall back to the first runner from the list above that’s on PATH.
The published npm package is clerk, not @clerk/cli. Never teach npm install -g clerk as the primary path. If the global CLI is stale or behaves differently from this skill, either upgrade the global install or fall back to the latest runner form above.
Except when following clerk-setup, verify the CLI is authenticated, linked, and healthy before running other Clerk commands in a session:
clerk --version # confirm the binary is on PATH
clerk doctor --json # structured health check; exit 1 if anything failedAlways run clerk doctor --json first. It catches the common setup failures (not logged in, project not linked, missing keys, stale CLI version) up front, so later commands don’t fail with confusing errors. In agent mode it also includes a Host execution check that warns when Clerk’s host-side config / credential directories are not writable, which is the canonical signal that the current invocation is likely sandboxed.
Each result has name, status (pass/warn/fail), message, optional detail, optional remedy (how to fix it), and optional fix (label for auto-fixable issues). Parse that and act on it, or surface it to the user. If Host execution warns, rerun the command on the host before trusting any auth/link/env/API failures from the same sandboxed run. Rerun clerk doctor --json whenever a later command starts misbehaving.
If clerk --version reports a newer CLI than this skill covers, trust clerk <command> --help first and refresh this skill bundle from its source. The reverse also applies: --accountless and the accountless JSON keys ship in CLI 3.3+ — on an older CLI, use the --keyless alias or upgrade.
clerk init does not require clerk auth login: on a framework with accountless support, an unauthenticated bootstrap with no --app, or an unauthenticated agent run with no --app or existing project link, mints an unclaimed accountless app with temporary development keys — no account, no browser, no flag. (A signed-out human re-running it in an existing project gets the login flow instead — --accountless forces the temporary-keys path.) Most instance commands then work on that key alone.
Two things to know before you use it: the accountless path follows whatever sk_ key is local — sk_live_ included, claimed or not — so pass --app <id> when you mean a real app; and clerk open returns a credential-equivalent claim URL, never safe to paste into a log or PR.
Which commands need an account, and the full rules: auth.md (opens in a new tab).
| Layer | What it does | Commands |
|---|---|---|
| Session / project | Auth, link a repo to a Clerk app, pull env keys | auth login, link, unlink, whoami, env pull, doctor |
| Instance config | Manage the configuration (social providers, session lifetimes, etc.) for a specific instance | config pull, config schema, config patch, config put |
| Backend API (default) | Runtime data: users, orgs, sessions, invitations, JWT templates, webhooks | clerk api <path> |
Platform API (--platform) | Account-level: applications, instances, billing | clerk api --platform <path> |
Frontend API (--fapi) | The instance’s public client-facing API (what clerk-js calls) | clerk api --fapi <path> |
A project is “linked” to an application via clerk link. Once linked, most commands auto-resolve the target app and dev instance from the repo’s git remote. To target something else, pass --app <id> and/or --instance dev|prod|<instance_id>. See references/auth.md (opens in a new tab) for the full resolution order.
The CLI ships with the Clerk OpenAPI catalog. Always discover endpoints dynamically instead of guessing paths:
clerk api ls # list every Backend API endpoint
clerk api ls users # filter by keyword (matches path, summary, tag, operationId)
clerk api ls --platform apps # list Platform API endpointsUse this before clerk api <path>. If you don’t see the endpoint you expected, it probably isn’t exposed.
clerk api command (the workhorse)clerk api makes authenticated HTTP calls. It auto-resolves keys, auto-detects method from body presence, supports stdin, and can preview mutations with --dry-run.
# GET requests
clerk api /users # list users
clerk api /users/user_abc123 # fetch one
clerk api /users?limit=5&order_by=-created_at # query params work inline
# Mutating requests
clerk api /users -d '{"email_address":["a@b.co"]}' # POST (auto-detected from body)
clerk api /users/user_abc123 -X PATCH -d '{"first_name":"A"}'
clerk api /users/user_abc123 -X DELETE
# Body from file or stdin
clerk api /users --file payload.json
cat payload.json | clerk api /users
# Always preview mutations first
clerk api /users/user_abc123 -X DELETE --dry-run
clerk api /users/user_abc123 -X DELETE --yes # skip confirmation once you've verified
# Target a specific app/instance
clerk api /users --app app_abc123 --instance prod
# Include response headers when debugging
clerk api /users --include
# Platform API (account-level, not tenant data)
clerk api /v1/platform/applications --platform
# Frontend API (the instance's public client-facing API — what clerk-js calls.
# Unauthenticated; --fapi and --platform cannot be combined, --secret-key is ignored)
clerk api --fapi /environmentIn human mode, clerk api with no arguments opens an interactive request builder; in agent mode it prints usage guidance and exits 0 — always pass an endpoint (or ls) explicitly from scripts.
For instance config, prefer the dedicated clerk config ... commands over raw Platform API /config paths. They handle dry-run, diffing, and confirmation more cleanly than the raw endpoint form.
Always --dry-run a mutation before running it for real. Then re-run without --dry-run (add --yes if you’re sure). In agent mode, interactive confirmation is bypassed, so --dry-run is the only safety net for destructive calls.
JSON bodies must be valid JSON. The CLI validates and rejects malformed payloads.
Endpoint paths may be given with or without /v1/ prefix - both work for Backend API calls. The CLI normalizes.
See references/recipes.md (opens in a new tab) for concrete patterns: listing/filtering users, creating orgs, impersonation sessions, etc.
users list, apps list, config pull, and most clerk api GETs return payloads that can be many kilobytes or megabytes. Production tenants commonly have thousands of users; an instance config can be hundreds of fields deep. Reading those responses into the conversation costs context window for no benefit. Save the response to a file first, then query just what you need with jq:
# 1. Persist the response. Use --limit 250 to maximize page size for users list.
clerk users list --json --limit 250 > /tmp/users.json
clerk apps list --json > /tmp/apps.json
clerk api /users/user_abc123 > /tmp/user.json
# 2. Inspect only what you need.
jq '.data | length' /tmp/users.json # current page size
jq '.hasMore' /tmp/users.json # are more pages available?
jq '.data[0] | keys' /tmp/users.json # discover the user shape once
jq '.data[] | {id, email_addresses}' /tmp/users.json # project to a few fields
jq '[.data[] | select(.banned)] | length' /tmp/users.json # aggregate without reading rowsIf jq is not available, fall back to Python or Node - both can stream the file without printing it whole:
python3 -c 'import json; d=json.load(open("/tmp/users.json")); print(len(d["data"]), d["hasMore"])'
node -e 'const d=require("/tmp/users.json"); console.log(d.data.length, d.hasMore)'cat / head the file only when you genuinely need to see the raw structure for one-off debugging. When walking pages, write each page to its own file (e.g. page-${offset}.json) so individual pages stay independently inspectable.
Read the command catalog (opens in a new tab) when choosing a subcommand or flag. Confirm unfamiliar syntax with clerk <command> --help.
The CLI auto-detects agent mode when stdout is not a TTY, or when --mode agent / CLERK_MODE=agent is set. In agent mode:
link without --app, unlink without --yes, users without a subcommand) either auto-resolve or exit with a usage error. clerk api with no args prints usage guidance and exits 0; pass an endpoint (or ls) explicitly. Always pass explicit flags in scripted calls: --yes, and --app for an app the person named that’s already in the account.--mode agent or CLERK_MODE=agent when you want the CLI’s non-interactive behavior and sandbox warning path to apply deterministically.link supports deterministic agent flows. In agent mode, clerk link --app <id> links directly. Without --app, newer CLIs signed in to an account first claim the app clerk init created in this folder; otherwise the CLI tries silent key-based autolink, and if it cannot determine the app unambiguously, it exits with a usage error.not_linked, follow When the folder isn’t linked (opens in a new tab). It covers sandbox checks, unclaimed apps, competing claim files, and older CLIs. Do not assume clerk link is the next step.init, follow clerk-setup. It owns framework-support, accountless, app-linking, migration, and login-order guidance so setup instructions have one source of truth.--fresh is destructive. It replaces the temporary app and overwrites the env keys and .clerk/keyless.json breadcrumb with no prompt, orphaning the previous app and its users. Never pass it just to re-run init.--yes in agent mode. unlink, security fix (unless --dry-run), and disable orgs while organization billing is on exit with a usage error without it. update without --yes prints a hint and exits 0 without updating.config patch / put, api mutations, users create, and enable / disable execute with no prompt and no error. Passing --yes is harmless but changes nothing. Do not treat it as a safety gate - --dry-run is the real one.security fix, tell the user what changes. Several fixes add a CAPTCHA, verification, second-factor, or passkey step, or force a password reset; findings with a customFlows note break custom sign-in flows until they are updated. mfa and passwordless-auth are product decisions: ask which --factors / --strategy rather than picking. See Audit and harden security (opens in a new tab).impersonate requires the [user] positional in agent mode. If a search term matches multiple users, it exits 2 listing candidate user IDs — retry with a specific user_... ID. Output is a JSON object ({url, id, userId, actor, ...}); surface url to the user and capture id — it is the only chance to record the revoke handle.webhooks listen is long-running. Run it in the background. In agent mode (or with --json) it emits NDJSON: one ready line ({type:"ready", relay_url, forward_to}), then one event line per delivery — each event line can be fed back to clerk webhooks verify --delivery.doctor --fix is ignored. Parse doctor --json output’s remedy field and act on it yourself.apps list and apps create default to JSON when piped.users defaults to JSON when piped, like apps. clerk users list and clerk users create emit JSON in agent mode. Bare clerk users (no subcommand) is a usage error in agent mode - pass list, create, or open explicitly. clerk users open requires the user-id positional in agent mode and prints a JSON descriptor instead of launching a browser.deploy --domain needs a domain the user owns, and deploy status is the gate. Ask the user for the domain before running clerk deploy --domain <domain>. When the wizard is needed (Apple’s private key, or the user prefers it), have the user run clerk deploy in a separate terminal from the project directory, never through your session or Claude Code’s ! shell escape. Verify with clerk deploy status --mode agent. deploy has no --app flag: to deploy a specific app, link the folder first with clerk link --app <id>. See Deploy to production (opens in a new tab).--input-json <json|@file|-> expands JSON into flags on any command (e.g. clerk init --input-json '{"framework":"next","yes":true}'). Stdin needs the explicit - marker (echo '{"yes":true}' | clerk init --input-json -); bare piped stdin is not auto-detected, so shell loops and self-reading commands (cat body.json | clerk api …) are untouched. Place --input-json after the leaf subcommand. Full rules in references/agent-mode.md (opens in a new tab).Full matrix and sandbox details in references/agent-mode.md (opens in a new tab).
--json on apps list and doctor. For clerk api, the response body is the raw API JSON, so pipe into jq freely.0 success, 1 runtime error, 2 usage/validation error. doctor returns 1 if any check failed.--verbose for stack traces when debugging.clerk api ls <keyword> before clerk api <path>.--dry-run on every config patch, config put, security fix, api -X POST/PATCH/PUT/DELETE.--instance prod rather than relying on defaults, and confirm with the user before any production mutation.env pull writes to .env.local (which should be gitignored). Don’t paste secret keys into code or chat.doctor --json to diagnose before assuming the CLI is broken.clerk impersonate bypasses the user’s MFA and may count against the impersonation quota.--app/--instance targeting, Backend vs Platform API.Operate the Clerk CLI (`clerk` binary) for authentication, user/org/session management, impersonation, local webhook testing, deploy verification, instance config, security audits, env keys, feature toggles, and any Clerk Backend, Platform, or Frontend API call. Use when the user mentions Clerk management tasks, "list clerk users", "impersonate a user", "test webhooks locally", "enable orgs", "enable billing", "clerk security", "harden my Clerk instance", "clerk env pull", "clerk doctor", "clerk deploy", "clerk api", or any ad-hoc Clerk API request. Prefer the CLI over raw HTTP: it handles auth, key resolution, app/instance targeting, and formatting automatically.
The verbatim description from this skill’s front matter — the string an agent matches on to decide whether to load it.
skills/clerk-cli/SKILL.mdmain, last pushed 6 November 2026.SKILL.md, not by matching a directory convention. 2 distinct layouts observed: .agents/skills/*/SKILL.md, skills/*/SKILL.md.h1 and no skipped levels:.claude-plugin/marketplace.json by Clerk, declaring 1 plugin. It is read for editorial metadata only — never as the skill index, which is always the repository tree./clerk/skills.md, and each skill at its own .md URL.4 files · 85 KB
Everything this skill ships beside its prose. All of it is set here, as subchapters of skill 6.
Documentation the agent loads on demand, rather than up front.