Canonfig
Reference

CLI reference

Look up every canonfig command, option, default, and exit code, in the order canonfig --help lists them.

Canonfig needs Node.js 24 or newer. Commands appear here in the order canonfig --help lists them. Run canonfig <group> --help for any group's usage and notes.

Global options and output

OptionEffect
-h, --helpShow help. After a command group, show that group's help.
-V, --versionShow the version. With --json, also show the build identity.
--jsonPrint the canonfig.cli/v1 JSON envelope. Allowed anywhere in the command.

Human output starts with a one-line message, then one line per action, resource, or check. A failure ends with a line such as exit 3: Human Action Required. When human output shortens a value it says so; use --json for the full value and in scripts.

Environment variableEffect
CANONFIG_LOG=offTurn off the command log at ~/.canonfig/canonfig.log.
CANONFIG_LOG_FILEWrite the command log to another path.
CANONFIG_DEBUG=1Add error details to internal failures (exit 1).
CANONFIG_LOCAL_CREDENTIAL_ROOTStore credentials in plaintext files under this directory instead of the OS credential store.
CANONFIG_POWERSHELLPath to PowerShell 7 on Windows 10 ARM64.

Exit codes

CodeMeaning
0Success
1Internal defect: a failure Canonfig has no explanation for
2Usage or configuration, including a Source Machine and a Follower Machine on different major.minor releases
3Human Action Required, including a locked or unavailable local credential store
4Conflict or Follower Drift
5Authentication or revocation: the Source Machine rejected or revoked this Follower Machine
6Transport: the Source Machine could not be reached
7Verification or apply failure
130Interrupted by SIGINT (Ctrl-C)
143Terminated by SIGTERM

Every failure Canonfig can explain uses a code other than 1, so a script can tell a refusal from a crash.

Self-update

canonfig self-update status
canonfig self-update check
canonfig self-update enable --apply --confirm-idle --npm-cli /home/operator/.npm-global/lib/node_modules/npm/bin/npm-cli.js
canonfig self-update apply --apply
canonfig self-update auto --apply --once
canonfig self-update disable --apply

Opt-in updates to the latest stable patch release of the installed major.minor line, for a global npm installation under your home directory. Minor and major upgrades stay manual.

CommandOptions
enable--apply, --confirm-idle, and --npm-cli <absolute path to npm-cli.js>, all required. Stop every Canonfig process and schedule first.
disable--apply required.
statusPrints settings and any interrupted update. Read-only.
checkAsks the npm registry for a newer patch. Read-only.
apply--apply required. Installs, verifies, and activates the patch only when Canonfig is idle.
autoWithout --apply, previews once. --apply keeps running in the foreground and checks every --interval <seconds> (default 86400, from 60 to 604800). --once runs one pass, for an external scheduler.

A running command or an unfinished sync blocks activation. After activating, auto exits; start it again under the activated version. See the self-update guide.

Source Machine

source init

canonfig source init

Creates the Source Machine's signing key and HTTPS certificate in the native credential store. On an initialized Source Machine it creates nothing and checks that the stored keys still match; see Source keys.

source scan

canonfig source scan --file ~/.codex/AGENTS.md --file ~/.claude.json

Proposes tool resources from evidence in the named files. At least one --file is required. It runs nothing and never proposes other kinds; see How Canonfig installs and verifies tools.

source reconcile-skills

canonfig source reconcile-skills --profile-file ~/canonfig.profile.jsonc
canonfig source reconcile-skills --profile-file ~/canonfig.profile.jsonc --apply
canonfig source reconcile-skills --profile-file ~/canonfig.profile.jsonc --apply --watch --interval 30

Removes skill resources from the profile file when you deleted their skill directory on the Source Machine. Without --apply it previews. --watch needs --apply and repeats every --interval seconds (default 5, from 1 to 86400). It never publishes and never deletes a skill directory. A conflict exits 4. See Remove deleted skills from the profile.

source digest

canonfig source digest --profile-file ~/canonfig.profile.jsonc
canonfig source digest --profile-file ~/canonfig.profile.jsonc --resource codex-config

