Let a Configuration Agent resolve work
Choose whether a Configuration Agent may propose or apply work on a Follower Machine, and set up the codex, claude, or custom agent harness and its limits.
Canonfig applies every Profile Resource it has a fixed action for. Work it
cannot do on its own becomes an Agent Task. For example, a tool resource
that has no Installation Recipe for the Follower Machine's platform but
declares an agentInstall block becomes an Agent Task there. By default, an
Agent Task stops the run with Human Action Required. You can instead let a
Configuration Agent propose a fix, or apply it within limits you set.
Before you start
- Run every command on the Follower Machine, after it is enrolled. On a
machine that is not enrolled,
canonfig agent harnessfails with "follower synchronization configuration is not enrolled". - Install the agent CLI on the Follower Machine and sign in to it: Codex CLI
for
codex, Claude Code forclaude, or your own program forcustom. - The agent policy and harness belong to this Follower Machine only.
canonfig follower enroll --replaceresets them: the policy returns todeterministic-onlyand the harness is removed.
Choose an agent policy
| Policy | During sync --apply |
|---|---|
deterministic-only (default) | No agent runs. Each Agent Task stops the run with Human Action Required. |
agent-propose | The agent runs and returns a proposal. Canonfig checks and records it, runs none of its actions, and stops at that task with Human Action Required. |
agent-apply | The agent runs and returns a proposal. Canonfig runs only the actions inside the limits, then checks the result itself. |
With agent-propose or agent-apply, sync --plan also runs the agent and
shows its proposal under "agent resolutions" without running anything. Use
that to see what the agent would do before you allow it.
Check the policy, then change it:
canonfig agent policy
canonfig agent policy agent-proposeStart with agent-propose. Move to agent-apply only after you have reviewed
proposals and the limits below.
Scheduled runs never wait for input. They follow the same policy, so with
agent-apply the agent can act while you are away.
Set up Codex or Claude Code
Point Canonfig at the agent CLI and say what it may touch. Use the absolute
path that command -v claude or command -v codex prints:
canonfig agent harness claude --executable /home/alex/.local/bin/claude --model opus --allow-path /home/alex/.local/share/canonfig/tools --allow-leaf-executable npm --allow-origin https://registry.npmjs.orgFor Codex, use codex and its path instead of claude.
--modelpicks the model. Canonfig passes it to the CLI's own--modeloption. Leave it out to use the agent's default model. The name cannot contain spaces or start with-.- Canonfig always starts the agent in read-only mode: Codex with a read-only
sandbox, Claude Code in plan mode. The agent only proposes; Canonfig runs
the actions. For this reason,
codexandclaudetake no other arguments. - The agent does not need to run inside a Git repository.
Each canonfig agent harness command replaces the whole harness setting, so
repeat every option you want to keep. To see the setting:
canonfig agent harnessSet up another agent
The custom harness runs any program you name, with exactly the arguments you
give, one --argument per argument, and no shell:
canonfig agent harness custom --executable /home/alex/bin/canonfig-agent --argument propose --argument --json --allow-path /home/alex/.local/share/canonfig/tools --allow-leaf-executable npm --allow-origin https://registry.npmjs.orgA value after --argument goes to your program, even when it looks like a
Canonfig option, as --json does here. custom does not accept --model;
pass the model in your program's own arguments.
Your program must:
-
Read the Agent Task from standard input. It is a JSON document whose
schemaiscanonfig.agent-task/v1, with the desired outcome, the evidence Canonfig observed, the paths, programs, and origins allowed, and how the result will be checked. -
Print one JSON proposal to standard output, and nothing else:
{ "summary": "Install review-cli 2.3.1 with npm", "actions": [ { "kind": "process", "executable": "npm", "arguments": ["install", "--prefix", "/home/alex/.local/share/canonfig/tools/review-cli", "review-cli@2.3.1"], "paths": ["/home/alex/.local/share/canonfig/tools/review-cli"], "origins": ["https://registry.npmjs.org"], "capabilities": [] } ] }Each action may also set
workingDirectory. Canonfig refuses any output that is not a proposal in this form.
Canonfig cannot make a custom agent read-only
Canonfig runs your program as you configured it and cannot stop it from changing files itself. Start it in its own read-only or plan mode through its arguments. Canonfig still checks every proposed action against the limits before it runs anything.
Set the limits
Repeat each option to add more entries.
| Option | What it allows |
|---|---|
--allow-path <path> | Paths an action may write, including everything below them. Canonfig stores each one as an absolute path: ~ is your home directory on this Follower Machine, and a relative path starts from the working directory. |
--allow-leaf-executable <name> | A program an action may run directly, such as npm. |
--allow-origin <https-origin> | A download source. It must be an exact HTTPS origin with no path, such as https://registry.npmjs.org. |
--allow-capability <capability> | elevation, login, restart, or reboot. |
--bind-secret <ENV=secret-name> | Puts the shared secret secret-name into the agent's environment as ENV, for example --bind-secret OPENAI_API_KEY=openai-key. Store the secret with canonfig secrets set. |
--maximum-input-bytes <bytes> | The largest Agent Task Canonfig sends the agent. The default and maximum is 1048576 (1 MiB). |
An agent gets only what both the Agent Task and these limits allow. A limit
never widens a task: every Agent Task Canonfig creates forbids elevation,
login, restart, and reboot, so --allow-capability does not give an
agent those rights for them.
An Agent Task's paths come from the tool's agentInstall.paths in the
profile. There, too, ~ is the Follower Machine's home directory, so
--allow-path ~/.local/bin covers an agentInstall path of
~/.local/bin/review-cli. Paths match whole directory names: ~/.local/bin
does not cover ~/.local/bin2. On Windows the match ignores case.
Canonfig refuses programs that can start other commands, because a path
allowlist cannot limit what they start. Examples are xargs, env, ssh,
npx, make, perl, git, find, tar, and sudo. Naming one fails at
setup:
xargs launches nested commands that cannot be bounded by an execution model; remove it from the agent harness allowlist
A proposed action that runs such a program, or any program the limits do not allow, stops with Human Action Required.
What happens during a run
For each Agent Task, Canonfig sends the task to the agent, checks the proposal
against the limits, and with agent-apply runs each action directly, without
a shell. Each Agent Task has a 300-second time limit and a 64 KiB output
limit. Canonfig removes the values of bound secrets from what it records.
The task becomes Human Action Required (exit 3), and the run stops there, when:
- the proposal asks for something outside the limits;
- the agent declines, times out, or prints more than the output limit;
- the agent's output is not a proposal;
- with
agent-apply, the agent's actions did not complete.
Resources applied before that task stay applied. Later ones wait until you
resolve the task and run canonfig sync --apply again.
With agent-apply, Canonfig then checks the resource itself with the verify
method the profile declares. The agent's own report never counts. If the
check fails, the run fails with "verification failed for agent task
<resource>" (exit 7). See
Recover from a failed or blocked sync.
If something fails
| Message | Cause | Fix |
|---|---|---|
"Bounded agent task requires an apply-authorized harness: <task>" (in the sync result, exit 3) | The policy is deterministic-only, or it is agent-apply and no harness is set. | Do the work yourself, or choose a policy and set a harness. |
"Agent proposal requires human review: <summary>" (in the sync result, exit 3) | The policy is agent-propose. | Review the proposal under "agent resolutions" and do the work yourself, or switch to agent-apply. |
"Agent harness is not configured for <task>" (in the sync result, exit 3) | The policy is agent-propose, or you ran sync --plan, and no harness is set. | Set a harness, or run canonfig agent policy deterministic-only. |
"Configured agent harness could not safely resolve the task: <reason>" (in the sync result, exit 3) | With agent-propose or sync --plan: the proposal broke the limits, the agent timed out or printed too much, or its output was not a proposal. The reason says which. | Fix what the reason names, for example widen a limit you intend to allow, or do the work yourself. |
"Agent did not apply the requested task: <task>" (in the sync result, exit 3) | With agent-apply: the proposal was refused, or its actions did not complete. | Review the agent resolution in the sync result, then do the work yourself or adjust the limits. |
"verification failed for agent task <resource>" (exit 7) | The actions ran, but the resource does not pass its verify check. | See Recover from a failed or blocked sync. |
"configured agent policy requires an adapter" (doctor, exit 2) | The policy is agent-propose or agent-apply and no harness is set. | Set a harness with canonfig agent harness. |
"configured agent adapter executable is unavailable" (doctor, exit 2) | The --executable path does not exist on this machine. | Set the harness again with the correct path. |
| "agent harness is not configured" (exit 2) | canonfig agent harness has nothing to show. | Set a harness. |
| "--model applies to codex and claude; pass a custom harness's model with --argument" (exit 2) | --model was given to a custom harness. | Remove --model and pass the model in --argument. |
| "--argument applies only to the custom harness; codex and claude get Canonfig's read-only flags" (exit 2) | --argument was given to a codex or claude harness. | Remove --argument. |
| "Agent harness origin must be an exact HTTPS origin: https://registry.npmjs.org/" (exit 2) | The origin has a path, here a trailing /. | Remove the path. |
| "Invalid agent harness maximum input bytes: 2000000" (exit 2) | The value is above the maximum. | Use a value from 1 to 1048576. |
| "Missing required option: --executable" (exit 2) | --executable is required. | Add --executable with the agent's absolute path. |
| "Invalid secret binding; expected ENV_NAME=shared-secret-name" (exit 2) | --bind-secret is not written as ENV=secret-name. | Write it as OPENAI_API_KEY=openai-key. |
| "Invalid agent harness configuration" (exit 2) | The harness kind is not codex, claude, or custom, a --model name contains a space, or --allow-capability is not elevation, login, restart, or reboot. | Correct the option. |
Recover from a failed or blocked sync
Find the message you see, fix its cause, and bring a Follower Machine back to Convergence without losing changes made on it.
How Canonfig works
Understand what the Source Machine and Follower Machines own, what syncs and when, what stays local, what one run can roll back, and where Canonfig keeps its files.