Canonfig
How-to Guides

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 harness fails 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 for claude, or your own program for custom.
  • The agent policy and harness belong to this Follower Machine only. canonfig follower enroll --replace resets them: the policy returns to deterministic-only and the harness is removed.

Choose an agent policy

PolicyDuring sync --apply
deterministic-only (default)No agent runs. Each Agent Task stops the run with Human Action Required.
agent-proposeThe 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-applyThe 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-propose

Start 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.org

For Codex, use codex and its path instead of claude.

  • --model picks the model. Canonfig passes it to the CLI's own --model option. 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, codex and claude take 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 harness

Set 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.org

A 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:

  1. Read the Agent Task from standard input. It is a JSON document whose schema is canonfig.agent-task/v1, with the desired outcome, the evidence Canonfig observed, the paths, programs, and origins allowed, and how the result will be checked.

  2. 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.

OptionWhat 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

MessageCauseFix
"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.

On this page