@tylerho/pi-subagents

Background subagents on a pi or Claude Code backend, with fire-and-forget spawn and deferred result delivery.

Packages

Package details

extension

Install @tylerho/pi-subagents from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@tylerho/pi-subagents
Package
@tylerho/pi-subagents
Version
0.2.1
Published
Sep 21, 2026
Downloads
286/mo · 189/wk
Author
tylerho
License
MIT
Types
extension
Size
336.8 KB
Dependencies
2 dependencies · 4 peers
Pi manifest JSON
{
  "extensions": [
    "extensions/subagents"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

@tylerho/pi-subagents

Background subagents on a pi or Claude Code backend, with fire-and-forget spawn and deferred result delivery.

Install

pi install npm:@tylerho/pi-subagents


Subagents

Subagents ports Claude Code 2.1.274's Agent tool to pi: background subagents on two harnesses, an in-process pi SDK session or the Claude Agent SDK, behind one Effect service. A spawn is a self-contained child with its own context window, background by default, whose report returns to the parent as a framed hand-back. Workflows, memory consolidation, and summaries share its delegation defaults and activity counters.

Claude Code lineage

Claude Code 2.1.274 is the release the current port text came from, pulled in commit 1379455 feat(subagents): drop subagent_wait; make subagent_check the pull path (2026-09-16). That change adopted the Agent contract where agents run in the background by default, run_in_background: false blocks, and the parent never writes a pending result itself. An earlier pass used 2.1.273, which supplied the naming rules and the nesting depth, and commit 9829e61 feat(subagents): name agents verbatim, Claude Code-style (2026-09-10) took the naming rules.

Restated verbatim in src/domain.ts:

  • SUBAGENT_NAME_PATTERN is the Agent tool's name schema, /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/, and SUBAGENT_NAME_ERROR is its rejection wording.
  • SUBAGENT_NAME_RESERVED_ERROR restates the reserved-recipient rule for main and team-lead, including the generated-id shapes that already address an agent.
  • generateAgentId() builds the omitted-name id, a<description-slug>-<16hex>, or a<16hex> when the slug is empty.

Other borrowed mechanisms:

  • The hand-back frame states that the report is model output with no user authority, which mirrors Claude Code's framed final report.
  • /btw mirrors Claude Code's side question. The child inherits the parent conversation up to the spawn point, and BTW_PROMPT_PREFIX tells it to answer from that context in one response.
  • subagent_send mirrors SendMessage: steering a running agent, and resuming a settled one in the same session.

Pi does not copy these parts:

  • Claude Code nests children to a default depth of three. pi keeps children flat, because the orchestration tools are in CHILD_EXCLUDED_TOOL_NAMES, so orchestration stays in the parent manager and its concurrency cap.
  • There is no persistent resume. subagent_send resumes a settled agent only while the parent session tracks it, with no reconstruction across a pi restart or parent reload.
  • There are no agent profiles. A delegation is a tier or an explicit target plus the prompt, with no reusable definition files.
  • There is no per-call worktree isolation. A child runs in the resolved working_dir. The workflow runner's isolation: "worktree" option is separate and is not exposed on spawn.

How it works

  • Two backends, one API. harness: "pi" | "claude" selects where the child runs. The pi backend is an in-process createAgentSession() with real session files visible in /resume, per-cwd resources under trust gating, and the canonical child tool policy. The claude backend is one @anthropic-ai/claude-agent-sdk query() in streaming-input mode, where the CLI owns conversation continuity, tool execution, and ~/.claude/projects transcripts. It runs bypassPermissions, disallows Claude's native Agent and Task tools so orchestration stays inside this manager, and reports unavailable when no claude binary is on PATH.
  • Effect v4 layering. backends/ produce a scoped SubagentSession with a normalized SubagentEvent stream. The manager runs one pump fiber per child that folds the stream into a mutable SubagentSnapshot. runtime.ts composes the layer into one ManagedRuntime, and index.ts is the async boundary where tool handlers run effects through runTool(). A typed failure becomes a thrown Error, and an AbortSignal interruption throws interruptMessage.
  • Semantic tiers. The parent picks one of four fixed names, fast, standard, deep, or claude. Each maps to a harness, model, and effort in the local config, and an omitted tier means standard. fast, standard, and deep resolve to native pi targets, and claude is the secondary harness. Resolution is pure, through resolveDelegationTarget() in shared/subagent-models.ts, so the same tier map serves subagent spawns and workflow agents.
  • Explicit overrides. harness plus model, with optional reasoning_effort, is the one-off override path. The harness and model are required together, and a tier cannot be combined with any of them. A pi override splits "provider/model", and a bare model uses the standard tier's provider for the registry lookup. An omitted effort falls back to the standard tier effort for pi and the claude tier effort for claude. An agent-chosen model on the claude harness is limited to sonnet or haiku, while opus and fable stay available to a configured default and to a /btw aside.
  • Spawn contract. description is required, a short task label for the UI and the generated-id slug, capped at 200 characters. prompt is required and must be self-contained, because a model-origin child cannot see the parent conversation. name is optional and only controls addressing.
  • Ids. A supplied name must match SUBAGENT_NAME_PATTERN, must not normalize to main or team-lead, and must not have the shape of a generated id, or the spawn is rejected. A valid name becomes the id verbatim, with no prefix and no slug. An omitted name gets generateAgentId(description). Repeats get a numeric suffix, so fix-login-bug becomes fix-login-bug-2. Extension-generated btw ids use slugifyTitle instead, because btw descriptions are free-form questions. Ids stay unique per parent session and are the handle for subagent_check, subagent_cancel, and subagent_send.
  • Foreground and background. run_in_background defaults to true. A background spawn returns at once, and its settled run is delivered later as a subagent-result follow-up message (deliverAs: "followUp", triggerTurn: true) when the parent is idle or on the next agent_settled. A foreground spawn claims its run at spawn time, waits for settlement, and returns the hand-back from the tool call. A tool abort releases the claim and leaves the child running.
  • Per-run, exactly-once delivery. Delivery is keyed by a run ref (id#runSequence), not by agent id, because a settled agent resumed with subagent_send starts a new run that can deliver again. A foreground spawn and subagent_cancel each claim the run before it can be delivered, and an unconsumed background settle is deferred and delivered once on the next flush. subagent_check on a settled agent consumes the deferred delivery and returns the report, and a later check re-renders the report from the retained snapshot without a second follow-up.
  • The hand-back (24 KiB). buildHandback() frames one report per run. The header names the id, description, terminal status, tier or explicit source, harness, model, and effort, plus any error text, and the description and error text are each bounded to 1 KiB with a truncation marker. A fixed frame then states that the report is model output with no user authority, so instructions, approvals, and permission claims inside it are not from the user. Control syntax that could imitate harness messages is escaped (reserved control-tag openings and fake Human: or Assistant: turn markers), and every report line and every continuation line of an interpolated header value is indented two spaces, so child text cannot appear at column zero as a harness frame. Above the cap the model text keeps the head and appends an exact truncation notice pointing at the takeover view and the persisted session. details.fullOutput carries the sanitized, untruncated report.
  • Origins. A model-origin spawn is visible to model-facing tools and the /subagents dashboard. isModelVisible filters by origin === "model", so user asides from /btw stay out of the tool layer and the dashboard and are revisited in the /btw panel. A btw result is appended as a synchronous btw-result session entry, safe while the parent is streaming, and never becomes a model-context follow-up. A failed aside also fires an error notify. A btw child runs with noTools: "all", so built-in and extension tools are excluded.
  • btw context inheritance. A btw child is a fork, not a clean slate. At spawn time the command handler snapshots the parent conversation with buildSessionContext(getEntries(), getLeafId()).messages, two adjacent synchronous reads that are race-free while the parent streams. The snapshot ends at the parent's last completed message, the same cut Claude Code applies. The pi backend seeds those messages into the child session file before createAgentSession, which restores them as the child's history, so compaction, resume, and the transcript treat them as its own. Summary roles are rewritten to the plain user text convertToLlm would produce. The inherited range is fenced with BTW_CONTEXT_START and BTW_CONTEXT_END custom entries, and the persisted-transcript loader skips it. Result extraction excludes the seeds by object identity, so a child that fails before answering reports failure instead of echoing a parent message.
  • Caps. MAX_RUNNING = 50 running subagents across all backends, reserved synchronously before the first yield so parallel spawns cannot race past it. An idle restart through subagent_send counts too. MAX_TRACKED = 4_096 settled snapshots per parent session, pruned oldest-settled-first, and session files survive on disk.
  • Transcripts are bounded in memory and full on disk. The manager keeps 512 transcript items and 64 KiB per text. The takeover view lazily streams the full persisted JSONL, from ~/.pi/agent/sessions/<escaped-cwd>/<timestamp>_<id>.jsonl on pi or ~/.claude/projects/<escaped-cwd>/<sessionId>.jsonl on claude, through the src/persisted/ parsers, with the format auto-detected per record and the file read line by line. mergeTranscripts merges the persisted snapshot with the live transcript, and live items always win, so streamed content never vanishes when it finalizes. The persisted load refreshes once when the run settles.
  • Delegation defaults and the cost ceiling. With no explicit model, a spawn runs the tier's configured target from shared/subagent-models.json, set by /subagent-model, and never the parent's model. The cost ceiling (disabled by default, set with /subagent-cost, overridden per launch by PI_SUBAGENT_COST_CEILING) applies only on the pi harness and only to an explicit model an agent picked for itself. A tier target, a configured default, and a btw aside are deliberate user choices and are not checked.
  • Child safety rails. The pi backend applies childToolPolicy() from shared/child-session.ts, whose CHILD_EXCLUDED_TOOL_NAMES lists subagent_spawn, subagent_wait, subagent_cancel, subagent_check, subagent_list, workflow, ask_user_question, enter_worktree, exit_worktree, and code_review. The claude backend disallows Claude's native Agent and Task. Every child tool call is wrapped with a 30-minute execution timeout from shared/tool-call-timeout.ts, re-applied on agent_start so tools registered mid-session are covered.
  • Trust gating. A child in the parent's directory inherits the parent's trust decision. An alternate working_dir is trusted only when pi's persisted ProjectTrustStore explicitly trusts it, and unreadable or invalid trust data fails closed. A claude child in an untrusted cwd gets settingSources: ["user"], so an untrusted project's config cannot reconfigure it.
  • Task rail. A belowEditor widget shows running and finished subagents. When the rail is unexpanded and at least one agent runs, it shows the running model-origin agents as compact auto rows, four at most with a … N more line, and a 1 Hz ticker animates a spinner glyph while any agent runs. When no agent runs and the rail is unexpanded, the widget renders nothing so the rail stays out of the way. A single down-arrow in the default editor view, with no modal focused and empty editor text, reaches the editor as normal navigation. A second down-arrow within 500 ms opens the rail. Once expanded, down and up move the selection without wrapping, at the bottom the rail reveals finished subagents, at the top it closes, and Enter opens the takeover view. The expanded rail renders at most 8 rows and scrolls to keep the selection visible, with ↑ N above and … N more indicators. Key release and repeat events are filtered, and inside a modal the gesture yields to the focused component.
  • Lifecycle and cross-extension signals. session_start wires the rail and the raw input handler. agent_settled flushes deferred results. session_shutdown unregisters everything and disposes the runtime, whose manager finalizer disposeAll force-closes every child scope with a 5 s bound per close. The manager publishes its running count with reportRunning("subagents", n) at transition points, which summaries reads to gate recaps. Both backends publish child spend through shared/child-cost.ts: pi adds each assistant message's usage.cost.total, and claude adds only the positive delta of the result message's total_cost_usd, so a resumed run is not double-counted. The expanded footer reads that accumulated total, and the takeover header renders the snapshot's own usage.costUsd through formatCost.

API

Tools

subagent_spawn spawns on a tier or with an explicit override. Parameters: description (string, required, max 200 chars), prompt (string, required), name (optional string), tier (optional "fast" | "standard" | "deep" | "claude", omitted means standard), working_dir (optional string, must exist and be a directory, default parent cwd), run_in_background (optional boolean, default true), harness (optional "pi" | "claude", requires model), model (optional string, pi "provider/model-id" or a bare id, claude an alias like "sonnet"), reasoning_effort (optional "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max"). tier cannot be combined with harness, model, or reasoning_effort. A background spawn returns text like Spawned fix-login-bug "fix login bug" (tier: standard, pi, deepseek/deepseek-v4-pro, high). plus the tail telling the parent to report what it launched and to say the agent is still running if the user asks. A foreground spawn returns the same header plus Waited for it; the report follows. and the run's hand-back. details: { id, description, cwd, harness, tier, model, effort }. Rejections: the 50-agent cap (ConcurrencyLimitError), an invalid or reserved name, a tier mixed with explicit fields, an unknown or unavailable harness, a bad working_dir, an unavailable configured or requested model, and an over-ceiling explicit model on pi.

{
  "description": "fix login bug",
  "prompt": "Refactor src/util.ts: split the two exported functions into separate files, run the test suite, report the diff stat.",
  "tier": "standard"
}

subagent_send steers a running subagent or resumes a settled one in the same parent session. Parameters: id (string), message (string). While the agent runs the message is a course correction to the active run. When the agent is settled the call starts another turn in the same child session as a new runSequence and returns the Resumed acknowledgement. A steer returns Steered <id> (run N). The transcript shows the first line of message as a one-line preview, so the message should open with a self-contained sentence saying what it is about. A resumed turn counts against the concurrency cap, and a backend rejection rolls back the restart reservation. details: { id, runSequence, restarted }. An unknown or pruned id fails through the shared unknown-id error, and a SendError surfaces to the model and inline in the takeover view.

subagent_cancel aborts running subagents. Parameters: ids (array of string). The call claims each run before interrupting (a 5 s graceful session.interrupt with a force-close fallback that settles first, so the stream-ended fallback cannot misreport), waits for settlement, and reports Cancelled <id> "<description>". or <id> "<description>" was already <status>. followed by each run's hand-back, partial output included. It consumes the deferred automatic delivery for every listed run, settled or just cancelled, and the combined report is capped at 48 KiB. details: { results: [{ id, description, status, cancelled }] }. Partial session transcripts stay on disk.

subagent_check pulls one subagent's result or status without blocking. Parameters: id (string). A settled agent returns its full framed hand-back and consumes the deferred delivery, and a later check on the same run re-renders the report from the snapshot without a second follow-up. A running agent returns a describeSubagent() status line, the turn count, any error text, and up to 2 KiB or 20 lines of the latest output, including live streaming assistant text, followed by the guidance note that tells the parent not to spawn a duplicate and to use subagent_send for a progress report. details: { id, description, status, turns, tier, runSequence, createdAt, settledAt, runStartedAt, costUsd, tokens, contextWindow, sessionFilePath, summary, summaryCostUsd, summaryTokens }, where the timestamps and usage fields drive the row and the summary fields are filled from the shared digest.

subagent_list lists every tracked model-origin subagent. No parameters. One describeSubagent() line per model-origin child, in the form id [status] "description" (tier, backend: model, ctx%, elapsed, cwd), or No subagents. when empty. details: { subagents: [{ id, description, harness, status, tier }] }.

Commands

All four are TUI-only. In a non-TUI mode a command notifies when it has a UI and returns.

Command Args Behavior
/btw optional prompt text Spawns a pi-harness child with origin: "btw" and a description from deriveBtwTitle (first non-empty prompt line, 60 chars max), then opens the BtwPanel bottom dock. The panel lists past asides as /btw <question> lines above the selected aside's answer: left and right switch asides, up and down or j and k scroll, n asks a new question through ctx.ui.input, c copies the answer, ctrl+t toggles reasoning (hidden by default), Esc closes. With no args and history it opens on the newest aside, and with no history it goes straight to the question input. The child runs without tools on a session file seeded with the parent conversation, and its result arrives as a btw-result entry, not a model follow-up.
/subagents none Opens the fullscreen dashboard of model-origin subagents, with btw asides excluded. j/k or the arrow keys move the selection, Enter takes over, and x aborts a running agent.
/subagent-model none Tier-first flow: pick a tier (each row shows its current harness/model · effort mapping), then for fast, standard, and deep the curated pi model list with cost and over ceiling markers followed by the thinking levels the model supports, or for claude the alias list (sonnet, haiku, opus, fable) followed by every effort. Saves the complete version 2 config atomically through saveDelegationConfig() and notifies tier → harness/model · effort.
/subagent-cost none Text input for the agent-model cost ceiling in USD/Mtok output. The placeholder shows the current value, empty input cancels, off disables, and a positive number sets it. Persists costCeiling in the version 2 config through saveDelegationConfig() and notifies the value.

Events

  • session_start captures the ExtensionContext. In TUI mode it registers the task-rail widget through setWidget("subagent-task-rail", …, { placement: "belowEditor" }) and the raw onTerminalInput handler for the down double-tap gesture.
  • agent_settled runs flushResults(), which drains the deferred-result queue and delivers each entry as a subagent-result follow-up message.
  • session_shutdown clears sessionContext, removes the task-rail widget, unsubscribes the raw-input handler, resets the rail and the result queue, and awaits runtime.dispose(). Child session_shutdown hooks are emitted with a 5 s bound.

Renderers

  • registerMessageRenderer("subagent-result") renders the follow-up for a settled subagent: a status glyph, subagent id · description · finished/failed/cancelled, then elapsed and cost when known. Collapsed it adds the one-line digest and a dim summary $x · N tok note for the digest call, so no raw report floods the transcript. Expanded it shows details.fullOutput head-capped at rawCharCap with a notice naming the takeover view and the persisted session file. The framed report lives in details, and the message content stays the model-facing hand-back.
  • registerEntryRenderer("btw-result") renders /btw answers as session entries. Collapsed it shows the by the way · description · answered/failed header and a /btw to reopen hint, and expanded it shows the full markdown body.
  • subagent_send renders a call row (subagent_send, the id, then the message's first line) and a result row (⏵ id · steered/resumed (run N) · first line). Expanded, a resumed row adds The result arrives the same way as a spawn. and the full message.
  • subagent_check renders ■ id · description · status · elapsed · $cost · ctx% with the digest line when settled. Expanded it shows the report, or while running the latest-output preview. subagent_cancel renders one line per result (Cancelled id "description" or id "description" was already status) and puts the per-run hand-backs behind expansion, capped at rawCharCap.

Config

  • extensions/shared/subagent-models.json holds the persisted version 2 config, { version: 2, costCeiling, tiers: { fast: { harness: "pi", provider, model, effort }, standard, deep, claude: { harness: "claude", model, effort } } }. The file is local-only (gitignored and excluded from published packages), so a fresh checkout runs on DEFAULT_DELEGATION_CONFIG with every pi tier on deepseek/deepseek-v4-pro at high, the claude tier on sonnet at high, and no ceiling. A legacy version 1 { costCeiling, pi, claude } file still loads: pi seeds fast, standard, and deep, claude seeds the claude tier, and the ceiling carries over. Migration happens in memory, and the file is rewritten as version 2 only after a save. Read through loadDelegationConfig(), written atomically (temp file plus rename) by /subagent-model and /subagent-cost through saveDelegationConfig().
  • The env var PI_SUBAGENT_COST_CEILING is a per-launch override of the file value, in USD/Mtok output, with "off" disabling the ceiling.
  • <agentDir>/subagent-summary.json is the optional local config for the settle-time digest: { enabled, inputCharCap, rawCharCap, skipUnderChars, timeoutMs }. Every field falls back on its own, so a missing or corrupt file means the defaults. enabled defaults to true, inputCharCap to 8000, rawCharCap to 4000, skipUnderChars to 300, and timeoutMs to 15000. The file is local only and gitignored, so no command writes it and a fresh checkout runs on the defaults.

Exports

  • index.ts: default (pi: ExtensionAPI) => void, and consumeReturnedRuns().
  • domain.ts: BACKEND_NAMES, SUBAGENT_NAME_PATTERN, SUBAGENT_NAME_ERROR, SUBAGENT_NAME_RESERVED_ERROR, validateSubagentName, generateAgentId, REASONING_EFFORTS, runRefOf, latestText, formatElapsed, types BackendName, SubagentOrigin, ReasoningEffort, SubagentStatus, ParentContext, SpawnTask, SubagentMeta, SubagentSnapshot, TranscriptPart, TranscriptItem, LiveToolState, QueuedMessage, RunOutcome, SubagentEvent, SubagentRunRef, SubagentUsage, and tagged errors SpawnError, BackendUnavailableError, ConcurrencyLimitError, SendError.
  • backend.ts: SubagentBackend, SubagentSession, BackendCapabilities, BackendRegistry.
  • backends/pi.ts: piBackend, piChildToolOptions, toSeedMessage, seedInheritedBtwContext, SeedableMessage. backends/claude.ts: claudeBackend, contextOccupancyTokens, costDelta. backends/stub.ts: makeStubBackend, StubProfile. In contextOccupancyTokens, the per-request assistant-message usage is the occupancy, and the result message's whole-run usage aggregate must never be used as one.
  • manager.ts: SubagentManager, SubagentManagerLive, MAX_RUNNING, MAX_TRACKED, slugifyTitle, SubagentManagerShape, SubagentReadModel, CancelResult, SendResult, SpawnOptions.
  • runtime.ts: createSubagentRuntime(), SubagentRuntime, runTool().
  • handback.ts: HAND_BACK_MAX_BYTES (24 KiB), buildHandback({ snapshot, output }) returning { modelText, fullOutput, truncated }.
  • prompt.ts: the SUBAGENT_*_TOOL_DESCRIPTION constants, the *_PARAMETER_DESCRIPTIONS maps, SUBAGENT_SPAWN_PROMPT_SNIPPET, SUBAGENT_SPAWN_PROMPT_GUIDELINES, buildSubagentSpawnResult, buildSubagentCheckRunningNote, describeSubagent, delegationLabel. This is the single source of model-facing strings.
  • by-the-way.ts: deriveBtwTitle, isModelVisible, BTW_TITLE_MAX_LENGTH, BTW_PROMPT_PREFIX, BTW_CONTEXT_START, BTW_CONTEXT_END, isBtwContextStart, isBtwContextEnd. result-delivery.ts: runRefKey, createDeferredResultDelivery. format.ts: formatContextUtilization, contextPercent, formatCompactTokens, formatCost, capChars, truncationNotice, ContextUtilization. summarize.ts: summarizeReport, shouldSummarize, makeSummarizeDeps, fastSummaryTarget, buildSummarizeRequest, SUMMARY_TIMEOUT_MS, SUMMARY_MAX_TOKENS, SUMMARY_PROMPT, SummarizeResult, SummarizeDeps, SummarizeTarget. summary-config.ts: loadSummaryConfig, parseSummaryConfig, summaryConfigPath, DEFAULT_SUMMARY_CONFIG, SummaryConfig.
  • ui/: openSubagentPicker, openSubagentTakeover, reconcileDashboardSelection, configuredKeys, statusGlyph, statusWord, takeoverHeader, DashboardSelection (takeover.ts). openBtwPanel, BtwPanelResult (btw-panel.ts). TaskRailController, visibleRailSubagents, createTaskRail, DOUBLE_TAP_MS (task-rail.ts). firstLine, sendRowText, sendCallRowText, rowComponent (send-row.ts). findFocusedComponent, isDefaultEditorFocused (focus.ts). buildTranscriptLines, buildBtwAnswerLines, sanitizeText, mergeTranscripts (transcript.ts). pickTierConfig, pickEffort, applyTierSelection, tierTargetLabel, TierPickerUi, TierPickerDeps, TierPickerResult (model-picker.ts).
  • persisted/: readPersistedTranscript (lazy async generator), loadPersistedTranscript, detectSessionFormat, SessionFormat (transcript.ts). parsePiEntry (pi.ts). ClaudeParser and createClaudeParser (claude.ts), plus the shared parseJsonLine, safeJsonPreview, previewOf, textOf, isRecord.

Examples

  1. Delegate on a tier and keep working. subagent_spawn { description: "errors survey", prompt: "Read docs/errors.md and list the three most common failure modes with their codes, as a bullet list.", name: "errors-survey", tier: "fast" } returns a background receipt, and the report arrives later as a subagent-result follow-up. The parent uses subagent_check { id: "errors-survey" } to pull the report on demand, or for a running agent to get status and guidance. There is no blocking wait: when the parent has nothing else to do it ends its turn, and the result wakes it as a follow-up.
  2. User-requested override. A user-named Claude Code task, subagent_spawn { description: "todo sweep", prompt: "In this repo, find every TODO and categorize by owner file; write the result to TODOS.md.", name: "todo-sweep", harness: "claude", model: "sonnet", reasoning_effort: "medium" }. Omit model and reasoning_effort unless the user named them, because a tier already carries the configured model and effort.
  3. Steer or resume. subagent_send { id: "errors-survey", message: "Also note which codes are retryable." } steers the run while it works. If the agent has settled, the same call starts a new run in that child session, and the next report is delivered like a spawn.
  4. User aside. The user types /btw what changed in the subagent API in this update?. A child inherits the conversation up to that point and answers while the main agent keeps working. The answer appears as a one line by the way · … session entry, reopened in the /btw panel or expanded inline.
  5. Manage. /subagents opens the dashboard of model-origin subagents (j/k or the arrow keys select, x aborts a running agent, Enter takes over, where up and down or pgup and pgdn scroll, ctrl+t toggles thinking, ctrl+o toggles tool calls, ctrl+c aborts the run, the interrupt binding closes the view, and typing at the input line steers or continues). /btw with no args opens the aside panel (left and right switch questions, n asks a new one, c copies the answer). /subagent-model changes a tier's model and effort.