Harnesses
A harness is the coding agent itself. Daktyl seats each one the same way and shows it on the phone the same way: same chat, same status, same calls, same approvals. There is no first-class harness.
Built in
These adapters ship inside the daemon. The table is read out of
daktyl-cli/src/daemon/adapters/*.mjs when this page is generated, so it cannot drift
from the code.
| Harness | Shape | What that means |
|---|---|---|
antigravity | stream | one long-lived process per seat; a turn is a line in and the reply streamed out |
claude-code | pane | drives a real terminal session you can attach to |
claude-headless | turn | one process per turn; the daemon feeds it prompts and reads the reply |
claude-sdk | sdk | an in-process SDK session; the model switches live |
codex | turn | one process per turn; the daemon feeds it prompts and reads the reply |
cursor | acp | speaks the Agent Client Protocol over a pipe |
opencode | acp | speaks the Agent Client Protocol over a pipe |
Adding one is configuration
Any harness that speaks the Agent Client Protocol is a block in
~/.daktyl/config.json — no new code, no release. Hermes, Copilot and opencode are seated
exactly this way on live hosts today:
"adapters": {
"hermes": { "kind": "acp", "argv": ["hermes", "acp"] }
}
A name the build does not know is refused by name — never silently mapped to another harness.
Setting one up
Install the harness and sign in to it on the machine; the daemon finds it and seats it. Daktyl never installs a harness, signs in to one or holds its keys. The table is read out of the adapters: the binary each one looks for, the variable that points it somewhere else, and the hint the daemon gives when it cannot find it (where it gives one).
| Harness | Looks for | Override | When it is missing |
|---|---|---|---|
antigravity | agy | DAKTYL_AGY_BIN | install Antigravity, or set DAKTYL_AGY_BIN to its path |
claude-code | claude | DAKTYL_CLAUDE_BIN | |
claude-headless | claude | DAKTYL_CLAUDE_BIN | install Claude Code, or set DAKTYL_CLAUDE_BIN to its path |
claude-sdk | claude | DAKTYL_CLAUDE_BIN | |
codex | codex | DAKTYL_CODEX_BIN | install the Codex CLI, or set DAKTYL_CODEX_BIN to its path |
cursor | cursor-agent | DAKTYL_CURSOR_BIN | install the Cursor CLI (cursor-agent), or set DAKTYL_CURSOR_BIN to its path |
opencode | opencode | install opencode, or set its argv in adapters.opencode |
With one harness installed, an agent started without naming one uses it. With several, name it:
daktyl create --harness codex.
Claude Code (claude-code, claude-sdk, claude-headless)
One claude binary, three ways of driving it; an unnamed start uses the terminal one,
claude-code. Install Claude Code and run claude once in a terminal to sign in.
The terminal harness runs inside tmux, so install tmux as well (brew install tmux, or
sudo apt-get install -y tmux); daktyl attach opens a running agent's session. It
also needs the channel plugin the installer puts in place — without it the harness is reported as not
present rather than launched deaf.
On macOS, claude-sdk signs in through the login Keychain, so the daemon has to run in
your login session. Where it cannot reach the Keychain it refuses the seat and says so.
Codex
Install the Codex CLI and sign in with codex login (codex login status
tells you whether you are). Each turn is one codex exec in the project directory. The
Daktyl tools are passed to every turn on the command line, so nothing needs adding to
~/.codex/config.toml. A signed-out Codex shows as blocked on sign-in, not as a crash.
Cursor
Install the Cursor CLI (cursor-agent) and sign in with cursor-agent login.
On a machine with no browser, NO_OPEN_BROWSER=1 cursor-agent login prints a link you can
approve on your phone. The CLI's sign-in is separate from the Cursor editor's. Daktyl runs it as
cursor-agent acp; a Cursor seat stays on the model it started with (no live model
switch) and has no compact.
Antigravity
Install Antigravity so that agy is on the path, and sign in to it once. On macOS its
credentials live in the login Keychain, so the daemon has to run in your login session; where it cannot
reach the Keychain the harness is reported as not probed, with the reason. One agy process
stays up per seat between turns. Antigravity accepts a conversation id it does not know and quietly
starts a new conversation, so Daktyl checks the id every reply carries against the one it asked for,
and a resume that forked is an error rather than a fresh conversation passed off as the old one.
opencode
Built in, run as opencode acp. Give opencode a provider itself (its own sign-in or a
provider key). The models a seat may switch between are the ones declared in the
opencode.json of the directory named by adapters.opencode.cwd
(provider.<name>.models, plus its model); opencode's own catalog also
lists models merged in from elsewhere that may never have been pulled, so only the declared ones are
offered. Effort is written into that file as the model's reasoningEffort and applies on the
next restart. An agent started in a registered project runs there; otherwise it runs in that
directory.
"adapters": {
"opencode": { "cwd": "/home/you/work" }
}
Hermes
Seated by configuration, with the block shown above. Set its model and provider in Hermes itself.
It has no effort control over ACP. When Hermes declares no model option, the block's own
model is what the phone shows.
Copilot (advanced setup)
The GitHub Copilot CLI speaks ACP and is seated by configuration too
("copilot": { "kind": "acp", "argv": ["copilot", "--acp"] }), after you sign in to it.
It ignores the MCP servers an ACP client declares, so a Copilot seat chats but has no Daktyl tools
unless you add the Daktyl server to ~/.copilot/mcp-config.json yourself.
Capabilities
Harnesses differ, and Daktyl says so rather than pretending. Each seat reports what it can do, and
the app gates its controls on that: a button you can see is a button that works. The vocabulary is
frozen — an adapter may claim native (the harness does it), emulated
(Daktyl does it around the harness) or unsupported; a capability the seat does not
mention is unknown, not no.
| Capability | What it gates |
|---|---|
status | live state on the phone (thinking, running, idle) |
context | the context ring and token telemetry |
model | switching the model from the app |
effort | reasoning-effort level |
permission_mode | the tool-approval mode picker |
thinking | extended thinking on or off |
compact | compacting the conversation |
interrupt | stopping a turn mid-flight |
plan | plan mode |
approvals | tool approvals reaching your lock screen |
resume | resuming the same conversation after a restart |
call | joining a voice call |
steer | sending a message while a turn is running |
project | launching inside a registered project directory |
tools | per-tool-call activity in the timeline |
diffs | working-tree changes as a diff on the phone |
restart_free_model_switch | whether a model switch keeps the process alive |
Choosing one
daktyl create --harness codex --model gpt-5 --project my-repo
daktyl agent ls # what is running here, panes and seats
daktyl fleet # everything, everywhere, with model and context