Agent Setup
Cloche supports any agent that can read a prompt from stdin and print a result marker to stdout. Agent steps use a nonced marker, CLOCHE_RESULT:{{ $result_nonce }}:<name> — Cloche substitutes the per-step nonce into the prompt it assembles, and also exports it to the agent process as CLOCHE_RESULT_NONCE for custom agent_command wrapper scripts that construct their own marker. The nonce exists because a free-form coding agent’s transcript can reproduce the literal string CLOCHE_RESULT:success incidentally — while grepping code, editing test fixtures, or discussing the protocol itself. Framing the marker with a per-step random nonce means only a line the agent deliberately copied from its own instructions counts as a result; quoted or incidental mentions elsewhere are left alone as ordinary text. See the Result Protocol for the full rules.
Custom prompt templates or agent_command scripts that hardcode CLOCHE_RESULT:<name> must switch to the nonced form: CLOCHE_RESULT:{{ $result_nonce }}:<name> in a prompt template, or CLOCHE_RESULT:$CLOCHE_RESULT_NONCE:<name> in a wrapper script. The nonce is generated once per step and reused across retries and resumes. Poll and skip steps are author-controlled and keep the bare form.
Built-in Agents
Cloche has a concept of known agents — agent commands it understands natively. Known agents receive default arguments automatically, and some arguments are required and will always be injected regardless of agent_args. Unknown agents (e.g. codex) receive no default arguments; the prompt is passed on stdin and the command is invoked as-is.
Known agents
| Command | Default args (overridable) | Required args (always injected) |
|---|---|---|
claude |
-p --dangerously-skip-permissions --model sonnet |
--output-format stream-json --verbose |
opencode |
run --format json --dangerously-skip-permissions |
--format json |
How agent_args interacts with defaults
When agent_args is not set, the agent receives its full default argument list.
When agent_args is set, it replaces the default args entirely — but required args are always appended if not already present. You cannot remove a required arg.
For claude, this means:
-p,--dangerously-skip-permissions, and--model sonnetare overridable: they are present by default but absent if you supplyagent_argswithout them.--output-format stream-jsonand--verboseare required: Cloche injects them even if youragent_argsomits them.--output-format stream-jsonis necessary because the prompt adapter parses Claude’s streaming JSON output to extract results and token usage.--verboseis required for that stream to include the result event.
Overriding arguments
Use agent_args to replace the default args. Required args are always present, so you do not need to include them.
step implement {
prompt = file(".cloche/prompts/implement.md")
agent_args = "-p --dangerously-skip-permissions --model claude-opus-4-5"
results = [success, fail]
}
Note that -p and --dangerously-skip-permissions must be included explicitly when using agent_args, since they are overridable defaults and will not be injected automatically.
Named agent declarations
Rather than repeating agent_args on every step, declare named agents at the workflow level and reference them from steps:
workflow "develop" {
agent haiku_claude {
command = "claude"
args = "-p --dangerously-skip-permissions --model claude-haiku-4-5"
}
agent opus_claude {
command = "claude"
args = "-p --dangerously-skip-permissions --model claude-opus-4-6"
}
step commit {
prompt = file(".cloche/prompts/commit.md")
agent = haiku_claude
results = [success, fail]
}
step implement {
prompt = file(".cloche/prompts/implement.md")
agent = opus_claude
results = [success, fail]
}
implement:success -> commit
implement:fail -> abort
commit:success -> done
commit:fail -> abort
}
Required args (--output-format stream-json and --verbose) are still injected automatically — you do not need to include them in args. Step-level agent_command and agent_args override the agent declaration.
opencode
opencode is also a known agent. Set agent_command = "opencode" (or pass --agent-command opencode at the CLI). The default invocation is:
opencode run --format json --dangerously-skip-permissions
The prompt is passed on stdin. Its one required arg, --format json, is always injected if your agent_args omits it, so structured events are emitted on stdout for the streaming parser to extract results and token usage.
Unknown agents
Any agent_command value not in the known agents table is treated as unknown. Unknown agents receive no default arguments, the prompt on stdin, and agent_args is passed through verbatim.
Fallback Chains
Specify multiple agent commands as a comma-separated list. Cloche tries each in order until one succeeds:
agent_command = "claude,gemini,codex"
Fallback behavior:
| Outcome | Action |
|---|---|
| Command not found / failed to start | Try next command in the list. |
Exit 0 with substantive output but no CLOCHE_RESULT marker (and no error_during_execution report) |
One recovery turn first: resume the same session (--resume <session-id> for claude, -c otherwise) and ask it to print only the marker. If the recovery turn produces one, use that result — no fallback. Otherwise, try next command in the list. |
Exit 0 or non-zero without a CLOCHE_RESULT marker (including no output at all, or an error_during_execution report) |
Try next command in the list. |
Exit 0 or non-zero with a CLOCHE_RESULT marker |
Use that result — no fallback. |
| All commands fail to start | Step returns an error. |
| Last command crashes without marker | Step returns fail. |
A bare exit 0 is not a success for agent steps. An agent that exits 0 without printing a marker cannot be trusted to have finished, so it gets the recovery turn (if it produced output) and then falls through to the next command — or to fail if it was the last one. Only a marker counts.
Claude Code
Prerequisites
- Claude Code installed on the host machine:
npm install -g @anthropic-ai/claude-code - An active Claude Code session on the host. Run
claudeonce interactively to authenticate before starting the daemon.
How Authentication Works
Cloche copies three specific files from your host’s ~/.claude/ directory (.credentials.json, settings.json, settings.local.json) into each container at /home/agent/.claude/. For interactive containers, ~/.claude.json is also copied to /home/agent/.claude.json; it is skipped for autonomous (non-interactive) runs. The files are copied — not bind-mounted — so each container gets its own isolated credential copy, avoiding concurrent write conflicts when multiple runs execute in parallel. Cloche runs chown -R agent:agent on the copied auth files at container startup so the unprivileged agent user can read them.
Dockerfile
FROM cloche-base:latest
USER root
# Install Node.js (required for Claude Code)
RUN apt-get update \
&& apt-get install -y --no-install-recommends nodejs npm \
&& rm -rf /var/lib/apt/lists/*
# Install Claude Code
RUN npm install -g @anthropic-ai/claude-code
# Add your project's build dependencies here
# RUN apt-get install -y ...
USER agent
Workflow Config
Claude is the default agent — no explicit configuration is required. The full default invocation is:
claude -p --output-format stream-json --verbose --dangerously-skip-permissions --model sonnet
Override with agent_args in your workflow or step config if needed. See overriding arguments above for how defaults and required args interact.
API Key Alternative
Set ANTHROPIC_API_KEY in the daemon’s environment and it will be passed into containers automatically — no session files required.
Troubleshooting
- Claude Code not found in container — Ensure the Dockerfile installs
@anthropic-ai/claude-codevia npm. - Authentication errors — Run
claudeon the host to ensure the session is active before starting the daemon. - Permission errors on
~/.claude— Check that the Dockerfile does not override the container entrypoint, which handles credential injection and runschown -R agent:agenton the auth files.
Codex
Prerequisites
An OpenAI API key with Codex access.
How Authentication Works
Codex authenticates via API key. Pass it to containers using CLOCHE_EXTRA_ENV:
export CLOCHE_EXTRA_ENV="OPENAI_API_KEY=sk-..."
cloched &
Dockerfile
FROM cloche-base:latest
USER root
RUN apt-get update \
&& apt-get install -y --no-install-recommends nodejs npm \
&& rm -rf /var/lib/apt/lists/*
RUN npm install -g @openai/codex
USER agent
Workflow Config
Set agent_command = "codex" in your workflow or config.toml. Codex is not a known agent, so it receives the prompt on stdin with no default arguments. Add agent_args if your version requires explicit flags:
agent_command = "codex"
agent_args = "--full-auto"
Token Usage Capture
Codex does not emit token usage in its standard output. Use usage_command to capture it separately. The command must output JSON with input_tokens and output_tokens fields:
{"input_tokens": 1234, "output_tokens": 567}
Configure via config.toml (applies to all Codex steps):
[agents.codex]
usage_command = "codex usage --last --json"
Or per-step in the workflow file:
step implement {
...
usage_command = "codex usage --last --json"
}
Step-level usage_command takes precedence over the [agents.codex] config.toml value.
The agent_name recorded alongside each step’s usage is the resolved agent command — codex here, or an alias’s expanded command when the step used agent = <identifier>, never the alias itself. Rows where the agent cannot be determined (usage recorded by an older cloche-agent build, or a workflow file no longer on disk) are labeled unattributed rather than left blank.
Troubleshooting
- Codex not found — Ensure the Dockerfile installs
@openai/codexvia npm. - Authentication errors — Verify
CLOCHE_EXTRA_ENVincludes a validOPENAI_API_KEYand that the daemon was started after the variable was set. - No output — Ensure the installed Codex CLI version supports reading prompts from stdin.