Validates a profile and prints each resource's content digest, without publishing. --resource <id> limits output to one resource. It exits 0 even when a declared digest differs. tool and credential resources have no content digest. An unknown resource fails with "profile <id> in <file> declares no resource <r>".

source publish

canonfig source publish --profile-file ~/canonfig.profile.jsonc --reviewer dana
canonfig source publish --proposal ./proposal.json --profile workstation --name Workstation --reviewer dana
canonfig source publish --profile-file ~/canonfig.profile.jsonc --reviewer dana --allow-empty
OptionValue
--profile-file <path>The profile file. Required unless --proposal is given.
--proposal <path>A source scan proposal to accept. Without --profile-file, also pass --profile <id> and --name <name>.
--reviewer <name>Required. Recorded with the revision.
--allow-emptyPublish a revision with no resources.

Signs the next Profile Revision. Content equal to the latest Profile Revision returns that Profile Revision. Any other content, including an older Profile Revision's, becomes the next sequence number; publishing old content again is how you roll back.

Publication fails with exit 2, before signing, when:

  • a declared verify.digest does not match (the message prints the right one);
  • a source path is absolute, contains .., or resolves outside the profile file's directory;
  • a number is too large to carry exactly, or is not finite;
  • an automatic installer recipe has no exact version;
  • the revision's metadata exceeds 1 MiB;
  • there are no resources and --allow-empty is not set.

See Profile file reference.

source serve and source service

canonfig source serve --host 127.0.0.1 --port 17342
canonfig source service install --host 127.0.0.1 --port 17342
canonfig source service status
canonfig source service remove

source serve runs the Source Machine's HTTPS endpoint in the foreground. --host is 127.0.0.1 (default) or ::1; --port defaults to 17342.

source service install runs source serve as a user service: a systemd user unit canonfig-source.service on Linux, a LaunchAgent dev.canonfig.source on macOS, or a Task Scheduler at-logon task Canonfig\canonfig-source on Windows. It takes the same --host and --port. It needs source init first, refuses when another source serve already answers on the port, and waits up to 20 seconds for the endpoint. If the endpoint does not answer, it exits 7 and leaves the service installed so you can inspect it. On Linux it does not enable lingering. On macOS, run it from the logged-in desktop session, not over SSH.

source service status reports one of:

StateExitMeaning
running0Installed and serving this Source Machine.
not-installed0No service.
not-running3Installed but stopped.
not-serving3Running but not answering as this Source Machine.
drifted4The service definition changed. Run source service install again.

source service remove stops and deletes the service. See Run Canonfig unattended.

source invite

canonfig source invite --endpoint https://127.0.0.1:17342 --output ./canonfig-invite --expires 15m --group developers
OptionValue
--endpoint <https-url>Required. An https:// URL on 127.0.0.1 or ::1.
--output <path>Required. Written with mode 0600.
--expires <duration>A whole number plus ms, s, m, or h. Default 15m, at most 24h.
--group <name>Follower Group to grant. Repeat for more. canonfig:secrets enables shared secrets.
--timeout-ms <ms>Default 10000, at most 60000.

The invitation is single-use. Move it to the Follower Machine over a private channel.

source revoke

canonfig source revoke laptop-dana

Revokes one Follower Identity. Its next request fails with exit 5.

Follower enrollment

cat ./canonfig-invite | canonfig follower enroll --stdin --name laptop-dana --profile workstation
cat ./canonfig-invite | canonfig follower enroll --stdin --name desk-dana --profile workstation --replace
canonfig follower unenroll

follower enroll

OptionValue
--stdinRequired. The invitation is read from standard input only, never as an argument.
--name <name>Required. This Follower Machine's name.
--profile <id>Required. The Machine Profile to follow.
--replaceReplace this machine's existing enrollment under a different name.
--timeout-ms <ms>Limit for each network step. Default 10000, at most 300000. Kept for later requests, including scheduled syncs.

Standard input must be the invitation file, at most 16384 bytes, ending within 10 seconds. A terminal on standard input is refused. Canonfig checks that this machine can store a credential before it uses the invitation.

