Claude Code as a delegated runtime
Parent: Agents and delegation.
Rho can hand a delegated agent to the installed claude binary instead of running Rho's own loop. The parent stays in Rho. The child uses Claude Code's harness and the user's Claude subscription. Model choice and runtime choice stay separate: picking an Anthropic model on the Rho runtime is not the same as runtime: claude-cli.
Subscription workaround
Anthropic does not allow third-party clients to sign in with Claude.ai Free/Pro/Max credentials or to route those plans through their own API stacks. Rho's Anthropic provider path is API-key billing only.
runtime: claude-cli is the supported indirect way to spend a Claude subscription from a Rho session: Rho stays the parent orchestrator, and the official claude binary owns sign-in, the child loop, and plan usage. Rho never sees or stores the subscription token. This is not a substitute for Anthropic API access inside Rho's own runtime, and it is not a root-session Claude Code mode.
When this is useful
Use runtime: claude-cli when you want that subscription-backed child while the main session stays on Rho:
- Use a Claude Pro/Max plan on planning, review, or research without making Claude Code the root harness
- Keep Rho as the orchestrator (fan-out, attach, cancel, session tree) while Claude owns the child loop and credential
- Reuse Claude Code tool names and permission behaviour for a bounded child task
- Open the full Claude transcript later with
claude --resume <session-id>after Rho finishes the run
Skip this feature when you only need "a subagent on Opus" through Rho's normal provider path (API key or another provider). Set model: / provider: on a runtime: rho agent instead. You do not need the claude binary for that.
Claude-cli agents are delegated only. The interactive root and rho run root cannot bind runtime: claude-cli. A Rho parent must launch them through the agent tool.
How to use it
Install the binary (Rho does not ship it):
bashcurl -fsSL https://claude.ai/install.sh | bash claude --versionSee Claude Code binary.
Sign in from Rho so Claude Code stores the subscription credential:
text/login claude-codeOr open bare
/login, pick Anthropic, then Claude Code (delegation only). Rho asks you to confirm, then hands the terminal toclaude auth login --claudeaiand never sees or stores the token. Details: Claude Code runtime sign-in.Write a delegated agent definition (there is no built-in Claude agent). Run
/agents createor/create-agentfor a guided questionnaire, or write a file such as~/.rho/agents/claude-planner.md:markdown--- id: claude-planner description: Use Claude Code to plan with an Anthropic model runtime: claude-cli model: claude-opus-5 reasoning: high tools: [Read, Glob, Grep] inherit_claude_config: false --- Produce a short plan. Prefer reading before editing.Notes:
tools:uses Claude Code names (Read,Edit,Bash(git *)), not Rho capabilities- Omitting
toolsmeans no tools. There is notools: all model:is a Claude model alias such asopus, or a full Claude model name. It is not a Rho@alias. In/agents, the Model row offers the aliases Rho knows (fable,opus,sonnet,haiku) plus a Claude Code default row; a definition that pins a full model name keeps its own row- optional
reasoning:maps to Claude--effort(low/medium/high/xhigh/max); omit to inherit Claude's default;offandminimalare rejected - Auto and Allow edits use Claude
dontAskonly when everytools:entry is a proven no-prompt Claude built-in for that Rho approval class andinherit_claude_configis false. ClaudedontAskand--allowedToolsboth execute without prompting, so specifiers such asBash(git *), write/process tools, unknown Claude/plugin/MCP names, or inherited Claude settings refuse spawn. Plan and Bypass keep their Claude-native mappings. Supervised always refuses, becauseclaude -pcannot prompt through Rho
Confirm setup in the TUI:
text/doctor /agents /info/doctorchecks binary and auth health./agentsshows runtime and Claude tool lists./infoopens an overlay with Claude Code ownership wording when signed in.Delegate from a Rho root session (interactive or automation parent on
runtime: rho):Ask the parent to call the
agenttool withagent_id: claude-plannerand a clear prompt. The call returns a run ID immediately, followed by an automatic completion notification.Watch, cancel, and resume:
bashrho attach <run-id>Attach paints Claude tools with the same card grammar as native Rho tools, using Claude names (
Read,Bash,Glob) plus paths, counts, and diffs when the stream provides them.Cancel through the
agentstool or parent shutdown. When the run finishes, attach and the completion entry may showclaude_session_id. Reopen the Claude-side transcript with:bashclaude --resume <session-id>/limitsprobes Claude Code/usagethrough a PTY when you are signed in (Claude still owns the token) and falls back to last-observed windows if that probe fails.
Quick checklist
| Step | Command or field |
|---|---|
| Install | claude on PATH |
| Sign in | /login claude-code |
| Define | runtime: claude-cli + Claude tools: / model: |
| Permission mode | Plan or Bypass. Auto / Allow edits only with proven no-prompt tools: for that Rho class and inherit_claude_config: false. Unknown names fail closed |
| Launch | Rho parent agent tool, delegated only |
| Inspect | rho attach <id>, /agents, /limits |
| Full Claude transcript | claude --resume <session-id> |
Claude CLI execution details
A runtime: claude-cli agent runs as claude -p with stream-json output. Rho owns the parent tree node; Claude owns the child loop and credential.
Before spawn, Rho checks claude auth status. If the binary is missing or the user is signed out, the run fails immediately with a message pointing at /login claude-code. Rho never stores Claude tokens.
Spawn flags are fixed and deliberate:
| Flag | Behaviour |
|---|---|
--output-format stream-json --verbose --include-partial-messages | NDJSON event stream with partial text |
--input-format stream-json | NDJSON user turns on stdin so the parent can course-correct a live child |
--permission-mode | Always set from a Claude-native mode. Delegated runs map Rho Plan to Claude plan and Rho Bypass to Claude bypassPermissions (just run; not Claude classifier auto). Rho Auto / Allow edits map to Claude dontAsk only when every declared tool is a proven no-prompt Claude built-in for that Rho approval class and inherit_claude_config is false. Claude dontAsk also auto-approves read-only Bash and PreToolUse hooks, and --allowedTools runs listed tools without prompting, so a specifier such as Bash(git *) (emitted as --tools Bash), write/process tools, unknown Claude/plugin/MCP names, or inherited settings refuse spawn rather than over-claim a deny-closed --allowedTools fence. Advisor one-shots set Claude dontAsk directly, with no tools. Supervised refuses before spawn. |
--disallowedTools Task,Agent | Blocks Claude nested subagents (legacy Task and current Agent) so fan-out stays under Rho |
--tools | Restricts built-in tool availability to the base Claude tool names from tools:. A specifier such as Bash(git *) still lists Bash, and unknown names have no proven Rho class, which is why Auto / Allow edits refuse those shapes under dontAsk. Empty allowlist still sets --tools "" so ambient tools are not inherited |
--allowedTools | Every declared non-nested-agent tool entry from tools: as separate argv values (bare names such as Read and patterns such as Bash(git *)). Task and Agent are never listed here |
--setting-sources | Empty for Claude dontAsk so user, project, and local hooks and allow rules cannot widen the child. Org-managed Claude policy still applies. Otherwise project by default, or user,project,local when inherit_claude_config: true |
--strict-mcp-config | MCP servers only from what the spawn passes |
--system-prompt-file / --append-system-prompt-file | From the agent definition body plus the delegated-child communication contract. prompt: replace writes a private run-dir file and passes --system-prompt-file; prompt: extend uses --append-system-prompt-file, even when the definition body is empty, because the contract is always included. Prompt body bytes never appear on argv |
--model | From the agent model: field when set, passed through unchanged. Omitted when the definition inherits Claude's model. Parent provider/model updates do not overwrite Claude agents |
--effort | From agent reasoning: when set (low, medium, high, xhigh, max). Omitted when unset so Claude keeps its default. off and minimal never reach spawn |
--max-turns | Exact configured step/turn cap from the bound launch data. If the installed binary rejects the flag, the run fails with a clear error |
--no-session-persistence | Delegated agent runs omit it, so claude --resume <session-id> works. Rho's own one-shot calls, such as a Claude Code advisor, set it and leave no session behind |
| cwd | Explicit project directory |
| prompt | First stream-json user turn on stdin, not argv |
Parents can message a running Claude-cli child with the agents action message. Rho keeps stdin open, writes each body as another stream-json user turn (Claude queues it until the current turn ends), and closes stdin after the terminal result when no parent messages remain. Each parent message counts against --max-turns. Claude children do not get message_parent yet.
Stderr goes to log.txt in the run directory. Cancel kills the child. Terminal success or failure comes from the stream result message (subtype / is_error), not exit code alone.
Usage, limits, and resume
Per-run usage (turns, tokens, cost) comes from Claude's terminal result and is stored on result.json. Cache read/write token fields stay separate on attachment usage events; input_tokens on the status file is the total input including cache so attach metrics stay consistent.
/limits probes the signed-in claude TUI /usage panel over a PTY and shows remaining percentages when the panel includes them. Rho never reads Claude's credential files. If the probe fails, /limits keeps last-observed windows from a prior claude-cli run.
The probe forces classic rendering in its child environment so inherited fullscreen preferences or Claude's automatic renderer fallback do not change the panel layout. Your normal Claude renderer settings are unchanged.
Percentages shown while Claude is still refreshing are not treated as live usage. The probe waits for refresh completion and reads the completed panel. A refresh timeout, load error, or last-known/partial-data fallback leaves the previous observations unchanged rather than stamping cached percentages as newly fetched. The probe does not retry a failed refresh automatically.
When a run finishes, result.json may include claude_session_id. Attach and the parent completion entry show it so you can reopen the full Claude transcript with:
claude --resume <session-id>Default concurrency is one global pool of 10 delegated runs (behavior.agent_concurrency in config). RHO_AGENT_CONCURRENCY is no longer read. /config → Agent behavior → Concurrent agents changes the live cap immediately. Claude-cli runs also take a nested Claude permit capped at 2 by default (RHO_CLAUDE_AGENT_CONCURRENCY overrides that nested cap). The Claude pool is always min(total, claude_cap), so the nested env cannot open a 2N fan-out window and Claude never exceeds the global total. The named max is 64.
Auth ownership
| Action | Owner |
|---|---|
| Sign in | Claude Code via /login claude-code (terminal handoff to claude auth login --claudeai) |
| Sign out | Claude Code via /logout claude-code or claude auth logout (global, not Rho-only) |
| Credential storage | Claude binary only. Rho never sees or stores the token |