Rove

Engines

An engine is the AI coding CLI a task runs on — claude, codex, copilot, kimi, or one you register yourself. Rove runs the real interactive CLI inside the task's terminal session.

Managed task = one git worktree + one branch + one or more terminal tabs

A Task can own several terminal tabs. Each engine tab has its own PTY process and conversation, but opening another engine or shell tab does not create another worktree: ordinary sibling tabs use the same Task directory. Two agents in sibling tabs can therefore edit each other's work; create another task when you need git-level isolation and a separate branch.

Which engines are supported

EngineIdAccount detectActivity badgeHistoryModel picker
Claude Codeclaude
Codexcodex✓ (after you trust hooks)✓ + effort levels
GitHub Copilotcopilot✓ (screen-based)
Kimi Codekimihandoff only
Gemini CLI, OpenCode, Cursor Agent, Grok CLI, Droid, Ampcontribbinary only✓ (screen-based)
Anything you registercustombinary only

Claude Code is the default and the most complete: its quota probe drives rate-limit auto-resume and the Settings usage dashboard.

Contrib engines are launch + badge only. Rove ships a catalog of well-known coding CLIs (gemini, opencode, cursor, grok, droid, amp) so they appear in the engine selector whenever the binary is on your PATH — with a proper name, a launch command, and screen-based activity badges. Settings → Engines lists them (and your own registered engines) with their binary discovery, but that is all detection can answer for them — no login state, history, or model picker; those need a real adapter, which is what promotes an engine to built-in.

Kimi is partial. Rove finds the binary, reads its login state, and can locate each session's transcript — enough to watch it for activity and to hand the conversation to another engine. It still doesn't parse that transcript (the wire format is unverified), so auto-title keeps the placeholder and rove api read-output reports engine_unsupported rather than guessing.

Picking an engine

Per task, at creation time, or with v in the sidebar. The default for new tasks comes from Settings → Engines (defaultVendor), and Rove remembers the last engine you used per project. From a script it is rove api add --command <engine-or-command-line> — see engine presets and protocols.

Engines whose CLI isn't installed are hidden from the new-task dialog. Custom engines always show — you added it, so Rove assumes you meant it.

Reasoning effort

Codex accepts none, low, medium, high, xhigh, passed as -c model_reasoning_effort=<level>. Other engines have no effort flag Rove can drive; a selected effort is ignored there rather than passed through.

Workspace trust

Claude, Codex, and Kimi each gate a first launch in a never-seen directory behind a trust dialog — and every task worktree is such a directory, so a hosted session can't answer it (Kimi's dialog even exits the process when a pasted first message lands on "Don't trust"). Before spawning an engine into a Rove-created worktree, Rove writes the vendor's own trust record for that path — ~/.claude.json projects[<path>].hasTrustDialogAccepted, ~/.codex/config.toml [projects."<path>"] trust_level = "trusted", or ~/.kimi-code/workspace-trust/ — merging into existing entries, never clobbering. This only ever fires for worktrees Rove itself created from a repo you already work in; your own directories are untouched.

Custom launch commands

Override any engine's launch command in Settings → Engines, or by hand in state.json:

{ "engineCommand.claude": "claude --model opus" }

Quotes are honored, so claude --append-system-prompt "be terse" works. For Claude, Rove appends its own --session-id so the tab stays resumable — but if your override already pins the conversation (--session-id, --resume, --continue, --from-pr), Rove leaves it alone.

If an engine exits non-zero, the terminal stays open with a banner pointing at Settings → Engines, and drops you into a shell.

Activity badges

The sidebar shows what each session is doing: working, done, or needs input. There's nothing to configure — Rove reads the engine's own hook events, falling back to its transcript when hooks aren't available.

One thing worth knowing: the depth of the badge depends on the engine. Claude, codex, and kimi report through hooks — the full working / done / needs-input vocabulary, sub-second. Engines without hooks or a readable transcript (copilot today) fall back to screen reading: Rove classifies the visible terminal against engine-declared rules, which still distinguishes working from waiting-on-you but can't see a completed turn the way a transcript marker can. Rove labels the gap honestly rather than guessing.

