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.

Migrating custom templates and wrappers

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 sonnet are overridable: they are present by default but absent if you supply agent_args without them.
  • --output-format stream-json and --verbose are required: Cloche injects them even if your agent_args omits them. --output-format stream-json is necessary because the prompt adapter parses Claude’s streaming JSON output to extract results and token usage. --verbose is 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 claude once 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-code via npm.
  • Authentication errors — Run claude on 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 runs chown -R agent:agent on 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/codex via npm.
  • Authentication errors — Verify CLOCHE_EXTRA_ENV includes a valid OPENAI_API_KEY and that the daemon was started after the variable was set.
  • No output — Ensure the installed Codex CLI version supports reading prompts from stdin.