Compass Docs
Developers

API, CLI & SDK

Call Compass over HTTP, from your terminal, or from Python — one surface, three clients, every example in all three.

Everything you can do in the app you can do from outside it. There's one HTTP API underneath, and three ways to call it:

  • API — the raw HTTP surface. Use it from any language or tool that can make a request.
  • CLI — the compass command. A full management surface for your terminal — not just running and inspecting work, but authoring it: create agents, build and deploy workflows, manage connections, every command scriptable for automation and CI.
  • Python — the async Compass SDK, from compass_core import Compass. The same wheel as the CLI, imported as a library, exposing every resource you work with in the app.

Pick your client once

Every example on this page comes in all three flavors. Switch any code block to API, CLI, or Python and the whole page follows — the choice is remembered next time you visit.

Install

The CLI and the SDK ship in a single Python wheel you download from the app, at Settings → Developer → SDK & CLI (the Download wheel button). The API needs no install at all.

The SDK & CLI settings panel: a Download wheel button and three steps — install, authenticate, run.
Settings → Developer → SDK & CLI — download the wheel and copy the install, login, and run commands.

Nothing to install. Calls go to your Compass URL — the same address you use to sign in — under the /v1 prefix:

https://your-compass-url/v1

Install the wheel as a tool:

uv tool install "./compass_core-<version>-py3-none-any.whl[cli]"

This puts a compass command on your PATH. It needs Python 3.13+; the [cli] extra pulls in the terminal dependencies. (pipx install "./compass_core-<version>-py3-none-any.whl[cli]" works too.)

Add the wheel to your project (Python 3.13+):

pip install ./compass_core-<version>-py3-none-any.whl
# or: uv add ./compass_core-<version>-py3-none-any.whl
from compass_core import Compass

Authenticate

Every client authenticates with an API key — create one in Settings → Developer → API keys and copy it (it's shown only once).

A key is not a bearer token. It's a self-contained credential that you exchange for a short-lived access token, and that access token is what actually rides on each request. The CLI and the SDK do the exchange for you and refresh it as it expires; over raw HTTP you do it yourself.

Authenticating by hand is three steps: read the values out of your key, exchange them for an access token, then call the API with that token.

1 — Read the values out of your key. The key is base64url-encoded JSON. Any base64url decoder will do; this one needs nothing but Python:

python3 -c "import base64, os; k = os.environ['COMPASS_API_KEY']; print(base64.urlsafe_b64decode(k + '=' * (-len(k) % 4)).decode())"

It prints the three values the key carries:

{
  "token_url": "https://auth.your-compass-url/application/o/token/",
  "client_id": "…",
  "client_secret": "…"
}

Take token_url from the key rather than guessing it — it's your sign-in provider's token endpoint, which is a different hostname from the Compass API.

2 — Exchange the key for an access token using the OAuth2 client-credentials grant, posting those three values as form fields:

COMPASS_ACCESS_TOKEN=$(curl -s -X POST "<token_url>" \
  -d grant_type=client_credentials \
  -d client_id="<client_id>" \
  -d client_secret="<client_secret>" \
  -d scope=openid | jq -r .access_token)

The reply is a standard OAuth2 token response: access_token is the token to send, and expires_in says how many seconds it stays valid. It's short-lived, so a long-running caller repeats this exchange when it lapses — which is exactly what the SDK and CLI do on your behalf. Keep the key; it's what you re-exchange with.

3 — Call the API with that access token as the bearer:

curl https://your-compass-url/v1/projects/ \
  -H "Authorization: Bearer $COMPASS_ACCESS_TOKEN"

Every API example below assumes $COMPASS_ACCESS_TOKEN holds a token that's still valid.

Or let a client do it

The CLI and the SDK take the key directly and handle the exchange and the refresh internally. If you'd rather not manage token lifetimes yourself, authenticate with one of them.

Log in once:

compass auth login --url https://your-compass-url

You'll be prompted for the key, which is saved to a local profile. The CLI does the token exchange on every call, so the key is the only thing you ever handle. Check it worked with compass auth whoami, and sign out with compass auth logout.

The client is async and works as an async context manager. Pass the key as credential along with your Compass URL:

import asyncio
from compass_core import Compass

async def main():
    async with Compass(
        credential="<your-api-key>",
        base_url="https://your-compass-url",
    ) as client:
        ...

asyncio.run(main())

The client exchanges the key for an access token on first use, caches it, and re-exchanges before it expires. It targets the v1 API.

Profiles and environment

CLI credentials are stored in a config file under ~/.config/compass/, and you can keep several profiles (for example, different organizations or environments):

compass config list          # show saved profiles
compass config use <name>    # switch the default profile
compass --profile <name> ... # use a profile for one command

Any command also reads these environment variables, which override the saved profile:

VariablePurpose
COMPASS_API_KEYThe API key to authenticate with.
COMPASS_BASE_URLYour Compass URL.
COMPASS_PROFILEWhich profile to use.
COMPASS_PROJECT_IDThe project to act in (see below).

Choose a project

Your API key is organization-scoped, so you tell Compass which project a call should act in. Skip it and calls act on your organization's default project.

Send the project on each request as a header:

X-Compass-Project-Id: <project-id>

GET /v1/projects/ lists the projects your key can reach and your role in each.

List the projects your key can reach, then make one active:

compass projects list              # ID, name, and your role in each
compass projects use <project-id>  # set the active project for this profile

The active project is saved on the profile and sent with every request. Override it for a single command with --project <id>, or set COMPASS_PROJECT_ID. compass auth whoami shows the active project — or default.

Pass project_id when you construct the client — it's sent as the X-Compass-Project-Id header on every request:

async with Compass(
    credential="<your-api-key>",
    base_url="https://your-compass-url",
    project_id="<project-id>",
) as client:
    ...

To see the projects a key can reach and your role in each, call await client.projects.list().

Run an execution

Execution is asynchronous: you dispatch work and get back an execution you then poll or stream until it finishes. Provide either a deployment_id (the live version) or a workflow_id (a specific workflow or agent), plus the input. The response has an id and a status — the id is typed by what you dispatched: workflow_execution_<hex> or agent_execution_<hex>.

curl -X POST https://your-compass-url/v1/executions/ \
  -H "Authorization: Bearer $COMPASS_ACCESS_TOKEN" \
  -H "X-Compass-Project-Id: <project-id>" \
  -H "Content-Type: application/json" \
  -d '{
    "deployment_id": "<deployment-id>",
    "input_data": { "topic": "Q3 report" }
  }'
