Skip to Content
Platform
CLIAdministration

Project administration

Administer a project’s credentials, callers, bindings, repositories, connectors, and runtime versions.

These command groups operate the cloud resources a project’s agents run against. They need a session from introspection login, and a few of them need a member role an API key cannot hold — each section says so where it applies.

This page is command reference. Use Agent development lifecycle for the ordered local, staging, and production workflow.

Choose the resource that owns the change:

You need toGo to
Confirm or override the active projectProjects and --project
Create an application credential or identity integrationAPI keys and applications
Supply endpoints, variables, or secrets to a runtimeBindings
Register source an agent may work onRepositories
Connect a customer’s provider accountConnectors
Create, inspect, or operate a deployed versionRuntimes

Orient yourself first — where you are logged in, and what the project holds:

introspection whoami introspection runtimes list -o table introspection api-keys list

Project and access

Projects and —project

There is no projects command group: projects are created in the dashboard, and the CLI works inside the project you selected on the login approval page. Every project-scoped command resolves a project before it runs. The order is:

  1. an explicit --project (-p) on the command, with a project slug or id,
  2. otherwise INTROSPECTION_PROJECT from the environment,
  3. otherwise the project selected when you logged in.

Run introspection whoami to see the active login and its project, and introspection login again to select a different one.

bindings and api-keys are the exception. Both always act on the project you logged in to and ignore INTROSPECTION_PROJECT. If the variable is set to a different project they print a note on stderr and continue against the login project — so a binding or key you believed you had scoped elsewhere may have landed in the login project. Neither family accepts --project either: changing project for them means a new login, not a per-command selector. When working across projects, log in to the intended project before running them, and treat that stderr note as a signal to stop rather than something to override.

API keys and applications

api-keys manages project API keys for application/SDK callers. applications manages application identities, service-account secrets, identity-provider federations, and assertion keys. Neither can request the member-only remotes capability used by dev.

Project API keys are environment-bound credentials for SDK callers. create writes the one-time secret to a new mode-0600 file, acknowledges it only after the write succeeds, and never prints the secret:

introspection api-keys create \ --name staging-sdk \ --environment staging \ --member-id <agent-member-id> \ --secret-file ./staging-api-key introspection api-keys create --secret-file ./ci-key --expires-at 2026-12-31T00:00:00Z introspection api-keys list introspection api-keys list --expiring introspection api-keys update --key <key-id> \ --name staging-sdk-2 \ --member-id <agent-member-id> introspection api-keys revoke --key <key-id>

--name defaults to cli and --environment defaults to production, so --secret-file is the only required flag on create. --expires-at takes an RFC 3339 timestamp; omit it for a key with no fixed lifetime. list returns active, non-expired keys; add --expiring to include keys with a future expiry or a grace-period revocation.

If the file write succeeded but acknowledgement failed, retry api-keys acknowledge --key <key-id>. Use revoke --expires-in <seconds> for a grace period.

Applications are organization-managed callers. Choose the type and environment that match the trust model, retain its id, then manage the application and its subordinate auth resources:

introspection applications create --type spa --name web \ --environment staging \ --redirect-uri https://app.example.com/callback \ --allowed-origin https://app.example.com introspection applications create --type native --name desktop introspection applications create --type jwks --name backend introspection applications create --type service-account --name worker \ --agent-member-id <agent-member-id> \ --allowed-scope runtimes introspection applications list introspection applications get <application-id> introspection applications update <application-id> --name web-staging introspection applications delete <application-id>

--environment is set at creation and defaults to production. A service account acts as --agent-member-id; when omitted, the Control Plane uses the organization’s system agent. update can replace that agent, or replace or clear redirect URIs, allowed origins, and allowed scopes.

Manage the auth resources appropriate to the application type:

# Service-account client secrets. The created secret is shown once. introspection applications secrets create --app <application-id> introspection applications secrets list --app <application-id> introspection applications secrets revoke --app <application-id> \ --secret <secret-id> [--expires-in <seconds>] # Direct JWKS identity federation. introspection applications idps create --app <application-id> \ --issuer https://issuer.example.com \ [--audience-client-id <audience>] # Brokered SPA federation, which also needs the OAuth client. INTROSPECTION_IDP_CLIENT_SECRET='...' \ introspection applications idps create --app <application-id> \ --issuer https://issuer.example.com \ --provider supabase \ --client-id <oauth-client-id> \ --scope openid --scope profile --scope email \ --wait introspection applications idps list --app <application-id> introspection applications idps delete --app <application-id> --idp <idp-id> # Assertion signing keys. introspection applications keys create --app <application-id> introspection applications keys list --app <application-id> introspection applications keys delete --app <application-id> --key <key-id>

A jwks application needs only --issuer. A brokered spa application also needs --provider (for example supabase, auth0, okta, or zitadel), --client-id, and --client-secret — pass the secret through INTROSPECTION_IDP_CLIENT_SECRET to keep it out of shell history. --scope is repeatable and defaults to openid profile email, and --wait polls until the brokered federation finishes provisioning.

Protect the one-time service-account secret before persisting it; later secrets list never returns the value. Creating applications and federations can require an owner/admin member login.

Runtime configuration

Bindings

introspection bindings is a CLI umbrella over three flat Control Plane resources, plus one composed read over two of them. It is not a separate /v1/bindings API:

Command groupResource
bindings endpointsllm, api, and mcp upstream targets and their egress header templates.
bindings variablesSandbox environment variables.
bindings credentialsWrite-only secrets referenced from endpoint headers.
bindings mcpNot a fourth resource: a view composing recipe MCP declarations with the kind=mcp endpoints and credentials that back them.

Each resource has its own verbs:

introspection bindings endpoints list|get|create|update|delete introspection bindings variables list|create|update|delete introspection bindings credentials list|get|create|update|delete introspection bindings mcp list|connect|disconnect

Variables have no get: list already returns their values, while endpoint and credential reads deliberately withhold header values and secrets.

Endpoints, variables, and credentials can be project-wide, runtime scoped (--runtime <slug-or-group-id>), or scoped to one exact runtime version (--runtime-id <version-id>). On those three, --environment is optional and takes shared, development, staging, or production. Name a lane to scope the row to it, or shared to write the row that applies to every lane; on a list, omitting the flag leaves the listing unfiltered, while shared narrows it to the rows that carry no lane of their own.

bindings mcp list takes a different --environment: required, and only the three concrete lanes (development, staging, production). There is no shared there, because it resolves one runtime version’s effective connections.

--runtime names the stable runtime and --runtime-id one immutable version of it. Both are resolved server-side, so a version id passed to --runtime is rejected and told which flag takes it.

Endpoint create/update accepts a complete JSON or YAML document as positional @FILE (or @- for stdin); flags override document fields. Bindings shows a full endpoint document and the credential it references.

Keep secret values out of shell arguments: --from-env reads the value from an environment variable, and --from-file (a mode-0600 file) and --from-stdin are the other secret-safe sources. Credential reads expose has_secret and secret_set_at, never the value. Endpoint reads return the unresolved ${NAME} template and referenced credential names, never an expanded secret.

MCP connections

bindings mcp connect creates or upserts the concrete endpoint for a stable recipe MCP id. list composes recipe declarations with the endpoints applicable to one runtime and environment, including required-but-missing and stale connections. Both resolve the recipe from the runtime, so neither takes a recipe argument.

introspection bindings mcp connect \ --mcp-server-id linear \ --name Linear \ --endpoint-url https://mcp.example.com/mcp introspection bindings mcp list \ --runtime <runtime-slug-or-group-id> \ --environment production introspection bindings mcp disconnect --endpoint <endpoint-id>

list requires --environment and either --runtime or --runtime-id. disconnect deletes the endpoint row named by bindings mcp list.

connect checks that --mcp-server-id is well formed, not that the recipe declares it. A mistyped id creates an endpoint that no declaration will ever match. Confirm the connection afterwards with bindings mcp list for the same runtime and environment and check the declared field on the row.