SituationResult
The name is already enrolledRefused: "the follower identity is already enrolled". Run canonfig source revoke <name> on the Source Machine first. Re-enrolling a revoked name keeps this machine's local settings.
This machine is enrolled under another nameExit 4: "this machine is already enrolled as <name> (<id>); pass --replace to enroll it as <new name> instead".
--replaceEnrolls the identity under the other name, then revokes the old one. Lists every reset setting (agent policy, harness and secret bindings, schedule, Local Overlay). If the old identity could not be revoked, prints the canonfig source revoke command to run.
Enrollment fails or you cancel itThe credentials it created are removed on both machines.

follower unenroll

Revokes this machine on the Source Machine, then deletes the local credential, received shared secrets, and the enrollment record. It leaves applied files, the schedule, and the tunnel record. When the Source Machine is unreachable, local removal still happens and the output shows sourceRevoked: false plus the canonfig source revoke <id> command to run. A locked credential store exits 3 and keeps the record so you can retry. On a machine that is not enrolled, it exits 0.

canonfig schedule remove
canonfig tunnel stop --forget

Synchronization

canonfig sync --plan
canonfig sync --plan --review-local
canonfig sync --apply
canonfig sync --apply --no-input
OptionEffect
--planDefault. Downloads and compares; changes nothing.
--applyApplies the plan and verifies every resource. Cannot be combined with --plan.
--no-inputNever prompts.
--review-localWith an interactive --plan, writes private reviews of first append-local adoptions. See append-local.
--scheduledSet only by the native schedule, which runs sync --apply --no-input --scheduled.

A failed action rolls back the run's file, directory, and config changes and exits 7: "resource <id> could not be applied to <target>: <cause>". Tool installs are not rolled back. Human Action Required (exit 3) and Follower Drift (exit 4) stop the run without rolling back. See the transaction boundary.

After a successful apply, Canonfig also copies shared secrets when the Follower Machine is in the canonfig:secrets group. If that copy fails, the command reports one error that says the files were applied.

When the profile suggests a schedule and you have not chosen one, the output says "schedule available" and names canonfig schedule set --default. Sync never installs a schedule.

A scheduled run restarts a managed tunnel that is down, once, before fetching. If the Source Machine is still unreachable, the run exits 6 and says to run canonfig tunnel start.

Recovery

canonfig recover
canonfig recover --no-input
canonfig abandon

recover resumes or rolls back an interrupted run. It accepts only --no-input, and needs that run's revision to still be authorized. abandon closes a run recover cannot finish; it does not undo anything, and the next run reconciles what was applied. Both exit 4 while another Canonfig process holds the run, and print its process ID. See Recover from a failed or blocked sync.

Status

canonfig status
canonfig status --json
canonfig status --follower laptop-dana

On a Follower Machine, status reports the enrollment, the applied Profile Revision, the schedule, and the result of the last run. converged is false while a run is open or interrupted, or when the last run did not converge. On the Source Machine, --follower <id> reports that Follower Machine's enrollment.

status --json includes completionReceipt, which separates: signed publication, apply result, client-load evidence, native scheduling, and journal verification. secondRunNoOp is true only when the latest converged run changed nothing. scheduled stays pending until a scheduled run has completed; after a failed scheduled run it gives the time and reason.

Local overlays

canonfig overlay list
canonfig overlay set claude-settings --target ~/.claude/settings.json --key permissions.deny
canonfig overlay remove claude-settings

A Local Overlay claims keys of a config resource's target for this Follower Machine. set needs one resource ID, --target, and at least one --key (repeatable). A claimed key that the profile drops is kept instead of removed. A claimed key that overlaps a key the profile still declares is Human Action Required until you change the overlay. In a key, write \. for a literal dot and \\ for a backslash. See Structured configuration ownership.

Diagnostics

canonfig doctor --no-input --timeout-ms 5000

Runs independent checks of this machine and its connection to the Source Machine. --timeout-ms limits each check (default 5000, at most 300000). See Doctor probes and exit codes.

Managed SSH tunnel

canonfig tunnel start --invitation ./canonfig-invite --ssh-host source.example.net --ssh-user dana --ssh-host-key-file ./source-host-key.pub
canonfig tunnel start
canonfig tunnel status
canonfig tunnel stop
canonfig tunnel stop --forget

