Skip to content

ekka CLI reference

The ekka CLI is your command line for running and governing agents on EKKA. Every command takes --help, and -v adds the mechanism behind any output: the hash chain, the ids, the internal names. The default view says what happened.

Setup and identity

Command What it does
ekka login --email [email protected] Sign in. We email a link; there is no password. Creates your account the first time.
ekka login [--email <you>] [--no-browser] Sign in via the browser and store a fresh session token. --email sends a one-time sign-in link instead; --no-browser prints the URL.
ekka whoami [--json] Show the org, environment and Enclave identity you're signed in as.
ekka logout Clear local session tokens (keeps profile metadata, the vault, and the Enclave identity).
ekka doctor Check whether an agent can work here and name what is missing. Runs eight checks in the order a new organization has to satisfy them, and always prints all eight.

Signing in, and enrolling the machine, are two different things

ekka login refreshes your session and leaves the Enclave alone. Enrolling this machine is ekka enclave create then ekka enclave start <id>, which you do once per machine. After that, login is all you need when your session expires.

Enclave

Command What it does
ekka enclave list Every Enclave your organization has, its health, and which build each one is running. Run this before creating one: you may already have an Enclave waiting to be claimed. Revoked ones are hidden unless you pass --all.
ekka enclave create --name my-laptop Create an Enclave id. Give it a name you will recognize in the list, not a placeholder. The id is safe to share with whoever runs the machine.
ekka enclave start Boot your Enclave in the foreground. Wait for authenticated; entering run loop. The first time, ekka enclave start <id> claims it for this machine, and that first run also looks for Claude Code (see below). On a server, run it under systemd instead of leaving it in a terminal: see Running on a server.
ekka enclave install-service [--dry-run] [--no-start] Install the Enclave as a systemd service so it survives reboots. The unit is generated from this machine: the enrolled home, the account that owns it, and the path of this binary. Linux, and needs root. See Running on a server.
ekka enclave status [--json] Whether an Enclave is running on this machine, and which build. Local only, and it uses no network. For a machine you are not sitting at, use ekka enclave list.
ekka enclave stop Stop the Enclave process on this machine. The organization's record is untouched, so you can start it again.
ekka enclave pause <id> Stop giving this Enclave work. Anything already running finishes first.
ekka enclave resume <id> Start giving a paused Enclave work again.
ekka enclave revoke <id> Revoke an Enclave permanently and release its slot. This is how you clean up one you created by mistake.
ekka enclave reset Erase this machine's enrollment so it can enroll again. Local and offline.

The Enclave is where each governed operation actually runs, on your side. Your data and keys never leave your machine. The Enclave is built into the signed ekka binary, so ekka enclave start is all you need.

Claude Code on this machine

When you claim an Enclave, that first ekka enclave start <id> checks whether Claude Code is installed here. If it is, the path is recorded as EKKA_AI_CLI_CLAUDE in ~/.ekka/enclave.env and your Enclave reports that it can offer that model, the same way it reports any other gate. The message names the path it found and the file it wrote it to, because a value you did not type should always trace back to a sentence you read.

It happens once, at claim. It records a path and nothing else about your machine, and it sends nothing anywhere.

Being available is not permission. Nothing runs through the model until you grant it to a plan, which is the same rule that governs every gate.

The setting is optional. To turn it off, delete the EKKA_AI_CLI_CLAUDE line from ~/.ekka/enclave.env and restart the Enclave: with the key unset, the Enclave offers no Claude gate. ekka enclave config prints the effective value and whether it came from the file, the environment, or a default.

revoke and reset are not interchangeable

ekka enclave revoke <id> ekka enclave reset
Acts on your organization's record of the Enclave this one machine
Needs the network yes, and works from any machine no, it is offline
Removes the row from enclave list yes no
Destroys local secrets no yes: the vault, the sealed identity and the device secret in this machine's keychain

Revoking stops the Enclave receiving work within about 90 seconds, lets a step already in flight finish, keeps every receipt it produced, and releases its Enclave slot. Any member of the organization can run it, and it asks you to confirm by typing the Enclave's name; --confirm <name> skips the prompt in a script.

