What
Adds a Coddy worker backend (type: coddy) for local mode (coddy-agent).
Coddy's one-shot mode prints only the final answer to stdout (coddy -p "<prompt>"), which matches the dispatcher contract (results are read from stdout), so the integration is a thin driver and needs no plumbing changes.
Why
Local mode currently supports claude / codex / pi. Coddy is a terminal coding agent that many people already have installed and configured, and like the other local backends it needs no API keys in dispatch.yaml.
How
CoddyDriver.build_execute emits:
coddy -no-stdin -ephemeral -permission-mode bypass [-model <CODDY_MODEL>] -p <prompt>-no-stdin- an inherited stdin must never block a one-shot run (nohup, systemd, CI runners that feed the job script on stdin);-permission-mode bypass- local mode has no TTY that could approve tool calls;-ephemeral- one throwaway session per task, nothing accumulates in~/.coddy;CODDY_MODEL(optional env) - a model id already configured in coddy's ownconfig.yaml; no keys or base URLs are injected.
supports_conclude() returns false: coddy resumes by workspace ("the most recent session in this folder"), not by session id, so a conclude run could attach to another task's session in the same project directory. Tasks run as ephemeral one-shots and the optional conclude fallback stays off.
The driver is registered in LOCAL_DRIVERS only, because the binary is not in the worker image. A coddy worker under runtime.execution: container now fails fast with an explicit error instead of a key lookup error at exec time.
Files
cairn/src/cairn/dispatcher/workers/adapters/coddy.py(new driver).../workers/adapters/__init__.py,.../workers/registry.py(registration).../dispatcher/config.py(WorkerType,WORKER_ENV_KEYS, local-only guard)cairn/tests/test_config_and_adapters.py(4 tests)README.md,dispatch.local.example.yaml(docs)
Testing
uv run --project cairn --group dev pytest- 102 passed, including 4 new tests (argv shape,CODDY_MODELoverride, no-conclude contract, local-only config guard)- live end-to-end on Linux with coddy 1.3.62 and llama.cpp (
n_ctx=262144):- one
exploreturn: renderedprompts/default/explore.md, graph snapshot in a file, the model returned a single raw JSON payload accepted byparse_json_output+validate_explore_payload; - full project with
bootstrap_enabled: false:reasonsolved it and the project completed (202 s);
- one
cairn dispatch --config dispatch.yaml --startup-healthcheck-onlydetects the CLI on PATH:[+] coddy /home/.../coddy.
Notes
docs/specs/dispatcher-design.md lists only claudecode / codex / mock and has no pi section either, so I left it untouched to keep this diff focused. Happy to sync the spec in a follow-up if that is preferred.