Start the Source Machine's endpoint first, then the tunnel.

tunnel start optionValue
--invitation <path>Required on first start.
--ssh-host <host>Required. Hostname, IPv4, or IPv6 address without brackets.
--ssh-user <user>Required.
--ssh-host-key-file <path>Required. The verified SSH public key of the Source Machine's host.
--ssh-port <port>Default 22.
--local-host <host>127.0.0.1 (default) or ::1.
--local-port <port>Default 17342.
--ssh-executable <path>OpenSSH client to run.
--ssh-argument <arg>One extra OpenSSH argument; repeat for each. Options that disable host key checks or add forwards are refused.
--timeout-ms <ms>Default 30000, at most 300000.

The first start saves everything needed to restart in ~/.canonfig/tunnel/tunnel-config.json (mode 0600), so you need not keep the invitation. tunnel start without --invitation restarts from that record and accepts only --timeout-ms; without a record it exits 2 and names the first-start command. To use a specific SSH key, add --ssh-argument -i --ssh-argument ~/.ssh/source_ed25519 to the first start.

tunnel status reports running, down, stopped, or not-configured, and the command to run. When the tunnel does not come up, the error says which of three things happened: SSH exited, SSH never opened the forward, or SSH connected but the Source Machine is not answering.

tunnel stop stops the tunnel and keeps the record, so nothing restarts it. tunnel stop --forget also deletes the record.

Profiles

canonfig profile list
canonfig profile show 7f3c9a2e
canonfig profile select workstation

list shows profiles, show shows one Profile Revision by ID, and select changes which profile this Follower Machine follows.

Agent policy

canonfig agent policy
canonfig agent policy agent-propose
canonfig agent harness
canonfig agent harness codex --executable /usr/local/bin/codex --model gpt-5-codex --allow-path /home/dana/.canonfig --allow-leaf-executable npm --allow-origin https://registry.npmjs.org --allow-capability restart
canonfig agent harness claude --executable /usr/local/bin/claude --model sonnet
canonfig agent harness custom --executable /opt/review-agent/bin/agent --argument --read-only

agent policy without an argument prints the policy. Policies are deterministic-only, agent-propose, and agent-apply.

agent harness without arguments prints the configured harness. To set one:

OptionValue
codex, claude, or customHarness kind.
--executable <path>Required.
--model <name>codex and claude only.
--argument <arg>custom only. Passed as is; repeat for each argument.
--allow-path <path>A path the agent may write. Saved as an absolute path, with ~ as your home directory. Repeatable.
--allow-leaf-executable <name>A program the agent may run. Repeatable. Programs that start other commands are refused.
--bind-secret <ENV=secret-name>Put a stored shared secret in the agent's environment as ENV. Repeatable.
--allow-origin <https-origin>An exact HTTPS origin the agent may reach. Repeatable.
--allow-capability <capability>elevation, login, restart, or reboot. Repeatable.
--maximum-input-bytes <bytes>Default and maximum 1048576.

A secret bound with --bind-secret is read when the harness starts, so a changed value takes effect on the next start. Only the variable name and secret name are saved.

Journaled setup

canonfig setup plan --role source --file ~/.codex/AGENTS.md --mode advanced --intent "prepare the Source Machine"
canonfig setup plan --role follower
canonfig setup approve --approver dana
canonfig setup apply
canonfig setup status
setup plan optionValue
--role <source|follower>Required.
--scope <scope>full (default), cli-only (checks only that the CLI runs), or project-only (also installs accepted tools, creates no identity).
--file <path>A file for tool discovery. Repeatable. It does not choose which files sync.
--mode <simple|advanced>Records the interview depth. Does not change the plan; kept by later plans.
--intent <text>A note recorded with the plan.

setup plan changes nothing. A full plan for the Source Machine fails early when the credential store cannot hold the Source Machine's keys. setup approve approves the current plan, including the exact content of every --file. setup apply runs the next stages; run it again to continue. If a discovery file changed after approval, apply clears the approval without running anything: plan and approve again.

