# custom harnesses
Any agent CLI beyond the built-ins can be registered by dropping a harness.json next to the state file (~/Library/Application Support/hrdx/ on macOS, $XDG_CONFIG_HOME/hrdx/ on Linux). Registered harnesses appear everywhere the built-ins do: in the pickers, in agent cycling, in the sidebar agents list, and in settings.
[
{
"kind": "aider",
"binary": "aider",
"args": ["--no-auto-commits"],
"resume": ["--restore-chat-history"],
"busy": "Waiting for the model"
},
{ "kind": "goose" }
]| field | purpose |
|---|---|
| kind | identifier used in pickers and pane names (required) |
| binary | executable to launch (default: same as kind) |
| args | extra arguments passed on every launch |
| resume | arguments that resume the latest session on restore |
| resume_first | put the resume args before args (for subcommands) |
| busy | substring visible only while working, drives the spinner and finish sound; empty: braille spinner detection |
## remote and container panes
Every pane is a real PTY, so a harness can just as well be an ssh, docker, or kubectl client running an agent at the target:
[
{
"kind": "remote-codex",
"binary": "ssh",
"args": ["-tt", "user@host", "cd /path/to/project && exec codex"]
},
{
"kind": "docker-codex",
"binary": "docker",
"args": ["exec", "-it", "-w", "/workspace", "container-name", "codex"]
}
]Wrapper scripts are useful when the host, container, namespace, or working directory is dynamic. Set the harness binary to the wrapper path and put fixed parameters in args.