Repositories

introspection repositories registers the source repositories a project’s runtimes may work on:

introspection repositories list introspection repositories add <owner/name> introspection repositories remove <owner/name-or-id>

Registration is what makes a repository addressable. A sandbox asks for its GitHub credential by repository id (POST /v1/repositories/{id}/access-token takes no slug), so a repository that is not registered cannot be named in any request. It is not, by itself, a grant: a recipe still has to list the repository under runtime.github.repositories, and a task still has to ask for it. See Work with repositories.

You often will not need add first. Creating a recipe from a GitHub selector — which runtimes create and the dashboard both do — registers the repository its recipe is pinned in, so this command is for the additional repositories an agent works on.

add takes a full GitHub URL as readily as an owner/name slug, resolves the organization’s GitHub installation itself, and is idempotent — a repeat returns the existing registration. Pass --integration-id only if the organization has more than one active GitHub installation, which is refused rather than guessed. remove accepts either the id or the owner/name a recipe grant would name.

add and remove need a member session from introspection login. repositories:write is a member-role scope, so an API key cannot register a repository — keys top out at repositories:read, which covers list.

Removing a repository does not edit any recipe, but it is refused with 409 repository_in_use while a recipe is still pinned in it — including the one runtimes create registered it for. A recipe that merely grants it resolves to nothing, and its tasks launch without that checkout rather than failing.

Connectors

introspection connectors manages provider integrations and the customer connections beneath them. Every command acts on the project selected by introspection login, and accepts a connector’s id or slug wherever one is named — so connectors authorize slack-support works without pasting ids around. See Connectors for the model.

introspection connectors list introspection connectors create --name <text> --provider <slug> --auth-mode <mode> … introspection connectors get <connector> introspection connectors update <connector> [--webhook-url <url>] [--client-secret <secret>] … introspection connectors delete <connector> introspection connectors authorize <connector> [--runtime <slug-or-id>] [--expires-in <duration>] introspection connectors connections list --connector <connector> introspection connectors connections get <connection-id> --connector <connector> introspection connectors connections revoke <connection-id> --connector <connector>

Registering a provider app takes two passes, because the app’s delivery URL contains the connector id and so cannot be known until the connector exists:

# 1. Create the connector. Idempotent on the slug. introspection connectors create --name "Slack support" \ --provider slack --auth-mode oauth-stored \ --scope chat:write --scope channels:read --api-host slack.com # 2. Register the app with the provider against # {control-plane-host}/v1/webhooks/slack/{connector-id} # 3. Feed back what the provider issued. introspection connectors update slack-support \ --webhook-url <URL> --client-secret <SECRET> --signing-secret <SECRET>

--client-secret and --signing-secret are also accepted on create, for a provider app that already exists. They are write-only: stored encrypted and never returned. Leaving one off update means unchanged — replacing it is the only way to rotate it, and there is no way to clear it. Creates and updates carrying a secret are sent so that a failed request does not echo it back.

connectors authorize is the command an operator actually reaches for: it prints the install link a customer opens.

introspection connectors authorize slack-support --runtime support-agent --expires-in 1h

The URL goes to stdout through the normal output path, so -o json and --query authorize_url work and it can be piped into whatever sends it; the expiry and the single-use warning go to stderr. It deliberately does not open a browser — the link is usually for someone else.

--expires-in takes seconds or a unit, so 1h and 3600 both work. The server allows 60s to 24h and defaults to 10 minutes, which suits following the link yourself; raise it when handing the link to someone who will open it later.

FlagEffect
--runtime <slug-or-id>The agent that answers this connection’s channels. Required by chat providers — a connector reporting requires_runtime: true answers 422 without it.
--subject <kind>Whose token the connection carries. Defaults to the org-owned app.
--user-id <id> / --anonymous-id <id>Assert the end customer this grant is for, using your own identifier. Recorded as the connection’s created_by_member_id, so the connection belongs to your caller rather than to the agent member that made the call. Mutually exclusive.
--return-url <url>Where the browser lands after consent.