Use reset on a machine whose vault is damaged, or on hardware you are handing on. What it erases exists nowhere else.

Guided demo

Command What it does
ekka demo Watch EKKA govern one real call, end to end. It creates a plan in your organization, denies a call it has no permission for, grants that permission, runs it again, and verifies the receipts. The plan is left behind so you can read what happened.

ekka demo takes no arguments. See the Quickstart for a beat-by-beat walkthrough.

Gate operations

Run one governed gate operation on the real governed path, or preview the decision without executing it. Admin-only (EKKA enforces this on your own tenant).

Command What it does
ekka gate <type> <op> --instance <alias> --resource <name> [--input <json>] [--check] Run one governed gate operation. --check previews allow or deny with no I/O and no cost; without it, the op executes through the gate and records a signed receipt. Types include postgres, llm, and mcp.

--instance names which gate instance serves the call. Every gate type has one, including llm, and there is no default, so the command always names the gate you meant. Run ekka gate list to see the instances your organization has: it prints them as <type>/<instance>.

# A database read (execute): reports ALLOWED + a receipt, or DENIED before any I/O
ekka gate postgres list --instance demoV1 --resource customers

# Preview only: does a standing Grant cover this? (no I/O)
ekka gate postgres list --instance demoV1 --resource customers --check

# An AI-model call: the model is the resource, the prompt rides in --input
ekka gate llm infer --instance prod --resource anthropic/sonnet-4 \
    --input '{"prompt":"hello"}'

Execute mode needs a running Enclave (ekka enclave start).

Naming a gate instance, and its credentials

A plan refers to a gate instance by alias, so the plan never carries a connection string. Credentials are deposited against the gate and their values are never printed back.

Command What it does
ekka gate alias create <gate> <alias> ... Name one gate instance so plans can refer to it.
ekka gate alias list <gate> The aliases defined on one gate.
ekka gate alias revoke <gate> <alias> Revoke one alias. Plans naming it stop resolving.
ekka gate credential deposit <gate> ... Store a secret for a gate to authenticate with.
ekka gate credential list <gate> The credential refs one gate holds. Values are never printed.
ekka gate credential revoke <gate> <ref> Revoke one credential.

Grants

A Grant is durable authorization: an agent may perform an operation on a resource, through a gate, until you revoke it. Admin-only.

Command What it does
ekka gate grant add --type <type> --instance <alias> --resource <name> --capability <code> [--agent <id>] [--ttl <seconds>] Grant an agent one capability on one resource. Capability codes are listed on What's included. --instance names the gate that serves the grant, for every gate type including llm, and there is no default. --agent is optional: omit it and ekka resolves your organization's core agent (pass it only to target a specific agent on a multi-agent team). --ttl is in seconds with no suffix, and defaults to 30 days. For --type llm, add per-call caps: --max-input <n> --max-output <n> --max-total <n>.
ekka gate grant list [--agent <id>] [--json] List active Grants (optionally for one agent).
ekka gate grant revoke <grant-id> Revoke a Grant. The same operation is refused again, live.
ekka agent declare <agent-code> --add <capability> Widen what an agent asks for. A grant may only name a capability the agent already declares, so this comes first. Creating a plan widens the declaration automatically while you own the agent and have never published it, which is why you rarely need this by hand.
ekka agent list [--json] Agents that can act here: your own, your core one, and any you installed.
ekka agent create <name> Create a new agent in your organization.
ekka agent catalog [--json] Published agents you could install, and where you stand with each.
ekka agent install <agent> Let a published agent act here. Installing consents to the permissions it asks for.
ekka agent approve <agent> Re-consent after its publisher changed what it asks for. Until you do, it keeps running under what you already agreed to.
ekka agent uninstall <agent> Stop an agent acting here. Your grants for it are kept, so re-installing does not mean re-granting.
ekka agent show <agent-code> What one agent declares, and which plans use each item. DECLARED: nothing is normal on a new organization: create a plan and it fills in.
# Let your agent read the customers table (agent resolved automatically)
ekka gate grant add --type postgres --instance demoV1 \
    --resource customers --capability knowledge.postgres.read