setup status shows the role, scope, mode, intent, discovery files, approval, completed stages, and the reason for each failed or skipped item. The record is ~/.canonfig/setup.json.

Scheduling

canonfig schedule set daily@09:00
canonfig schedule set weekly:Mon,Thu@12:30 --timezone Europe/Paris
canonfig schedule set daily@09:00 --executable /usr/local/bin/canonfig
canonfig schedule set --default
canonfig schedule status
canonfig schedule remove

Calendars are daily@HH:mm or weekly:Day[,Day...]@HH:mm, with days Mon to Sun. Times are in --timezone (an IANA name) or this machine's zone. --executable sets the canonfig the job runs. --default installs the profile's suggested schedule and takes no other option. set prints the zone, the next run, and a warning when the time does not exist on a daylight-saving day; it never starts a run for a time already past today. set refuses while a native override of the job exists. See Sync on a schedule.

Shared secrets

printf '%s' "$GITHUB_TOKEN" | canonfig secrets set github-token
canonfig secrets set github-token
canonfig secrets list
canonfig secrets sync
canonfig secrets remove github-token
canonfig secrets bootstrap
CommandEffect
set <name>Stores a value read from standard input.
listLists names and where each came from. Never values.
remove <name>Deletes a stored secret. Removing a name the Source Machine owns discards that value on this Follower Machine.
syncFetches authorized secrets from the Source Machine. sync --apply already does this.
bootstrapChecks the credential store end to end and reports the storage it selected.

secrets set never takes the value as an argument:

  • Piped input is stored exactly, including a trailing newline; use printf '%s', not echo. If the pipe does not end within 10 seconds, it fails with "secrets set timed out after 10 s waiting for end of input on stdin".
  • At a terminal, it prompts Secret for <name> (input hidden): and drops only the final Enter. Ctrl-D on an empty entry exits 2; Ctrl-C exits 130.
  • The value must be non-empty valid UTF-8 with no NUL byte, at most 16384 bytes: "the secret on stdin exceeds the 16384 byte limit".

A credential-store failure exits 3 with the store's recovery text. See Opt-in shared secrets.

Headless Linux storage

secrets bootstrap runs as you, never uses sudo, and stores only test items it removes again. Install libsecret-tools and a Secret Service provider such as gnome-keyring first. From a background shell, point it at your session bus:

env -i HOME=$HOME PATH=$PATH XDG_RUNTIME_DIR=/run/user/$(id -u) canonfig secrets bootstrap

If /run/user/<uid>/bus does not exist, run sudo loginctl enable-linger <user>. The login keyring must be unlocked, which a password login does. When it cannot prove storage survives a logout without disturbing your session, the result says manual: restart, then run the same command.

On a machine without Secret Service, you can choose unencrypted files with mode 0600 instead. Shared secrets still require a secure store.

CANONFIG_LOCAL_CREDENTIAL_ROOT="$HOME/.canonfig/credentials" canonfig secrets bootstrap

See Run Canonfig unattended.

Upstream skills

canonfig skills track --name code-review --path skills/code-review --source https://github.com/acme/agent-skills --ref v1.4.0 --subdir skills/code-review
canonfig skills list
canonfig skills check --name code-review
canonfig skills update --name code-review --apply
canonfig skills auto --apply --once

Records where a skill came from and updates it from that Git repository.

OptionValue
--root <path>Directory holding the installed skills. Default: the current directory.
--config <path>The list of skill sources, relative to --root. Default .canonfig/skills-sources.json.
--name <id>Skill name. track needs exactly one; check, update, and auto accept several (default: all).
--path, --source, --reftrack only, all required: installed directory, public HTTPS Git URL or local repository, and branch, tag, or commit.
--subdir <path>track only. Skill directory inside the repository. Default ..
--applyupdate and auto only. Without it they preview.
--dry-runupdate and auto only. Preview explicitly.
--interval <seconds>auto only. Default 86400, from 60 to 604800.
--onceauto only. One pass.

A local edit to a skill blocks its update; nothing is overwritten by force. Private and SSH repositories are not supported. Updates copy files and never run them. With a Source Machine, update skills there, then publish.

Harness configuration