Codex won't run Rove's hooks until you trust them once via /hooks, so Codex badges stay dark until you approve. That's by design — Rove writes the hook definition but never bypasses the trust prompt for you.

Mechanics: design/engine-internals.md.

Resuming and forking

Resume. A Claude tab whose process is gone (reboot, unarchive) relaunches into the same conversation instead of a blank one. A tab that never sent a first message isn't resumed — there's no transcript yet. Codex, Copilot, Kimi, and custom engines can't take a caller-set session id, so their tabs relaunch fresh.

ctrl+a y opens the resume picker for the active task.

Continue in a new tab. ctrl+a c opens the continuation flow in the same worktree. What happens depends on the source and destination engines:

Same engine → a native fork only when that CLI can actually branch a conversation. The two resulting tabs keep the source context and then diverge:

EngineNative fork?How
claude--resume <src> --fork-session
codexcodex fork <src>
copilotstarts a fresh Copilot session with a transcript handoff
kimistarts a fresh Kimi session with a transcript handoff
customrefused; Rove doesn't know its session store

Copilot's --resume and Kimi's -S reopen rather than branch, which would put two live processes on one transcript. Rove therefore uses the same transcript handoff as a cross-engine continuation: the new tab is a fresh conversation that reads where the previous one stopped. A custom engine without a known session store is refused instead of silently opening a blank continuation.

Different built-in engine → a handoff. This is the move that saves you when you hit a usage limit mid-task. The new engine starts fresh with a first prompt that points it at the old session's transcript and asks it to state where the previous one stopped — that sentence is how you check the handoff landed.

Handoffs work in every direction between the four built-ins — the receiving agent is handed the previous transcript's path and reads it in whatever format it finds, so no format ever has to be converted. Only a custom engine can't be a handoff source (Rove doesn't know its session store); that case is refused with a reason. A handoff to a custom engine works fine.

Custom engines

Any CLI can be an engine. A custom engine is a named preset: an id, a launch command, an optional display name, and — declared once at registration — the protocol Rove speaks to it. Settings → Engines → + Add engine asks for each. Or by hand:

{
  "customEngineIds": ["aider"],
  "engineCommand.aider": "aider --model sonnet",
  "engineName.aider": "Aider",
  "engineProtocol.aider": "claude"
}

Being in customEngineIds is the registration.

engineProtocol.<id> is optional and says "talk to my binary the way you talk to claude" — set it when your CLI is a wrapper around a built-in (a different binary name, a fixed set of flags, a company shim) so the transcript reader, workspace-trust pre-answer, and first-message delivery all apply. Leave it out and the preset gets the generic protocol: it launches and runs fine, but Rove reads no history, pre-answers no trust dialog, and falls back to silence-window liveness with settle-then-paste delivery.

Press x on an engine row in Settings to reset a built-in's overrides, or remove a custom engine entirely.

Engine presets and protocols

Rove separates two things a "vendor" used to conflate:

  • the command — what actually runs. A preset id (claude) or a full command line (codex --search). Nothing validates its flags; probe an unfamiliar CLI with <cmd> --help first.
  • the protocol — which adapter Rove uses for that command: whose transcripts to read, whose trust store to pre-answer, whether the first message may ride the launch argv.

The protocol is derived from the command, never declared beside it:

  1. argv[0] names a registered preset (built-in or yours) → that preset's protocol. Deterministic, and it answers before anything spawns — the normal path.
  2. Otherwise Rove can recognise a known engine binary through wrappers (env FOO=1 claude, node …/codex.js), the same walk the process probe uses at runtime.
  3. Neither → generic, described above.

rove api engine-list prints every entry with its raw command and resolved protocol; copy one into rove api add --command verbatim, or edit a flag first. See API.md for the dispatch verbs.

Where conversations are stored

Engines own their own history. Rove reads it, never writes it.

EngineTranscripts
claude~/.claude/projects/<encoded-cwd>/<sessionId>.jsonl
codex~/.codex/sessions/<YYYY>/<MM>/<DD>/rollout-*.jsonl
copilot~/.copilot/session-state/<id>/events.jsonl
kimi~/.kimi-code/sessions/<workspace>/<session>/agents/main/wire.jsonl

That's why a crash never loses a conversation, and why history survives rove reset and a machine reboot.

On this page