# Let your agent call a model, with per-call token caps
ekka gate grant add --type llm --instance prod \
    --resource anthropic/sonnet-4 --capability llm.infer \
    --max-input 4000 --max-output 1000 --max-total 5000

Plans and schedules

A plan wires governed gate operations into ordered steps; a schedule runs a plan on a cadence for your organization only. See Create your first plan for authoring. Admin-only; a plan must be active to be scheduled.

Command What it does
ekka plan list [--limit <n>] Your organization's plans, with the identity every other command takes.
ekka plan show <plan> One plan: its steps, the capability each step consumes, and the inputs it takes at run time.
ekka plan show <plan> --definition The plan as authored: what your file said.
ekka plan show <plan> --compiled The plan that runs, after skills and cataloged calls are expanded and every @input.x is compiled into a typed binding.
ekka plan template <file.json> --gate <type>[/<instance>] --op <read\|write\|list> Write a complete starter plan for one governed gate call, so your first plan is not a blank file. The file carries the plan's name beside its steps, so plan create needs nothing else. Add --model <id> for the llm gate. Refuses to overwrite an existing file.
ekka plan validate <file.json> [--json] Check a plan file the way plan create would, creating nothing. Prints what the plan would need: each capability and resource, and whether a grant already covers it. Exits 0 only when create would succeed, so CI can hold plan files to the same bar.
ekka plan create <file.json> [--schedule <cadence>] Create the plan the file describes and print its versioned identity (for example [email protected]). The file carries the whole plan (name, version, steps), so the same file creates the same plan from your laptop or from CI. On success it prints what the plan needs, with the exact ekka gate grant add command for anything missing. Add --schedule (for example --schedule "@daily") to create and schedule in one command.
ekka plan delete <plan> Delete a plan. It stops running and leaves ekka plan list, and the identity can be used again. Runs it already produced keep their Receipts, and ekka receipts verify still verifies them, because each run carries its own copy of the plan. A run already in flight finishes normally. Refused while a schedule still points at the plan: ekka plan unschedule first.
ekka plan run <plan-identity> [--input key=value ...] Run a plan once, now, as a governed run. Pass the full identity that plan create printed. --input repeats.
ekka plan schedule <plan-identity> --cron "<expr>" [--tz <zone>] [--input key=value ...] Run a plan on a cadence. Standard 5-field cron (for example "0 9 * * 1-5") or an alias (@hourly, @daily, @weekly, @monthly). --tz is an IANA timezone (default UTC). Inputs are the same surface as ekka plan run and ride on every fire.
ekka plan schedule <plan-identity> --every <interval> The friendly interval form: 1m, 5m, 15m, 30m, 1h, 6h, 12h, or 1d.
ekka plan schedules List your schedules: cron, active state, NEXT-RUN, and LAST-RUN. A populated LAST-RUN means the schedule is firing.
ekka plan unschedule <schedule-id> [--pause\|--resume] Remove a schedule, or pause and resume it in place.
# Every weekday at 9am, New York time, with an input
ekka plan schedule "[email protected]" \
    --cron "0 9 * * 1-5" --tz America/New_York \
    --input audience=sales

# The common case: just run it hourly
ekka plan schedule "[email protected]" --every 1h

Every scheduled fire is a normal governed run: Grants are enforced, every step produces a signed Receipt, and ekka receipts verify covers scheduled runs exactly like manual ones. Pausing keeps the schedule; resuming realigns it to the next real slot, and a paused schedule never back-fires missed runs. Missed fires during downtime are skipped, not bursted.

--definition and --compiled answer different questions

They are two different documents. A cataloged API step is written as {call, to, subject, text} and reaches the gate as {resource, key, value: {method, body}}. Only the compiled form answers "why did my run do that", because it is the one that actually ran.

A compiled plan appears once the plan is created. Editing a plan clears it until it is recompiled, and --compiled says so rather than printing nothing.

Receipts and runs

