CLI
The incantory command-line client: device login, pull, push, diff, labels, forks, render, installs, export and import, codegen, eval reports and webhooks.
The CLI needs Node 20.19 or later. Run it with npx or install it globally.
npx incantory login
npx incantory add alice/code-review@production --to claudeEvery command accepts -h / --help for its usage. incantory --help lists them all.
Global options
| Option | Meaning |
|---|---|
--json | Print exactly one JSON document on stdout; progress goes to stderr |
--url <url> | API base URL (default $INCANTORY_URL or https://incantory.ai) |
--offline | Use only the local cache (pull, render) |
-q, --quiet | Less output |
--no-color | Disable colour (also NO_COLOR=1) |
-h, --help | Help for a command |
--version | Print the version |
Environment
| Variable | Meaning |
|---|---|
INCANTORY_TOKEN | API token; overrides the stored login. Use this in CI |
INCANTORY_URL | API base URL |
INCANTORY_CACHE_DIR | Cache directory (default $XDG_CACHE_HOME/incantory or ~/.cache/incantory) |
INCANTORY_NO_TELEMETRY | 1 to skip recording install events |
NO_COLOR | Disable colour |
INCANTORY_DEBUG | Print stack traces on unexpected errors |
Account
incantory login
incantory login [--scopes read,write] [--device-name name] [--no-browser]Logs in with the device flow: the CLI mints a token, registers only its hash, prints a code and opens the approval page. After you approve, the token is saved to ~/.config/incantory/credentials.json (mode 0600, one entry per API URL).
incantory logout
incantory logoutForgets the stored token for this server. Revoke it on the server at Settings → Security.
incantory whoami
incantory whoamiShows the account behind your token.
Working with prompts
incantory pull
incantory pull <owner/slug[@label|@vN]> [dir] [--force]Downloads a prompt into a working directory (default: the slug), with the entry file's frontmatter restored, and records the version in .incantory/state.json. Refuses to overwrite local changes unless you pass --force.
incantory push
incantory push [dir] -m <message> [--force]Commits the directory as a new version, sending the version you pulled as baseVersion. If someone else committed first you get stale_base and exit code 5; --force commits on top anyway. If nothing changed it says so and exits 0.
incantory diff
incantory diff <owner/slug> <a>..<b>Unified diff between two versions, including frontmatter (1..3 or v1..v3).
incantory log
incantory log <owner/slug> [--limit N] [--all]Versions, newest first, with labels, yanked marks, author and hash.
incantory label
incantory label set <owner/slug> <name> <vN> [--reason text] [--protected] [--require-passing-eval]
incantory label ls <owner/slug>
incantory label rm <owner/slug> <name>
incantory label history <owner/slug> <name>Moves, lists and deletes labels, and shows a label's move history. A move onto a version without a passing eval fails with eval_required when the label requires one.
incantory fork
incantory fork <owner/slug[@label|@vN]> [--slug new-slug] [--license SPDX]Forks into your namespace, at the ref's version if it names one.
incantory render
incantory render <owner/slug[@label|@vN]> [--var name=value]... [--var name=@file] [--vars-file vars.json] [--on-missing error|keep|empty]Renders the prompt with the shared template engine. --var name=@file reads the value from a file. Chat prompts print as ## role sections, or as messages with --json. No model is called.
incantory export
incantory export <owner/slug[@label|@vN]> [dir] [--force]Writes a git-friendly directory: the package files plus incantory.json metadata.
incantory import
incantory import [dir] [--slug s] [--title t] [--visibility public|unlisted] [--draft] [-m message]Creates a new prompt from a directory: an export, or any folder with a recognisable entry file such as prompt.md, SKILL.md or *.mdc. The directory then becomes a working copy you can push.
incantory codegen
incantory codegen <owner/slug[@label|@vN]>... [-o prompts.d.ts]Writes TypeScript types for the prompts' variables. They plug into @incantory/sdk, so render() is type-checked.
Installing into coding tools
See Install into tools for where each tool's files go.
incantory add
incantory add <owner/slug[@label|@vN]> --to claude|cursor|copilot|agents|codex|windsurf|gemini [--project|--global] [--yes-i-read-it] [--var name=value]... [--no-record]Installs a prompt into a coding tool and records it in incantory.lock. A prompt the scanner rates high risk needs --yes-i-read-it. --no-record skips the install-count event.
incantory update
incantory update [owner/slug...] [--global] [--force] [--yes-i-read-it]Re-resolves label and latest refs in incantory.lock and rewrites the installs. @vN pins never change.
incantory remove
incantory remove <owner/slug> [--to claude|cursor|copilot|agents|codex|windsurf|gemini] [--global]Deletes the installed files and cuts out managed sections. Your own content in shared files is left alone.
incantory verify
incantory verify [--lock path]Checks every pin in incantory.lock against the registry (exit code 7 on a mismatch) and reports labels that have moved.
CI
incantory eval
incantory eval report <results.jsonl> (--run <id> | --ref <owner/slug@vN> [--model m] [--dataset id]) [--chunk-size N]Uploads eval results from a JSONL file (one result object per line) to an existing run or a new one. Exits 9 when the server does not offer the evals API. See Evals and the CI gate.
incantory webhook
incantory webhook ls
incantory webhook add <url> --events a,b [--prompt owner/slug]... [--description text] [--inactive]
incantory webhook rm <id>
incantory webhook test <id>
incantory webhook deliveries <id> [--limit N] [--cursor c]
incantory webhook redeliver <id> <deliveryId>Manages your webhooks. add prints the signing secret once, alone on stdout (so it can be piped into a secret store; with --json it is the secret field); store it where your receiver can read it. test sends a ping delivery, deliveries shows the delivery log, and redeliver sends a past delivery again.
Output
Plain text by default, with colour only when stdout is a terminal and NO_COLOR / --no-color are not set. Rendered prompts go to stdout; progress, the device code and warnings go to stderr. With --json, a failure prints:
{ "error": { "message": "Not found", "code": "not_found", "exitCode": 4 } }Exit codes
| Code | Meaning |
|---|---|
| 0 | Success (including "nothing to push" and "already up to date") |
| 1 | Unexpected error (INCANTORY_DEBUG=1 prints the stack) |
| 2 | Usage or invalid input: a bad flag or ref, a missing or invalid variable, invalid JSONL, a 400/413/422 |
| 3 | Authentication: not logged in, 401/403, or login denied or expired |
| 4 | Not found (404/410, unknown label) |
| 5 | Conflict: stale_base, local changes would be overwritten, a directory is not empty, slug_taken |
| 6 | The risk gate refused a high-risk prompt (re-run with --yes-i-read-it) |
| 7 | Integrity: a content hash mismatch, lock_mismatch, or a failed verify |
| 8 | Network, rate limit or server unavailable (after retries), or an offline cache miss |
| 9 | This server does not support the operation yet |