# Execute a deployment
compass execute --deployment <deployment-id> --input topic="Q3 report"

# Execute a workflow or agent draft, reading input from a file
compass execute --workflow <workflow-id> --input @inputs.json

# Chat with an agent (--message is shorthand for --input message=…)
compass agents execute <agent-id> --message "Summarize today's signups"
execution = await client.executions.create(
    deployment_id="<deployment-id>",
    input={"topic": "Q3 report"},
)
print(execution.id, execution.status)

Pass workflow_id="<workflow-id>" instead to execute a workflow or agent draft.

Get the result

Once dispatched, read the execution by id to check its status and output. Poll until it reaches a terminal state — or stream it instead.

curl https://your-compass-url/v1/executions/<execution-id> \
  -H "Authorization: Bearer $COMPASS_ACCESS_TOKEN"
compass executions get <execution-id>
execution = await client.executions.get("<execution-id>")

Stream it live

For real-time output, subscribe to the execution's event stream — a Server-Sent Events connection that emits each event (tool calls, output, completion) as it happens — the same trace you'd see in Observability.

curl -N https://your-compass-url/v1/streams/<execution-id> \
  -H "Authorization: Bearer $COMPASS_ACCESS_TOKEN"

Add --follow (-f) when you execute to stream events as they happen:

compass execute --deployment <deployment-id> --input topic="Q3 report" --follow
async for event in client.streams.events("<execution-id>"):
    print(event)

Inspect executions

Beyond the execution itself, you can list your project's executions and read any execution's full trace — per-node details and the hierarchical tree, including child executions.

# List executions in the project (optionally ?workflow_id=…)
curl "https://your-compass-url/v1/executions/" \
  -H "Authorization: Bearer $COMPASS_ACCESS_TOKEN" \
  -H "X-Compass-Project-Id: <project-id>"

# Per-node details, and the hierarchical trace
curl https://your-compass-url/v1/executions/<execution-id>/node-executions \
  -H "Authorization: Bearer $COMPASS_ACCESS_TOKEN"
curl https://your-compass-url/v1/executions/<execution-id>/tree \
  -H "Authorization: Bearer $COMPASS_ACCESS_TOKEN"

GET /v1/executions/summary returns aggregate usage over a time window.

compass executions list
compass executions node-executions <execution-id>
compass executions tree <execution-id>
page = await client.executions.list(workflow_id="<workflow-id>")
steps = await client.executions.node_executions("<execution-id>")   # per-node details
tree = await client.executions.tree("<execution-id>")               # hierarchical trace

Create an agent

Agents are workflows of type agent, so every client creates them through the workflows surface — and the CLI adds a first-class agents group on top, including an interactive wizard.

POST /v1/workflows/ with the agent's definition. The easiest way to get a definition to start from is to build one in the app and read it back with GET /v1/workflows/{id}:

curl -X POST https://your-compass-url/v1/workflows/ \
  -H "Authorization: Bearer $COMPASS_ACCESS_TOKEN" \
  -H "X-Compass-Project-Id: <project-id>" \
  -H "Content-Type: application/json" \
  -d @agent.json

Run compass agents create with no arguments for an interactive wizard that walks you through the name, instructions, provider, and tools:

compass agents create

Or pass everything as flags — ideal for scripts and repeatable setups:

compass agents create \
  --name "Release Notes Writer" \
  --instructions "You write concise release notes from a list of changes." \
  --provider <provider-connection-id> \
  --tool integration:<connection-id> \
  --tool workflow:<workflow-id> \
  --no-conversation-history

The --tool flag is repeatable and accepts agent:<id>, workflow:<id>, or integration:<connection-id> — the same three tool kinds as the builder. The model comes from the provider connection. You can also create from a saved YAML definition with --file agent.yaml.