canonfig harness init
canonfig harness init --format json
canonfig harness validate
canonfig harness targets
canonfig harness plan --strict
canonfig harness apply
canonfig harness watch --targets codex,claude-code
canonfig harness status
canonfig harness diff
canonfig harness clean --dry-run
canonfig harness doctor
canonfig harness export --source-only --output ./harness-source.zip

Writes each agent tool's native configuration files in a repository from one file, .canonfig/harness.yaml (or harness.json).

CommandEffect
initCreates the configuration file. --format yaml (default) or json.
validateChecks the configuration and each target's translation.
targetsLists supported agent tools and their support level.
planShows which native files would change. --all also lists unchanged files.
apply (alias sync)Writes the plan.
watchApplies stable changes until stopped; stops on a conflict.
statusReports pending changes, conflicts, and diagnostics.
diffPrints the pending changes.
cleanRemoves only files Canonfig wrote and nobody changed.
doctorChecks the selected tools' executables.
exportWrites an archive of the configuration and/or the generated files.
OptionValue
--root <path>Repository root or a directory inside it. Default: the current directory.
--target <id>, --targets <ids>Limit to some targets (repeatable, or comma-separated).
--strictTreat lossy or unsupported translations as errors.
--forceTake ownership of files that conflict. Not allowed with watch.
--dry-runDo not write, for apply, clean, watch, and export.
--interval <seconds>watch only. Default 1, from 1 to 3600.
--output <path>export only. A .zip or .tar.gz path; never overwritten.
--include-source, --source-onlyexport only. Add the configuration, or export only it.

Behavior you can rely on:

  • Apply takes over an existing generated file only when its content already matches. Different text you wrote is a conflict, not overwritten. Line-ending changes alone do not count as edits.
  • Edits to JSON and JSONC files change only the affected properties; comments and formatting elsewhere stay. Invalid JSON is refused, not rewritten.
  • A CLAUDE.md symlink to the repository's AGENTS.md is kept as is. Other symlinks in generated locations are conflicts, even with --force.
  • Setting a target to enabled: false and running an unfiltered apply removes its generated files, except files other targets still need. Apply with --target changes only the selected targets.
  • A skill source symlink that dangles, loops, or points outside the repository fails with SKILL_SOURCE_INVALID.
  • Hook events a target cannot express fail with HOOK_EVENT_UNSUPPORTED under --strict, and warn without it. Claude Code and Factory Droid have no before_agent or after_agent; Droid also has no after_compact or subagent_start.
  • A project with more than one harness configuration file is refused.
  • export does not include credentials, sessions, or files Canonfig does not own. Review literal values and scripts in an archive before you share it.
  • watch runs in the foreground, does not install a service, and does not reload running agent tools.

See Claude Code hooks and Factory Droid hooks for event names, and the harness configuration guide.

Installer bindings

canonfig installer list
canonfig installer set uv --executable /home/dana/.local/bin/uv
canonfig installer set npm --executable /usr/local/bin/node --arg /usr/local/lib/node_modules/npm/bin/npm-cli.js
canonfig installer check npm
canonfig installer remove npm

A binding tells this Follower Machine exactly how to start a package manager. It is local and never comes from the Source Machine. Methods are apt, brew, bun, cargo, npm, pnpm, uv, and winget.

set takes one absolute --executable and at most one absolute --arg entry point, checks them by running --version, and saves the binding in ~/.canonfig/installers/<method>.json. A binding cannot add options, environment variables, or a shell. check runs that check again. remove records that the method is not allowed; installs with it then need Human Action Required instead of using PATH.

On Windows, bind npm to node.exe plus npm-cli.js; see Windows package managers.

JSON envelope

{
  "schema": "canonfig.cli/v1",
  "command": "status",
  "status": "success",
  "exitCode": 0,
  "message": "status completed",
  "data": {}
}

Successes go to standard output and failures to standard error. A usage error with --json is an envelope with status "error" and exitCode 2. Every command group, including secrets, uses this schema. Secret-like fields are removed from data before printing. With CANONFIG_DEBUG=1, an internal failure adds data.diagnostic; review it before you share it, because it can contain paths.

On this page