Each authorize run mints a fresh single-use state, so the printed URL is a bearer capability for exactly one install. Mint one per customer, hand it to one recipient, and never reuse or cache it.

Asserting --user-id mints a customer member, so it can fail with 409 when the organization has reached its member limit — a plan conflict, not back-pressure.

connections revoke destroys the provider token behind one connection: that subject is disconnected immediately and must re-consent through a fresh install link, and the approvals recorded against the connection are revoked with it. The CLI confirms before doing so. The connector and its other connections are untouched.

Provider token brokering is intentionally SDK-only. The CLI does not print short-lived provider credentials to a terminal — use connections.getToken / get_token from a JavaScript, Python, or Rust client.

delete and connections revoke need a member session from introspection login: connectors:delete is a member-role scope that an API key cannot hold. If a command 404s with “Connectors are not enabled”, the deployment has turned the feature off — it does not mean the connector is missing.

Runtimes

Runtime versions begin with the recipe manifest:

introspection runtimes create --manifest .introspection/<name>.yaml introspection runtimes list [--runtime <slug-or-group-id>] introspection runtimes get <runtime-id> introspection runtimes versions <runtime-id> introspection runtimes pin <runtime-id> [--environment staging] introspection runtimes pin <runtime-id> --sha <sha> introspection runtimes pin <runtime-id> --branch <main|pr/N> introspection runtimes unpin <runtime-id> introspection runtimes update <runtime-id> --yank [--reason <text>] introspection runtimes update <runtime-id> --unyank introspection runtimes delete <runtime-id>

create reads the canonical manifest and Git checkout, creates the immutable recipe pin through the active GitHub integration, and bootstraps the first runtime. The manifest filename is the runtime-group slug. Later versions remain Git-driven.

The first bootstrap must come from a reviewed production commit. Before running create, make sure:

  • the worktree has no uncommitted changes;
  • main is checked out and is the GitHub repository’s default branch;
  • local main matches the pushed origin/main; and
  • the repository is available through the project’s GitHub integration.

The resulting version immediately becomes active in both staging and production. create does not accept a feature branch or pull-request commit: if you started with a pull request, merge it first and update local main. Once the runtime group exists, later pull-request commits can become staging candidates through the normal Git-driven version flow.

pin steers staging; --environment defaults to and accepts only staging. With no flag it freezes staging on the named exact version, --sha freezes it on the version built from that recipe commit, and --branch follows future versions built from main or pr/N. A moving branch ref and a frozen commit are mutually exclusive, and unpin restores staging to main. Production normally follows the repository’s default branch and can be pinned only through the Control Plane API. See Operating runtimes for the immutable-source versus movable-lane distinction.

update --yank withdraws a version from resolving for new work without deleting its history, and --unyank reverses it. delete removes the version from future use and evicts its baked images, so prefer --yank when you need a reversible withdrawal.

JavaScript, Python, and Rust SDKs intentionally expose runtime list/get, resolution, and run only. Use this CLI or the dashboard for lifecycle changes.

Recipe records

Cloud recipe records are immutable Git pins. Authoring them is operator work, so these commands have no SDK equivalent; the SDKs read recipes only.

introspection recipes list [--name <name>] introspection recipes get <recipe-id> introspection recipes create --name <name> \ [--repository-id <id>] [--git-ref <ref>] [--git-sha <commit>] \ [--sub-path <path>] [--slug <slug>] introspection recipes update <recipe-id> [--name <name>] [--description <text>] introspection recipes delete <recipe-id>

Runtime bootstrap normally creates the initial recipe pin for you; reach for recipes create only when operating the record directly. --name is its only required flag, and --slug overrides the stable slug otherwise derived from the name and short commit sha.

update changes the operator-facing name and description only. The Git pin (repository, ref, commit, sub-path) is immutable: pointing at different content means creating a new recipe. delete is a soft delete, and is refused while runtimes still reference the recipe.

Last updated on