Agents are managed through client.workflows — validate a definition into a Workflow and create it:

from compass_core.core.workflows import Workflow

agent = Workflow.model_validate(definition)  # e.g. loaded from a JSON file
created = await client.workflows.create(agent)

Build, validate, deploy

The whole workflow lifecycle is available from code: create a workflow from a definition, validate it, and deploy it. Because agents are workflows under the hood, validate and deploy work on an agent's id too.

curl -X POST https://your-compass-url/v1/workflows/ \
  -H "Authorization: Bearer $COMPASS_ACCESS_TOKEN" \
  -H "X-Compass-Project-Id: <project-id>" \
  -H "Content-Type: application/json" \
  -d @workflow.json

curl -X POST https://your-compass-url/v1/workflows/<workflow-id>/validate \
  -H "Authorization: Bearer $COMPASS_ACCESS_TOKEN"

curl -X POST https://your-compass-url/v1/workflows/<workflow-id>/deploy \
  -H "Authorization: Bearer $COMPASS_ACCESS_TOKEN"
compass workflows create --file workflow.json
compass workflows validate <workflow-id>
compass workflows deploy <workflow-id>
workflow = await client.workflows.create(Workflow.model_validate(definition))
result = await client.workflows.validate(workflow.id)
await client.workflows.deploy(workflow.id)

Manage connections

Connections, providers, and gateways can be managed from any client — creating or changing them needs a key with a Developer role, because they hold credentials.

curl https://your-compass-url/v1/providers/ \
  -H "Authorization: Bearer $COMPASS_ACCESS_TOKEN" \
  -H "X-Compass-Project-Id: <project-id>"

The same shape applies to /v1/connections/ and /v1/gateways/.

compass providers list
compass connections create

The connections, providers, and gateways groups share the same commands.

providers = await client.providers.list()
connections = await client.connections.list()
gateways = await client.gateways.list()

Scriptable end to end

Everything above composes: create an agent, deploy it, kick off an execution, and parse the result — from CI, a script, or your own backend, without the UI.

Reference

HTTP resources

All routes live under https://your-compass-url/v1 and take an access token as the bearer, plus (optionally) the project header shown above.

ResourceRoutes
ExecutionsGET/POST /v1/executions/, …/{id}, …/{id}/node-executions, …/{id}/tree, …/summary
StreamsGET /v1/streams/{execution_id} — live Server-Sent Events
WorkflowsGET/POST /v1/workflows/, …/{id}, …/{id}/validate, …/{id}/deploy, …/{id}/versions
DeploymentsGET /v1/deployments/, …/{id}
ConversationsGET/POST /v1/conversations/, …/{id}, …/{id}/executions
ApprovalsGET /v1/approvals/, …/{id}, POST …/{id}/approve, …/{id}/reject
Connections / Providers / GatewaysGET/POST /v1/connections/, /v1/providers/, /v1/gateways/
IntegrationsGET/POST /v1/integrations/, …/{id} — custom (OpenAPI) connectors
ProjectsGET /v1/projects/ — the projects your key can reach, and your role

CLI commands

GroupWhat it does
compass authlogin, logout, whoami.
compass configManage profiles (list, use, path).
compass workflowslist, get, create, update, delete, validate, deploy.
compass agentslist, get, create, update, execute, delete.
compass executeDispatch an execution of a deployment or workflow.
compass executionsInspect executions: list, get, node-executions, tree.
compass approvalsDecide human-in-the-loop approvals.
compass projectslist the projects your key can reach, and use one.
compass conversationslist, get, delete.
compass connections · providers · gatewaysManage each kind of connection.
compass integrationsManage custom (OpenAPI) connector definitions.

Run compass --help, or compass <group> --help, to see every option. Most commands print a readable table by default; use -o json or -o yaml (--output) for machine-readable output:

compass workflows list -o json
compass executions get <execution-id> -o yaml

Python resources

The client groups calls by resource:

ResourceUse it for
client.executionsDispatch executions and read their results and traces.
client.streamsSubscribe to an execution's live events.
client.workflowsList, get, create, update, validate, and deploy workflows and agents.
client.conversationsGroup executions into conversations.
client.approvalsList and decide human-in-the-loop approvals.
client.filesUpload files to attach to executions.
client.connectionsManage integration connections.
client.integrationsManage custom (OpenAPI) connector definitions.
client.providersManage provider (LLM) connections.
client.gatewaysManage gateway connections.
client.projectsList the projects your key can reach, with your role.

Python errors

The SDK raises typed exceptions you can catch:

ExceptionWhen
AuthErrorThe request was rejected as unauthenticated or forbidden — a revoked key, or one without access here.
NotFoundErrorThe resource doesn't exist in your project.
ValidationErrorThe request was rejected as invalid.
RateLimitErrorYou've been rate limited (the client retries with backoff).
ServerErrorSomething failed server-side.

All of them derive from a common CompassClientError, so you can catch broadly or narrowly. A key that can't be exchanged for an access token at all — malformed, or refused outright — raises CompassClientError itself, before any API call is made.

Next

On this page