Command What it does
ekka receipts list [--json] List recent runs found in your local audit log (newest first).
ekka receipts show <run-id> [--json] Print a run's signed receipt chain (the Gate Token issued, each gate's receipt, the run attestation) with its hash links.
ekka receipts verify <run-id> [--json] Verify a run's signed receipt chain offline: recompute the hash chain and check every signature.
ekka run list [--limit N] [--json] List recent runs, newest first.
ekka run show <run-id> [--json] Show EKKA's allow or deny decision for a run, including the reason an action was denied and which grant would have covered it.
ekka receipts trace <run-id> The unsigned half of a run: which endpoint each step reached, its status and how long it took. Troubleshooting detail, never evidence. The signed half is receipts show.

A denied action produces a decision but no receipt chain (nothing ran, so nothing was signed): use ekka run show for those. See Governance receipts for how to read them.

Skills

Reusable bodies of work a plan can call by name. See Skills for what they are and how to write one.

Command What it does
ekka skill list [--all] [--json] Every skill this organization can use. --all includes archived ones, which are hidden by default.
ekka skill show <name>[@<version>] [-v] [--json] One skill: what it takes in, what it hands back, its size and its versions. Without @<version> you get the newest.
ekka skill test <file> [--json] Run every check publish makes and create nothing. Use it while you are writing the file.
ekka skill publish <file> [--json] Publish a skill file. EKKA assigns the version; a published version is never rewritten.
ekka skill fork <name>[@<version>] [--out <file>] Copy a published skill into a file you can edit. Only an open skill can be copied.
ekka skill promote <plan-file> --name <name> [--op <id>] [--out <file>] Turn an operation from a plan file into a skill file. Every @input.<name> becomes a port.
ekka skill from-api <api>[@<version>] --call <call> [--name <name>] [--out <file>] Write a skill file for one operation of a cataloged API.
ekka skill archive <name>@<version> [--json] Stop offering a version. It leaves the listing and the next plan naming it is refused. Plans that already use it keep working.
ekka skill unarchive <name>@<version> [--json] Offer an archived version again.

Archiving does not stop anything that already runs

A plan copies a skill's steps into itself when the plan is created, so it never looks the skill up again at run time. A schedule firing tonight runs exactly what it ran last night. Archiving changes the future: the skill leaves ekka skill list, and the next plan that names it is refused.

A version is always required, because name@1 and name@2 are different bodies and a plan pins one of them. Nothing is deleted, and unarchive undoes it.

promote, from-api and fork publish nothing

All three write a file on your machine. Read it, edit it, then ekka skill test and ekka skill publish. A generated body has a blank output_map for you to fill in, so publishing it unread would ship a contract nobody chose.

APIs and the catalog

Third-party APIs a plan can call: Slack, S3, Gmail, and whatever your organization catalogs itself. See Add your own API for the whole flow.

A connection is per machine. The credential lives in this machine's vault and never leaves it, so an API connected on your laptop is not connected on a colleague's.

Command What it does
ekka api list [--json] What this organization can connect, whose row each one is, and which are connected on this machine.
ekka api describe <name> [--version <n>] What the API is, in plain English: its address, the credential it takes, and every call it offers. Name a version to read one that is no longer the newest.
ekka api spec <name> [--version <n>] [--json] The same facts as the fields a plan step carries. This is what you copy when writing a plan against it.
ekka api connect <name> Connect it on this machine. Asks for what the API needs and stores the credential in this machine's vault.
ekka api test <name> [--connection <name>] [-v] Does this connection work right now: four answers on one screen, for the connection file, the credential in this machine's vault, the grant, and a live call. A check that cannot be performed says so and is never reported as a pass. Add --connection when this machine holds several connections of the same API.
ekka api disconnect <name> [--yes] Remove the connection and its credential from this machine. The catalog row is untouched.

Putting an API into the catalog

Your own internal APIs are yours to add, with no deploy and no waiting on us. A row you add is private to your organization and named <your-org>/<name>.

Command What it does
ekka api catalog validate <file.json> [--json] Check a catalog file and create nothing. EKKA runs the real insert against the real rules and throws it away, so the answer is the one adding it would give.
ekka api catalog add <file.json> [--json] Add the API in this file to the catalog.
ekka api catalog publish <org>/<name>@<version> [--json] Offer one of your rows to every organization on this EKKA. It stays private until EKKA approves it.
ekka api catalog archive <org>/<name>@<version> [--json] Stop offering one of your rows. It leaves ekka api list and the bare name stops resolving to it.
ekka api catalog unarchive <org>/<name>@<version> [--json] Offer an archived row again.

