crewship credential
Manage credentials (API keys, tokens, secrets) used by AI agents.crewship cred
Subcommands
Provider pools (account groups)
crewship credential pool … manages provider pools — the Account
groups of the Credentials page: a named set of provider accounts of one
provider and one billing mode, in priority order. The UI says account group,
the API and CLI say pool; they are the same object
(API reference).
A pool is a definition only — creating one does not bind it to an agent,
grant its members or enable failover yet — and every subcommand, reads
included, requires OWNER or ADMIN. A scoped CLI token additionally needs
credentials:write for create, update and delete (list and get need
no scope); the scope does not bypass the role requirement.
Every pool carries a revision. pool get prints it; pool update and
pool delete send it back as the quoted If-Match header through
--revision, so an edit made against a definition another administrator has
since changed is refused with 412 rather than overwriting it.
crewship credential pool create
Create a provider account set. Requires workspace OWNER or ADMIN access.
This stores a definition only: it does not grant agents access, assign accounts,
or enable runtime failover. Secret values are never returned.
crewship credential pool list
List up to 100 definitions in the current workspace. Requires OWNER or ADMIN.
JSON output contains items and next_cursor; pass a non-null cursor to fetch
the next page. No secret values are included.
crewship credential pool get
Show a definition and its member IDs and priorities. Requires OWNER or ADMIN
in the pool’s workspace. Use the exact pool ID, not its display name.
crewship credential pool update
OWNER/ADMIN only. Scoped CLI tokens additionally require credentials:write;
that scope does not bypass the role requirement. Read the current revision with pool get, then submit the
complete replacement name and membership. Provider and authentication mode
cannot change. Retained members keep their round-robin history. Changes grant
no account access. If another administrator edits first, the server returns
412: inspect the new definition before retrying rather than overwriting it.
crewship credential pool delete
OWNER/ADMIN only. Scoped CLI tokens additionally require credentials:write;
that scope does not bypass the role requirement. Retires the definition and prevents future selection. It does
not delete or revoke provider accounts or remove membership history. Retired
names stay reserved; choose another name for a new definition. Pools are not
yet bindable to agents in this increment; active execution/binding protection
must be integrated before runtime assignments are enabled.
crewship credential list
List all credentials in the workspace.
SOURCE column shows who owns the row: user (operator-created via UI/CLI), system (auto-managed rows minted by manifest dispatch), or agent. When a row is provisioned for a service, the service slug is suffixed (e.g. system (github-bot)).
Without
--limit, the paged request uses a page size of 100. If more results
remain, the next cursor is printed to stderr. With --offset the command pages
by position instead and ends the human formats with
showing 101–112 of 112.
crewship credential get
Show credential details. The credential value is never displayed.
PROVIDER_LOGIN, or an AI_CLI_TOKEN / API_KEY of a
model provider) seven more rows follow: Mode, Plan, Owner, Expires, Refresh
(not supported (<mode>), or the status with the last / next time and any
error), Delivery (env CLAUDE_CODE_OAUTH_TOKEN, file .codex/auth.json, …)
and Pays for (N agents, M crews).
crewship credential access <id>
Show your server-calculated access to the credential’s metadata and actions.
The command never retrieves the secret. With a CLI token, reveal is denied:
the actual reveal route requires an interactive session, fresh login, a reason
and an audit write. A conditional result is eligibility, not a promise that a
later mutation will pass its live checks.
crewship credential dependents <name-or-id>
List the visible, saved routines that statically declare this credential’s
type (credentials_required, credential_ref.type, or {{ secrets.<type> }}
in supported steps and hooks), with a present-time selection estimate.
Output columns: SLUG, NAME, CURRENT SELECTION — where CURRENT SELECTION is
would_resolve if the runtime’s current ACTIVE selection points at this
credential, another_credential if a different matching row wins, or
unavailable if no row qualifies.
visibility_limited and recorded_use: "not_attributed" fields the table
summarises.
crewship credential refresh
Force a provider login’s access token to be refreshed now.
auth.json imported as --type PROVIDER_LOGIN — can be refreshed; a Claude
setup-token or an API key answers 400. The server refreshes such logins on
its own 24 h before expiry and before a run start with less than 48 h left,
so this is for forcing one: after a login was marked needs_relogin and
re-imported, or to see whether the seat still answers. Prints the login’s
rows (see get) on success; 409 while another refresh of the same login is
in flight. Provider accounts are OWNER/ADMIN-only, so a MANAGER gets
not found here, not forbidden. See
Provider logins.
crewship credential create
Create a new credential. The value is validated against the provider API before saving.
Credential values are validated against the provider API automatically. If validation fails, you are prompted to confirm saving. OAuth tokens (
sk-ant-oat*) and SECRET type credentials skip validation.An OpenAI-compatible endpoint
A self-hosted or internal gateway that speaks the OpenAI wire format is stored as one credential: the endpoint and the key together, under providerOPENAI_COMPAT.
{baseURL, apiKey, headers} object, which
is the same shape an authenticated ENDPOINT_URL credential already used. The key
is delivered to the agent’s sidecar, which writes it into the outbound
request; it is not written into the agent’s environment. crewship provider route show OPENAI_COMPAT prints the route it
will take.
Five consequences to know before you create one:
-
The endpoint must carry auth material of some kind to be isolated. A
bearer token, custom headers, or both — any of these routes the credential
through the sidecar, which writes them into the outbound request so they never
enter the container. An endpoint with no auth at all stays unrouted: there is
nothing to isolate, and routing it would put a failure in front of a path that
works.
crewship crew inspectreports which of the two a run got. -
Calls bill at $0.
OPENAI_COMPAThas no rate row — Crewship cannot know what your endpoint charges — so cost-ledger rows for it are zero.crewship provider route listmarks it(unpriced)for exactly this reason. A $0 spend line for these calls is the truth, not a cheap month. -
An endpoint granted to one agent answers only for that agent. The crew’s
sidecar holds one store, but every credential in it carries the crew members
it was granted to, and a model call is served only a credential the calling
agent holds — resolved from that agent’s own route token, not from anything
the request can claim. Give two members two different
OPENAI_COMPATcredentials and each reaches its own endpoint with its own key. A member the crew holds a credential for but this one was not granted is refused with503 no credential availablerather than handed a teammate’s (#2052). A crew holding no credential at all for a provider is unchanged: the three vendor providers still forward the call for the agent to authenticate itself, which is what they did before credentials existed. Scope follows the grant you made, so nothing here asks you to declare it twice. A credential linked to the crew, or bound at crew or workspace scope, reaches every member and stays available to all of them; one granted to named agents —crewship credential assign— reaches only those. A grant that happens to cover every member of the crew is the same thing as a crew-wide one, and is treated as such. One case is deliberately still crew-wide: a local-model endpoint an agent picks up from the workspace default rather than from a grant of its own. The default is the newestENDPOINT_URLcredential in the workspace that no agent has been granted — a row granted or bound to one agent is skipped, so it will not become the crew’s by accident — but the default itself applies to every agent, and is delivered that way. Grant an endpoint to the agents that should have it if you want it scoped. -
One active credential set per crew sidecar. Agents with the same resolved
credentials safely reuse it: each request carries a self-verifying,
crew-bound route token for attribution. A key rotation or a different set
forces a restart. If an older concurrent run then sends a request, its
credential fingerprint no longer matches and the sidecar returns
403/503instead of serving it from a set the run was never launched with. Two overlapping agents in one crew whose credential sets differ may still need a retry after that restart — the restart is per credential set, and only the last one to start is live. What changed with #2052 is the failure mode of the request that does get through: it is answered from the caller’s own grants or refused, never from a teammate’s. The fingerprint is what carries that guarantee, andcrewshipdalways has one: the internal token it is keyed on is filled in at startup from yourauth.internal_token, else derived fromENCRYPTION_KEY, else a fresh random for the boot. There is no configuration that turns this off, so nothing here asks you to switch it on. It matters only if you run a sidecar Crewship did not launch. A sidecar started without a fingerprint accepts a correctly signed route token from any agent in the container, because there is no configuration identity to compare against — a forged or malformed token is still rejected. The server logs a one-timesidecar credential isolation is fail-openwarning if it ever reaches that state itself; that would mean a build bypassing the normal startup path, so report it rather than trying to reconfigure around it. -
The endpoint and the key are one stored object, so a full-value rotate
replaces both. Pipe the whole object in rather than passing it on the command
line:
To rotate only the key and keep the endpoint, use the field-by-field form. The server merges the fields you send over the stored value and leaves the rest alone, which is what you want for a routine key rotation:
--auth-token-stdinrather than--auth-token, for the same reason--value-stdinexists: an argument is readable by anything that can see the process table while the command runs, and it lands in your shell history. The--auth-tokenflag still works and is fine for a throwaway value, but do not use it for a key you intend to keep. Secrets are never readable, so the merge has to happen server-side — the CLI cannot read the current key back in order to resend it.
crewship credential test-stored self-hosted-llm does dial it
(#2043). Two separate things make that safe, and only the second is a network
control: the path is role-gated, so an arbitrary caller cannot reach it, and the
dial itself goes through the guarded probe — the address is checked after DNS
resolution, so a link-local or cloud-metadata target is refused even when the URL
is perfectly well-formed, and redirects are never followed. A URL that passed
create-time validation is not thereby a safe one to dial; shape validation says
nothing about where a name resolves. It reports reachability — DNS, TLS, a wrong
path prefix, a gateway serving no model list — and deliberately not
authentication: the probe sends no apiKey and no custom headers, because
whoever can edit the credential can repoint baseURL, and a Test button that
posts the stored secret to that host would be a way to exfiltrate it. A key that
is present but wrong shows up on the first agent call.
--base-url on any other provider is a local validation error, exit 2:
crewship credential update
Update a credential. Only changed flags are sent.
PROVIDER_LOGIN, --value / --value-stdin is a re-login: the
server splits the new value into its parts again (access token, refresh
token, plan, expiry), drops the old parts and the refresh state, and keeps the
credential’s id and every assignment — the way to bring back a seat that
reached needs_relogin. The provider and type cannot change in the same
request (400 re-login must keep the existing provider and type); the billing
mode is inferred from the value’s shape as on create.
crewship credential delete
Delete a credential.
crewship credential assign
Assign a credential to an agent. The credential is injected as an environment variable into the agent’s container.
crewship credential unassign
Remove a credential from an agent.
crewship credential field
Manage custom fields in addition to a credential’s main value. The parent has
the alias fields; subcommands are list, set, and remove (rm and
delete are aliases for remove). Secret field values are never returned.
field set flags are --value, --value-stdin, --plain, and --ordinal.
Keys must be lower_snake_case. Without --plain, a field is encrypted and
shown only as (secret) by field list; --plain is for identifiers such as
regions, account IDs, and hosts.
crewship credential bind
Bind a credential to an environment variable slot in one scope.
The credential’s name is the account (github-acme); the slot is what the agent reads (GH_TOKEN). Keeping them apart is what lets one workspace hold ten GitHub accounts — ten crews can each bind GH_TOKEN to a different one.
No scope flag means workspace scope.
--crew and --agent are mutually exclusive: a binding has exactly one scope.
Within a scope a slot points at exactly one credential — binding a slot that is already taken returns 409 Conflict instead of replacing the existing row. Binding the same slot in a different scope is not a conflict.
crewship credential bindings
The command also accepts the alias crewship credential binding-list.
List bindings in the workspace.
crewship credential unbind
Remove a binding, by id or by naming the slot and scope.
crewship credential resolve
Show the slot map one agent will actually boot with, and which rule produced each row. Values are never shown.
agent_grant (an explicit credential assign), agent_binding, crew_binding, workspace_binding, crew_link (no binding — delivered under the credential’s own name).
crewship credential login
Sign in to a model provider with a device code and store the login as a
PROVIDER_LOGIN credential owned by you. The command prints a one-time code and
a URL; open the URL in any browser, sign in to the account that pays for the
model, enter the code, and the command finishes when the server has stored
the login. The server — not the CLI — polls the provider, so the sign-in
survives a closed terminal (--no-wait) and a server restart.
Only OPENAI (ChatGPT Plus / Pro / Business, for the Codex adapter) offers
this today; the stored login is delivered to Codex agents as a rendered
auth.json whose refresh token never leaves the server — see the
Codex CLI guide.
Exit codes:
0 when the credential was created (its details are printed the
way credential get prints them); 2 when the provider refused the sign-in
or the credential could not be stored; 3 when the 15-minute code expired
before it was entered.
crewship credential login-status
Show the state of a device-code sign-in: pending, complete (with the
credential id), expired or denied (with the reason).
crewship credential test
Test a credential value against the provider API without saving it.
crewship credential test-stored
Re-test an already-saved credential against the provider API without re-supplying the value. Useful for verifying that a rotated key still works, or that a long-lived token has not been revoked upstream.
valid: true; otherwise the error message from the provider is printed.
Crewship maintains upstream probes for API-key credentials from Anthropic, OpenAI, Google, OpenRouter, Cursor, Factory, GitHub, GitLab and Vercel, plus any ENDPOINT_URL credential. For API keys, a pass means the key itself works.
For an OpenAI PROVIDER_LOGIN in subscription mode, Crewship stores the OAuth access token extracted from a Codex auth.json and reconstructs the login file for the CLI. That token is not an OpenAI API key. This command reports not checked rather than sending it to the API-key endpoint; the same applies to older OpenAI AI_CLI_TOKEN auth blobs. A PROVIDER_LOGIN in api_key mode retains the provider’s API-key probe; an Anthropic subscription setup-token retains its separate OAuth probe. agent credential-readiness checks whether an unprobed login would reach a particular agent, and a controlled CLI run is still needed to prove it works.
OPENAI_COMPAT is probed here too (#2043), and it is the one that answers a different question. Because its endpoint is operator-supplied, this command asks whether the host is reachable and serving a model list — it sends no apiKey and no custom headers, so a pass means the endpoint is live and correctly addressed, not that the key is accepted. A wrong key surfaces on the first agent call.
For every other provider there is nothing to call — the agent talks to that API directly and Crewship holds only the secret. Those credentials report not checked rather than valid, and exit 0:
crewship credential rotate
Requires OWNER/ADMIN role, or the credential.rotate capability (grantable to a MANAGER/MEMBER so an oncall user can rotate a leaked token without full vault access). The new value is capped at 64 KiB.
Issue a new value for the credential. The old value is preserved on the rotation row for the grace window (max 7d) so in-flight agents that cached the old key can still fall back during their run, then the old value is scrubbed.
The cobra default for --grace-seconds is 0, but the flag is only sent when you explicitly set it. Omit the flag and the server applies its standard 24h grace. Pass --grace-seconds 0 to force an immediate cutover (no overlap). Pass any positive value (up to 604800 / 7d) to set a custom window.
crewship credential rotations
List rotation history for a credential.
crewship credential rotation-cancel
End an ACTIVE rotation’s grace window immediately and scrub the old value. EXPIRED / CANCELLED rotations are no-ops on the server side (idempotent 200).
crewship credential audit
Show the full credential timeline — the same view the detail Sheet’s Audit tab uses. Useful for grep-ing for ROTATE / TEST / REVOKE events without scraping the UI.
crewship credential default-env-var
Print the conventional env var name for a provider (GH_TOKEN, GITLAB_TOKEN, VERCEL_TOKEN, …). Useful when scripting credential assign and you don’t want to memorise every provider’s convention.
This is a suggestion, not a rule. Crewship accepts any provider string; one it has no convention for simply prints nothing and exits non-zero, and you pass
--env-var-name yourself. Every name below is the variable the vendor’s own CLI or SDK documents reading.DOCKER, TERRAFORM, ANSIBLE, CUSTOM_CLI and NONE are recognised providers with no entry: the docker CLI authenticates through ~/.docker/config.json rather than an env var, and HCP Terraform’s token variable is host-suffixed (TF_TOKEN_<hostname>), so any single value here would be invented.
crewship credential reveal
Disclose a credential’s plaintext value.
- an OWNER has enabled reveal for the workspace (
crewship credential reveal-policy --enable) - your membership carries the
credentials:revealcapability — theadminpreset includes it and an OWNER or ADMIN with no explicit capability set holds it by default, but an explicit set is authoritative: revoked is revoked, and a MANAGER holds it only when granted - you are MANAGER or above; a MANAGER is additionally limited to credentials in their own crews
- the credential is not
SEALED(seesensitivity) - your
--reasonis at least 20 characters and not a generic placeholder - the session is fresh — created within the last 5 minutes. The interactive sign-in this command performs satisfies it; refreshing a page or a token does not
- your account is not still on the seed default password — change it in account settings first, then sign in again
- the reveal can be written to the tamper-evident audit chain — if that write fails the command gets a
500and no value
The endpoint has its own per-IP rate limit (
http.cred_reveal_per_min, default 3/min), and unlike the general API bucket, authenticated CLI callers are not exempt from it.
crewship credential reveal-policy
Show or set the workspace credential-reveal switch. Reveal is off for every workspace — including newly created ones — until an OWNER turns it on.
403, because whether a tenant has reveal enabled is useful to an attacker choosing a target. Changing it requires OWNER.
Both directions are written to the tamper-evident audit chain before taking effect: if the audit write fails, the switch does not move.
Enabling the switch grants nobody reveal on its own. Each person still needs
the
credentials:reveal capability on their membership. The recommended
corporate default is two people holding it, not the whole admin team.crewship credential sensitivity
Set a credential’s classification. It is the first thing the reveal gate consults and the only layer no role can override.
Raising a classification is a MANAGER+ action and takes effect immediately — it only ever removes reach, so it needs no ceremony, and a control that is annoying to tighten stops being used. Lowering requires OWNER or ADMIN and is written to the audit chain first: it hands out a key that did not exist a moment earlier, and it is the cheap move for an attacker holding an admin session.
SEALED has no escape hatch on purpose. To get a usable value out of a sealed credential, rotate it — crewship credential rotate mints a new one and shows it once.
Existing credentials are STANDARD, which is safe only because the workspace reveal switch defaults to off.
RESTRICTED behaves like STANDARD today. The four-eyes second-approver flow
that will distinguish them is deferred, but classifying now still pays off —
that gate will key off this field.