CLI reference
The canonopy command covers the whole workflow from a terminal: build a model from the JSON you send Jev (canonopy build), review how it decides (optional), add past cases, retrain, read reports and advice, decide, and manage versions and keys. It's optional: every command is one plain HTTP call to the API, and coding agents can use the hosted MCP connector with nothing installed.
Install
pip install https://canonopylabs.com/dl/canonopy_cli-0.6.2-py3-none-any.whlThe canonopy-cli package needs Python 3.9 or later and nothing else. pipx install works with the same URL. Set your key from the console:
export CANONOPY_API_KEY=cnp_…--keyoption- Your API key. Default:
$CANONOPY_API_KEY. --base-urloption- The API. Default:
$CANONOPY_BASE_URL, orhttps://api.canonopylabs.com. --jsonoption- Print the API's JSON instead of a summary.
Commands
In the order you'd usually use them. A decision model is called a domain in the API.
canonopy build jev-request.json --name refunds --rules "Never approve when amount is over 500." # your own model from a Jev request
canonopy build status refunds # where the build is (or: a build id)
canonopy build jev-request.json --interview # a few questions about your JSON first
canonopy build questions BUILD_ID # the questions (or: a model's name)
canonopy build answer BUILD_ID # answer them on the terminal (or --file answers.json)
canonopy playtest my-bot@latest --cmd "python my_game.py" --episodes 20 # your game plays with the model, locally
canonopy shadow start refunds # shadow mode: beside your current decisions
canonopy shadow send refunds requests.jsonl # real requests with your current decision
canonopy shadow review refunds # the disagreements (--pick-model, --pick-current, --skip)
canonopy spot-checks refunds # this week's optional card (--set off|light|thorough)
canonopy init refunds --describe "We handle refund requests. Actions: approve, escalate, decline. …"
canonopy describe refunds "Card vs payment: these go to cards" # the set-up conversation (- reads stdin)
canonopy examples refunds # optional: how it decides on about 20 cases
canonopy signoff refunds --correct ex_03:action=escalate --retrain # optional: correct any, retrain with them
canonopy upload refunds past_cases.csv # CSV with a header row, JSONL or JSON
canonopy upload refunds better_cases.csv --replace # these replace every uploaded case
canonopy uploads refunds # each upload: id, date, file, cases
canonopy uploads delete refunds UPLOAD_ID # one upload's cases, deleted permanently
canonopy data clear --confirm refunds # every uploaded case (--signoff, --outcomes)
canonopy train refunds # --no-wait, --promote auto|always|never
canonopy advice refunds # what would improve it most
canonopy report refunds # or: canonopy report refunds 3
canonopy decide refunds@latest --state '{"message": "refund please", "amount": 40}'
canonopy options refunds action store-credit --description "offer store credit" --when "tier is pro"
canonopy outcomes DECISION_ID --action approve # what really happened
canonopy outcomes --unsure refunds # the unsure queue
canonopy outcomes DECISION_ID --review refunds --answer action=escalate
canonopy progress refunds # what's waiting for the next retrain, and every version
canonopy versions refunds
canonopy promote refunds 3 # what refunds@latest serves
canonopy download refunds@latest -o refunds.zip # to run yourself
canonopy fallback refunds --provider typesafe --key-env TYPESAFE_API_KEY
canonopy keys [list | create NAME | revoke KEY_ID]
canonopy decisions refunds --route review --since 2026-09-01 # the decision log (--json for JSON)
canonopy decisions show refunds DECISION_ID # one decision in full
canonopy decisions export refunds --format csv > decisions.csv # or --format jsonl, -o FILE
canonopy decisions delete refunds DECISION_ID # or --before 2026-06-01 --confirm refunds
canonopy decisions wrong DECISION_ID --answer escalate # mark a decision wrong (--note "…")
canonopy retention [30_days | 90_days | 365_days | until_deleted] # how long decisions are kept
canonopy sync # cases a downloaded model saved offline
canonopy sync --status # where they are, and how many wait
canonopy mcp # the local MCP server
canonopy skill install # the agent skill for Claude Code (--project, --dir, --force)--state and --questions take JSON, plain text, or @file.json. Errors print the API's message and exit with status 1.
canonopy sync sends what a downloaded model saved while it couldn't reach us (it needs the canonopy-runtime package installed alongside; --dir picks another folder). Each case leaves the local file once it's stored; the held ones join your unsure queue.
canonopy decisions filters with --since, --until, --source, --route, --answer action:refund (repeatable), --version, --has-outcome or --no-outcome, and --search (words in the case's text, or a decision id); --limit and --cursor page through. Export takes the same filters. See The decision log.
upload --replace, uploads delete and data clear delete cases permanently; examples you corrected and outcomes stay unless data clear gets --signoff or --outcomes, and versions already trained are kept. Train again afterwards for the next version of the same model. See Replace or remove cases.
Build from a Jev request
For models made from the JSON you send Jev (Start with no data), in canonopy-cli 0.4.0 and later:
canonopy build jev-request.json # the body you send Jev, as is
canonopy build jev-request.json --name refunds --description "Refund requests" \
--rules "Never approve when amount is over 500. Always escalate when fraud_flag is true."
canonopy build jev-request.json --name refunds --examples more-states.jsonl \
--field "order.amount=the refund asked for, in USD (0-5,000)" # 5-20 more real states, notes on fields
canonopy build jev-request.json --name refunds --history past_refunds.csv --wait
canonopy build status refunds # the latest build of a model, or a build id
canonopy examples refunds # optional, once it's ready: how it decides
canonopy signoff refunds --correct ex_03:action=escalate --retrain # optional: correct any, retrain with them
canonopy rules found refunds # rules found in your history
canonopy rules found refunds --confirm fr_3 --hard fr_1 --reject fr_2
canonopy history flagged refunds --status pending # past cases that contradict your rules
canonopy history flagged refunds --follow-rule h1042 --keep h1180 --drop h2210
canonopy history flagged refunds --all follow_rule # or keep, or drop
canonopy advice refunds # what would improve it most
canonopy train refunds # a targeted retrain: prints the build id
canonopy rules change refunds "Always escalate when amount is over 300." # retrains now; --replace for all your rules
canonopy decisions wrong DECISION_ID --answer escalate # or --answer action=escalate, --note "…"build FILEcommandFILEholds{"state", "questions"}, and optionallyexamples,fields,rulesandname(a pasted Jev request works:modelis ignored).--examples FILE(5-20 more real states, likestate: one per line, or a JSON list; up to 50; no past decisions or answers needed, a few examples of what you send Jev make it better),--fields FILE(notes on fields: a JSON object keyed by path or name) and--field "path=note"(repeatable),--rules "…"or--rules-file F(plain words),--name,--description,--history FILE(past cases: CSV, JSONL or JSON),--wait(until the model is ready, needs attention or failed; nothing waits for you in between),--json.build … --interviewcommand- The build asks a few questions about your JSON first and waits for your answers up to
--answer-timeoutseconds (default 600), then goes on with what it has. With--wait, it returns when the questions are ready. build questionscommand- A build id or a model's name (its latest build): the questions, most useful first, and what each answer holds.
--round 2for the follow-up. build answercommand- Asks each question on the terminal (Enter skips it), or sends
--file answers.json({"answers": [{"id": "q01", "text": "…"}]}).--more: more answers follow, the build keeps waiting. build statuscommand- A build id (
bld_…) or a model's name: where the build is, what it read, the quality check, and what to do next. rules foundcommand- Lists the rules found in your history with their support, agreement and what confirming each changes.
--confirm,--rejectand--hardtake rule ids (fr_1 …);--hardconfirms a rule and enforces it on every decision, like your own rules. A build id works in place of the model's name. history flaggedcommand- Lists flagged past cases (
--status pendingorreviewed,--limit,--cursor).--follow-rule,--keepand--droptake case ids;--alldecides for every pending case. rules changecommand- New rules in plain words (or
-to read them from stdin), added to yours (or--replace). Your model is retrained with them straight away, and the build says what changed; the new version serves only if it passes the quality check.--waitwaits for the build to finish. Its examples (the changed situations) are optional to review withcanonopy examples. decisions wrongcommand- The right answer for a decision:
--answer escalate(the decision question) or--answer question=answer(once per question), and--note.canonopy decisions wrong MODEL DECISION_IDworks too. The next retrain learns it. advicecommand- What would improve the model most, in plain words.
examplescommand- Optional, any time: how your model decides on about 20 situations, with the answer for each and why.
signoffcommand- Optional:
--correct EXAMPLE_ID:question=valuefor each example you correct (repeatable), and--retrainto retrain with them now. Without--retrain, they apply at the next retrain.--all-okalso marks every other example right.
On a model made with canonopy build, canonopy train starts a targeted retrain and prints its build id; canonopy build status shows the before and after. See Rules found in your history and Improve your model.
Try it on real work
canonopy playtest my-bot@latest --cmd "python my_game.py" --episodes 20 [--once] [--keep-situations 200]
canonopy shadow start|stop|status refunds
canonopy shadow send refunds requests.jsonl
canonopy shadow review refunds [--pick-model ID … --pick-current ID … --skip ID …]
canonopy spot-checks refunds | canonopy spot-checks --set thoroughplaytestcommand- Serves the model (a local
.zip, orname@versiondownloaded from your workspace) at a local endpoint on 127.0.0.1, runs--cmdonce per episode (or once for all with--once), reads one JSON line of numbers per episode, and sends only those numbers (--no-sendto keep them). Needscanonopy-runtime. See Playtest your model. shadowcommandstart,stop,status;send MODEL FILE(JSON lines of{"state", "current", "source", "confident"});reviewlists the disagreements, and--pick-model,--pick-current,--skiprecord your review. See Shadow mode.spot-checkscommand- This week's optional card for a model, or
--set off|light|thoroughfor the workspace.
The local MCP server
canonopy mcp runs an MCP server on stdio so coding agents can use every step above, plus a docs tool. It reads your key from CANONOPY_API_KEY and never prints it.
claude mcp add canonopy --env CANONOPY_API_KEY=cnp_… -- canonopy mcpMost agents don't need it: the hosted MCP connector has the same tools with nothing installed. Use the local server to upload files straight from disk, save downloaded models to disk, or read a day-one backend's key from an environment variable. Setup for Cursor, Codex and other clients: Use with coding agents.
The agent skill
canonopy skill install copies the Canonopy Decisions skill to Claude Code's personal skills folder, ~/.claude/skills/canonopy-decisions/, and prints where it went. --project installs it in the current project's .claude/skills/ instead (or --project DIR), and --dir PATH in any agent's skills folder (as PATH/canonopy-decisions/). It never replaces an installed copy unless you add --force. canonopy skill show prints SKILL.md.
The runtime CLI
The runtime that runs a downloaded model offline has a command line of its own, in the canonopy-runtime package:
pip install "canonopy-runtime[text] @ https://canonopylabs.com/dl/canonopy_runtime-0.6.3-py3-none-any.whl"
python -m canonopy_runtime bank-support@3.zip request.json
canonopy-runtime sync # send the cases it saved while offline (reads CANONOPY_API_KEY)
canonopy-runtime queue # where they are, and how many wait
canonopy-runtime playtest my-bot@3.zip --cmd "python my_game.py" --episodes 20 # your game plays with it; prints the results
canonopy-runtime reader list # the text readers downloaded to this machine, and their size
canonopy-runtime reader remove # delete them to free the space (fetched again when a model needs one)request.json is a /v1/decide body. The answer is printed in the same format as the hosted endpoint. sync and queue take --dir FOLDER (default: CANONOPY_OFFLINE_DIR or your user data folder); sync exits with status 1 when it couldn't send everything (the cases stay in the file). See Running it yourself.
Or with curl
export CANONOPY_API_KEY=cnp_…
API=https://api.canonopylabs.com
curl -s $API/v1/domains -H "Authorization: Bearer $CANONOPY_API_KEY" # list domains
curl -s $API/v1/domains/refunds/data -H "Authorization: Bearer $CANONOPY_API_KEY" -F file=@cases.csv # upload
curl -s -X POST $API/v1/domains/refunds/train -H "Authorization: Bearer $CANONOPY_API_KEY" # train
curl -s $API/v1/domains/refunds/versions -H "Authorization: Bearer $CANONOPY_API_KEY" # versions