A row is never edited, and archiving is how you retire a wrong one

Fixing an API means publishing the next version, because a plan pinned to version 1 must keep running exactly what it ran yesterday. That leaves the wrong version still in the menu, and archiving is what takes it out.

Nothing connected to it breaks: a connection pins a version and a compiled plan holds the whole request, so neither reads the row again. An archived row is still readable by naming its version (ekka api describe <name> --version 1), which is how you see what an old connection points at.

Organizations and members

Command What it does
ekka org list [--json] Every organization you belong to. The active one is marked.
ekka org create <slug> [--name <name>] Create an organization and switch to it.
ekka org switch <slug> Change which organization your commands act on.
ekka org members list Who is in the organization, and their role.
ekka org members invite <email> --role <role> Invite somebody by email. Nothing is shared until they accept.
ekka org members resend <email> Resend a pending invitation. The role is unchanged.
ekka org members set-role <email> <role> Change a member's role, one of admin, member or viewer.
ekka org members cancel <email> Cancel a pending invitation.
ekka org members remove <email> Remove a member from the organization.
ekka org edition [--json] Which edition this organization is on, and what it includes.
ekka org usage [--json] What this organization has run, metered, and what credit is left.
ekka org delete <slug> --confirm <slug> Delete an organization that is still pending, or deactivate an active one. Receipts and audit history are retained.

Spend ceilings and credit

Command What it does
ekka org limits [--json] The spend ceilings this organization runs under, and which are EKKA's defaults versus its own.
ekka org limits set <meter> <max> [--period <period>] Set this organization's own ceiling for one meter. Raises or lowers it. Admin only.
ekka org limits remove <meter> [--period <period>] Give up this organization's own ceiling and go back to EKKA's default. Admin only.
ekka org billing [--json] What credit this organization has left, and what it has spent this period.

A ceiling bounds how much gets spent in a period. That is a different question from ekka org edition, which shows the published limits on how much can exist (seats, Enclaves, agents). EKKA stops work when a ceiling is reached, so ekka org limits is the screen that answers "why was I refused".

ekka org limits marks every row as EKKA's default or as your own choice, because who chose a number decides who can change it. remove prints the default it went back to: removing your ceiling is not the same as having none.

Changing a ceiling is recorded

set and remove are admin decisions. Each one is written to your organization's audit chain on the same transaction as the change, and the owner is emailed even when the owner made the change. Read them back with ekka audit list.

Credit is prepaid: work spends it, and when it runs out work stops. There are no invoices and no card is kept on file for automatic charges. Credit is added to your organization by the EKKA team, so write to [email protected] to top up. ekka org usage shows the balance beside what has actually been consumed. Prices are on Pricing.

Switch before you delete

ekka org delete only resolves the active organization and answers "not found" for any other. Switch to it first. Deleting the organization your Enclave was claimed in is how a machine ends up bound to an Enclave that no longer exists.

Environments and appearance

Command What it does
ekka env list [--json] The environments this machine is enrolled in.
ekka theme [dark\|light\|auto] Show the colors ekka prints with, or change them. Leave the value out to see what is set. NO_COLOR turns color off entirely.

Secrets

The local Enclave vault. Values never appear on the command line and never leave your machine, and they are encrypted at rest: even the filenames on disk reveal nothing about what is stored, and the Enclave's own identity is kept the same way. On macOS and Windows the sealing key lives in the OS keychain, so the vault stays sealed if its files are copied off the machine; on Linux the key is a permission-protected file, so full-disk encryption is still worth turning on. Names must match ^[A-Z][A-Z0-9_]{2,127}$.

Command What it does
ekka secret put <NAME> --stdin Store a secret, value read from stdin.
ekka secret put <NAME> --from-env <ENV_NAME> Store a secret, value copied from an environment variable.
ekka secret list [--json] List stored secret names and metadata (never values).
ekka secret remove <NAME> Remove a secret (idempotent).

Shell completion

Command What it does
ekka completion <bash\|zsh\|fish> Print a shell-completion script for your shell.