@thoth-agents/pi-subagents
Installable Pi package that adds markdown-defined subagents, delegated task tools, history, and model profiles.
Package details
Install @thoth-agents/pi-subagents from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@thoth-agents/pi-subagents- Package
@thoth-agents/pi-subagents- Version
0.6.0- Published
- Oct 18, 2026
- Downloads
- 570/mo · 211/wk
- Author
- eremesng
- License
- MIT
- Types
- extension, skill
- Size
- 797.5 KB
- Dependencies
- 0 dependencies · 2 peers
Pi manifest JSON
{
"skills": [
"./skills"
],
"extensions": [
"./dist/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
Pi Subagents Extension
Pi extension for delegating work to markdown-defined subagents. Continuation is unavailable by default: subagent_continue is exposed only when effective enable_continue is explicitly true. The extension registers tools for the orchestrator, runs subagents in isolated in-memory Pi sessions, tracks task history, provides a TUI history panel, and supports per-subagent model/thinking-effort profiles.
Requires Pi >=0.99.0 and Node >=22.19.0; development SDK/TUI dependencies are pinned to 1.0.2. This fork delegates LLM subagents. Background shell jobs belong to the separate @thoth-agents/pi-background-tasks package; its lifecycle passes through by default, and child jobs stop with the child. Existing configuration, model/tool commands, run-mode defaults, and continuation policy are preserved.
What it provides
- Markdown-defined subagents loaded from global and project directories.
subagent_runfor task-mode or background delegation to one agent per call.- Optional
subagent_continuefor resuming the exact persisted nested session with optional mode/model/effort overrides whenenable_continue: true. subagent_send_messagefor live same-parent steering of owned background tasks on supported Pi runtimes.- Child-provided
ask_orchestratorfor blocking questions with parentsubagent_reply, and independentnotify_orchestratorfor non-blocking progress (both enabled by default unless denied). - Status/result/list/cancel tools for delegated tasks.
- Isolated in-memory agent sessions for each subagent run.
- Subagent markdown used as system prompt, with delegated task/context as the user prompt.
- Project-scoped task history in a global SQLite data/cache location.
- TUI history panel via
/subagentsorctrl+,by default. - Task-to-background handoff via
ctrl+hby default, configurable insubagents.json. - Automatic background completion/failure notifications that start or queue a parent-orchestrator response; no polling is needed just to wait.
- TUI execution rendering can expand/collapse tool and rendered component output with
ctrl+o, show/hide assistant thinking blocks withctrl+t, and display queued/consumed steering messages in the owning task detail timeline. - Named model profiles via
/subagents-modeland definition tool editor via/subagents-tools, both on pi-core's shared list-editor shell. - Per-agent/default model and thinking-effort configuration.
- Tool allowlist filtering that prevents subagents from delegating to other subagents.
- Generic subagent-to-parent interaction handoff so human decisions happen on the main thread.
Task summary and usage channels
Publishes complete snapshots on pi-core's v2 thoth:subagents:state channel with
source @thoth-agents/pi-subagents and envelope
{ v, source, sessionId, at, data } (at is Unix milliseconds). Data contains
active-session in-memory task summaries: id, agent/display name, mode/status,
model/effort, lifecycle times, input/output token usage and cost, and an output
preview bounded to 800 UTF-16 code units, plus status counts and persisted totals.
It contains no prompts, context, transcripts, results, thread snapshots or
questions. The required history field contains up to 100 persisted session
task summaries selected and ordered by descending cost, using the same strict
allow-list as live tasks; persisted totals remain separate. V1 snapshots are
not accepted by the v2 contract.
Snapshots are published after task changes (activity uses the manager's 150 ms
coalescing), on session start/switch/tree/compact, and in response to
thoth:subagents:state:request. Subscribe before requesting with data: {} and
the target session ID in the envelope. Pre-readiness requests are answered once
by the session readiness snapshot; consumers replace state rather than merge
deltas. There is no replay cache or shared child/parent event bus.
Cumulative parent-session totalCost and runCount are published on v1
thoth:subagents:usage, requested through thoth:subagents:usage:request with the
same envelope/empty-data contract. The raw thoth:subagent-usage bus event and
raw request handler are removed, with no dual publication. Its checkpoint
custom-entry type remains unchanged, including restore and replay-duplicate
suppression. Upgrade pi-subagents and pi-thoth-theme to >=0.3.0 together and
/reload to retain status-line subagent cost display. See
pi-core's exact contracts.
Rendering
Tool calls/results, completion/question messages and the shared above-editor
Work panel render through the theme's Render KIT when present, discovered through
@thoth-agents/pi-core at render time. Without the kit, they keep native Pi
rendering; there is no dependency on @thoth-agents/pi-thoth-theme.
The Agents provider uses pi-core's v2 data-only Work panel contract. Rows carry
semantic status, identity segments and keyed metric/continuation groups.
Reserved format widths keep row heights stable across digit-width changes;
sidebar consumers can request right-aligned metricLayout: 'columns'.
Metrics include cost and use semantic icons in nerd/unicode modes (including
elapsed), with explicit text labels in ASCII. History rows omit unavailable
metrics and their separators instead of showing ?;
the host owns glyph animation and styling, not row callbacks. pi-core's
discovery/action API lists sources,
subscribes to revisions, reads bounded rows and invokes same-session actions.
Upgrade pi-subagents, pi-background-tasks and pi-todo together to >=0.3.0, then
/reload: first-owner arbitration hides incompatible sections in mixed v1/v2
installs.
The visual palette uses theme roles instead of hardcoded neon colors or RGB
cycling. Agents retain animated braille status while running; the shared host
owns input interception and refreshes only while a child runs. While the parent
is busy or subagents are live, Agents shows queued/stopping/running work, current
prompt failures (including cancellation/interruption and timeouts), and at most
the three most recent current-prompt completions. Older outcomes remain in
history, not panel rows. Once the parent is idle with no live subagents, Agents
collapses to one selectable line with session done/failed totals; Enter opens the
same history panel as /subagents or ctrl+,. Prompt boundaries use pi-core's
observed-text heuristic for idle interactive/RPC submissions, not queued steering
or completion wake-ups. The history view and Work detail use pi-core's shared
panel primitives without changing navigation, scrolling, folding, display toggles
or cancellation. Panel overlays open through openOwnedOverlay.
Child rate-limit warnings
The Agents Work panel row and /subagents detail show a warning-role field for
allowed_warning (rate limit warning) or rejected (rate limited)
observations reported by that task's live child session through pi-core's
provider-limits registry. The text identifies the provider/window and shows
reset HH:MM in local 24-hour time when supplied. Task status is unchanged.
Warnings clear at reset without further task activity, or when the same task
reports allowed for that window; an unknown reset remains visible until a
replacement or cache eviction.
Capture starts when the extension loads, before child queries or UI subscriptions. An in-memory UI cache retains the 512 most recently reported task/provider/window observations, independently of row visibility, child teardown, and account-window replacement by other sessions. Detail opened after child teardown reads the same cache. This is not persisted history, replay of the account-wide registry, or quota fetching; extension shutdown/reload discards the cache.
Install as a Pi package
This fork is an installable Pi package named @thoth-agents/pi-subagents.
Thoth-managed public setup requires >=0.3.0, the first release owning
/subagents-tools, and uses this npm source:
pi install 'npm:@thoth-agents/pi-subagents@>=0.3.0'
For local development in this monorepo, use the checkout directly:
pnpm run setup:pi:local
The helper supplies the fork path to Thoth's Pi installer and does not require
publishing the local package to npm. To configure Pi directly, use the same
scoped source and add -l to install for one project instead of globally:
pi install -l 'npm:@thoth-agents/pi-subagents@>=0.3.0'
The package manifest exposes:
{
"pi": {
"extensions": ["./dist/index.ts"],
"skills": ["./skills"]
}
}
The npm metadata includes the pi-package keyword required for Pi package gallery discovery. After publishing the npm package, it is eligible to appear on the Pi package page.
Use /reload after changing extension code, skill files, config, or markdown subagent definitions during an interactive session.
Package installation scope and configuration scope are independent. A globally installed extension can still use project-local .pi/subagents.json and .pi/subagents/*.md; a project-local package installation does not require every subagent setting to be project-local.
Subagent definitions
Subagents are markdown files with optional strict YAML frontmatter. Each definition's identity is its filename stem, trimmed and normalized to lowercase. If frontmatter name is present, it must match that identity case-insensitively; otherwise loading fails with a diagnostic telling you to rename the file or change name.
Load order:
- Global user agents from
$PI_CODING_AGENT_DIR/agents/*.md. - Global user subagents from
$PI_CODING_AGENT_DIR/subagents/*.md. - Project agents from
.pi/agents/*.md. - Project subagents from
.pi/subagents/*.md.
Project definitions override global definitions with the same normalized filename identity. Within the same scope, subagents definitions override agents definitions with that identity and Pi shows a startup warning so the duplicate can be cleaned up. Every failed definition load blocks lower-priority definitions with its filename identity, not a name claimed in invalid frontmatter.
The npm package is the extension runtime only. It does not ship or load subagent definitions from node_modules/@thoth-agents/pi-subagents/agents; use the directories above, or run subagent_list_agents / subagent({ action: "list" }) to inspect the definitions Pi actually loaded.
Default global agent directory:
~/.pi/agent
Override with:
PI_CODING_AGENT_DIR=/path/to/pi-agent-dir
Definition format
Example (discovery.md):
---
name: discovery
description: investigates isolated ideas, code, documentation, and context7 before deciding whether deeper design work is needed
tools:
- read
- bash
- context7_status
- context7_search_library
model: anthropic/claude-sonnet-4-5
effort: low
---
# Discovery Subagent
You are an isolated research executor...
Supported frontmatter:
| Field | Description |
|---|---|
name |
Optional name; must match the filename stem after trimming and case-insensitive normalization. Identity always comes from the filename. A mismatch fails loading; rename the file to <name>.md or change name. |
description |
Short description shown by subagent_list_agents. |
tools |
Tool allowlist: a comma-separated inline list or multiline YAML list, never both. Explicit exact-name lists are the recommended default. Manual advanced globs, including *, match all registered root tools (active and inactive); exact names also work when root-inactive. The runner then adds enabled ask_orchestrator and notify_orchestrator, subtracts disallowed_tools, and excludes native subagent_* tools. Missing permitted implementations are dropped with a durable warning; launch fails if none remain. Omitted tools uses the built-in defaults; an empty definition list uses configured default_tools. |
disallowed_tools |
Manually configured exact tool names removed after allowlist resolution, for injected tools and trimming glob results. Accepts a comma-separated string or YAML list. Absent, empty string/value, or [] means no denial. Globs, non-string items, nested values, and ambiguous declarations fail definition loading with a source diagnostic. Uninstalled denied names are inert and produce no warning. |
model |
Optional model as provider/model-id. |
effort, thinking_level, thinkingLevel |
Optional thinking effort: off, minimal, low, medium, high, xhigh. |
subagent_mode |
Optional default execution mode for this definition: task or background. |
/subagents-tools
Pi-subagents owns /subagents-tools (from 0.3.0). In interactive TUI mode it
opens the shared pi-core list-editor shell: arrows/j/k, g/G or wheel navigate;
enter/e edits a definition, space toggles an exact tool, enter/esc/q returns,
s saves, and esc/q cancels with dirty-draft discard confirmation. The wide table
starts at 84 columns and the cursor-centered viewport follows terminal height.
The editor targets the global/project definitions currently resolved by this
extension, including project overrides. It discovers all registered root tools
(active and inactive) on each open and identifies the child-provided
ask_orchestrator and notify_orchestrator separately. Native subagent_* controls are not selectable.
There is no dynamic * mode, and @active is rejected. Existing globs and
unrecognized names remain read-only and are preserved on normal save.
Saving edits only the definition's tools field, preserving unrelated
frontmatter, disallowed_tools and body bytes. Stale files and pre-write races
fail safely; partial saves report already-changed definitions and allow retry
with the original draft. Running children and ambient root tools are unchanged.
An optional host adapter supplies reset defaults and managed-file validation.
Without one, the command works generically and r defaults is unavailable.
Thoth's adapter applies only to its marked, canonical global agents/thoth-*.md
specialists; project and unmanaged definitions stay generic. Explicit reset may
remove manual entries in favor of the adapter's defaults.
The structural protocol uses
Symbol.for('thoth-agents.pi-subagents.tools-panel.v1'): a registry with
version: 1, an optional adapter (version: 1, appliesTo(target, content),
validate(target, content), optional defaultTools(target, content)), and a
command-ownership capability (version: 1, command: 'subagents-tools').
Targets contain role, filePath, and scope. Preserve other registry fields
when registering. Incompatible versions are ignored; adapters are discovered
on open and managed validation stays bound across save retries.
Upgrade Thoth and pi-subagents together and /reload. New Thoth warns once at
session start when command ownership is absent; new pi-subagents warns when Pi's
registered commands expose duplicate owners from an older Thoth extension.
Tool allowlist formats
Use an explicit exact-name list by default, and choose exactly one tools format per subagent definition.
Comma-separated inline list:
tools: read, write, bash
Multiline YAML list:
tools:
- read
- write
- bash
Both examples load the same allowlist: read, write, and bash. Comma splitting applies to tools and disallowed_tools; scalar fields such as description can contain commas without becoming lists.
Every definition's frontmatter must be a strict YAML mapping with unique keys, regardless of whether it declares disallowed_tools. Only plain scalars, sequences and mappings are supported: anchors (&), aliases (*), merge keys (<<) and explicit tags (!, !! or custom tags) anywhere in the frontmatter fail loading with a diagnostic and block same-filename fallback. Quoted strings containing these characters are ordinary text. Quote the wildcard as tools: "*" (or tools: ["*"]) and quote values containing : , such as description: "worker: x". Unquoted tools: * and colon-containing plain descriptions are invalid YAML and are not accepted as legacy syntax.
YAML parse errors, duplicate keys, non-mapping/null documents, invalid types for supported fields, name mismatches, malformed disallowed_tools, and unreadable files fail definition loading with a source diagnostic and block fallback with the same filename identity. Diagnostics for invalid YAML include quoting guidance. A failed custom.md claiming name: worker blocks custom, not a separate worker.md; it cannot act as a worker override. Quoted keys and YAML string escapes are supported; tools accepts a comma-separated string or a list of strings.
Globs are manual advanced selections, not the default. Every glob, including tools: "*" and agent_browser_*, expands at launch against all tools registered in the root session via getAllTools() (active and inactive). * is an ordinary glob, alone or mixed with exact names; this is broader than the previous active-only behavior. Preserve glob entries when saving or synchronizing rather than expanding them. The removed @active selector is rejected with a diagnostic recommending exact names.
The runtime natively excludes only subagent_*, for every selection form. Other packages' tools, including ask_user_question, todo and third-party delegation tools, are selectable unless the definition denies them. Shell-job tools from @thoth-agents/pi-background-tasks remain selectable under *; its lifecycle passes through by default, and child jobs stop with the child.
With enable_ask_orchestrator: true (the default), every child receives the child-provided ask_orchestrator unless its disallowed_tools denies it. This includes globs (including *), explicit lists that omit it, and empty/default selections; even an empty or unavailable root inventory under * still yields the enabled injected tools. Disabled or denied names are removed before SDK registration and verification, never reported as missing implementations. The same effective permitted list controls SDK tools, custom-tool injection and registry verification. An empty effective selection fails launch. Independently, enable_notify_orchestrator: true injects notify_orchestrator under the same selection and denial rules; disabling ask does not disable notify.
Edit disallowed_tools manually in the definition file to deny injected tools or trim glob results. For example, either format removes injected ask_orchestrator and ordinary bash:
disallowed_tools: ask_orchestrator, bash
disallowed_tools:
- ask_orchestrator
- bash
Thoth-generated specialists use explicit lists that omit the interactive question tool, task-list tool and third-party delegation tools. Only Oracle declares disallowed_tools, denying ask_orchestrator to preserve independent judgment. The runtime itself is role-agnostic. Thoth synchronization preserves operator tools (including globs) and operator disallowed_tools, including an explicit empty denial.
These exclusions are not a sandbox: shell and MCP tools can still launch agents indirectly.
For every selection form—explicit lists and globs (including *), alone or mixed—a selected tool without a child-loadable implementation is dropped after session creation, and the child runs with the remaining tools. Dropped names are persisted as dropped_tools in task and attempt history and shown as a compact warning on running/queued Agents rows in the Work panel, in task details, and in status, result, and completion notifications; they are never listed in the child prompt. If every selected tool is missing, launch fails with the missing-implementation diagnostic. All selections still reject unexpected extra child tools, and unrelated startup failures remain errors.
Exact names and tools matched by globs reach the child even when inactive in the root. For example, agent_browser_* includes root-inactive registered browser capabilities that the child may activate. All selections are checked against the child's registered implementations, rather than requiring every selected tool to be active in the model tool list. Selected tools with deferred or codemode exposure remain callable through Pi's native nested-tool interface. When the effective selection includes the codemode tool, lean children load Pi's public codemode extension in mode on; scripts can call only the child's selected script-callable tools. Children without codemode selected do not load that extension. Excluded and prohibited tools are absent from the child's registered inventory.
If the registered inventory is unavailable or a glob matches no registered tool, that glob contributes nothing; exact names and enabled ask_orchestrator and notify_orchestrator still apply. There is no fallback to the root's active inventory. Native subagent_* controls remain excluded, and disallowed_tools applies to every form. Missing child implementations use the same durable warning rules; launch fails only when no permitted implemented tool remains.
Do not mix the formats or declare tools more than once:
# Invalid: inline and multiline formats are mixed.
tools: read, write
- bash
Invalid definitions are not loaded. On startup or /reload, Pi shows a warning with the subagent name, file path, and validation issue. Use either the inline or list format without duplicate keys. The parser accepts frontmatter files with either LF or Windows CRLF line endings.
The markdown body becomes the subagent instructions.
Project and global config
Choose the narrowest scope that matches the intended behavior:
| Scope | Path | Use it when |
|---|---|---|
| Global defaults | $PI_CODING_AGENT_DIR/subagents.json, or ~/.pi/agent/subagents.json when the environment variable is unset |
The setting should apply across projects unless locally overridden. |
| Project-local overrides | .pi/subagents.json |
This workspace needs different defaults, shortcuts, or tools. |
| One definition | Frontmatter in the selected global/project Markdown definition | Only that subagent needs subagent_mode, or an explicit per-file model/effort override. |
Config resolves as a field-by-field cascade:
enable_continue follows the same cascade and defaults to false. Because tool exposure is decided when the extension loads, changing enable_continue takes effect after /reload or a Pi restart.
- Project
.pi/subagents.jsonvalues win when present. - Missing project fields inherit from global
$PI_CODING_AGENT_DIR/subagents.jsonor~/.pi/agent/subagents.json. - Fields missing from both use built-in defaults.
Avoid copying every global value into project config: add only intentional local overrides unless you specifically want to pin inherited values. Changing where the package is installed does not change this cascade.
Named model profiles are stored separately in thoth/profiles.json, not in subagents.json, and apply by normalized agent name regardless of definition scope. See Model profile resolution. The former model_profiles field in subagents.json is no longer read or written.
Asking an agent to configure Subagents
You can ask the bundled subagents-configuration skill for setup or explanation. If your request does not already name a scope, the agent should explain the cascade and ask whether you want:
- a global default for every project;
- a project-local override for the current workspace; or
- a change to one subagent definition only.
The agent should also ask for unresolved behavior choices—such as whether omitted runs default to task or background—before editing. A question about how configuration works is not authorization to change files, and the agent should not edit both global and project config unless you explicitly request both.
Example requests:
Explain whether default_mode belongs in global or project config. Do not edit anything.
Set default_mode to background only for this project.
Configure the global reviewer profile, but leave project overrides unchanged.
Give the project-local discovery definition background mode without changing other agents.
Config example
The same JSON shape is valid globally or project-locally; place it only in the scope you intend:
{
"default_model": "anthropic/claude-sonnet-4-5",
"default_effort": "medium",
"default_mode": "background",
"enable_continue": false,
"enable_ask_orchestrator": true,
"enable_notify_orchestrator": true,
"ask_timeout_ms": 600000,
"timeout_ms": 1200000,
"timeout_warning_ms": 180000,
"max_total_timeout_ms": 3600000,
"max_timeout_extensions": 3,
"stall_timeout_ms": 240000,
"tool_stall_timeout_ms": 900000,
"stall_suspend_max_ms": 900000,
"max_concurrency": 5,
"debug": false,
"session_resources": "lean",
"lifecycle_passthrough": [
"@thoth-agents/pi-claude-bridge",
"@thoth-agents/pi-antigravity-bridge",
"@thoth-agents/pi-background-tasks",
"@thoth-agents/pi-openai-fast"
],
"history_panel_shortcut": "ctrl+,",
"detail_cancel_shortcut": "x",
"background_handoff_shortcut": "ctrl+h",
"default_tools": [
"read",
"memory_context",
"memory_search",
"memory_recall",
"memory_get"
]
}
Config fields
| Field | Default | Description |
|---|---|---|
default_model |
current orchestrator model | Fallback model for all subagents. Format: provider/model-id. |
default_effort |
current orchestrator effort | Fallback thinking effort. Also accepts default_thinking_level or thinkingLevel. |
default_mode |
background |
Fallback execution mode when neither the invocation nor the selected definition sets one. Accepts task or background. |
enable_continue |
false |
Opt-in gate for new continuations and subagent_continue tool exposure. Project values override global values; changing it requires /reload or restart before tool availability changes. |
enable_notify_orchestrator |
true |
Independently inject child-provided notify_orchestrator unless denied by the definition. Follows the global/project cascade. |
enable_ask_orchestrator |
true |
Gate for always-on child-provided ask_orchestrator (unless denied by that definition) and parent subagent_reply. Follows the global/project cascade; /reload or restart after changes to update parent tool exposure. |
ask_timeout_ms |
600000 |
Positive integer reply timeout per question (10 minutes). Waiting suspends stall_timeout_ms, but does not pause the execution deadline. |
timeout_ms |
1200000 |
Initial execution deadline per subagent attempt (20 minutes); also the default extension amount. |
timeout_warning_ms |
180000 |
Warning lead time before the current deadline (3 minutes). Normalized to 0 (disabled) when greater than or equal to timeout_ms. |
max_total_timeout_ms |
3600000 |
Total execution ceiling including extensions (60 minutes). Raised to timeout_ms when lower. |
max_timeout_extensions |
3 |
Maximum number of deadline extensions per attempt. |
stall_timeout_ms |
240000 |
Inactivity timeout when no tools are active (4 minutes). Suspended during pending orchestrator questions, context compaction, and auto-retry backoff; resuming refreshes both session and active-tool inactivity budgets. |
tool_stall_timeout_ms |
900000 |
Positive integer inactivity budget per active tool (15 minutes), raised to at least stall_timeout_ms. Uses the same numeric normalization, invalid-value fallback, and global/project cascade. Each tool update refreshes that tool's inactivity timer. |
stall_suspend_max_ms |
900000 |
Positive integer safety ceiling for each compaction or auto-retry backoff window (15 minutes). Compaction ends on compaction_end, including errors/aborts; retry backoff ends on the next session event. Exceeding the ceiling aborts with stall_timeout and compaction/retry diagnostics. Uses the same numeric normalization, invalid-value fallback, and global/project cascade as stall_timeout_ms. It does not cap pending-question waits; the execution deadline still applies throughout. |
max_concurrency |
5 |
Max concurrent subagent tasks per cwd/config pair. |
debug |
false |
Enable bounded runtime/interaction diagnostics in the executing project's .pi/subagents-debug.log. Use temporarily and disable after diagnosis. |
session_resources |
lean |
SDK resource loading mode. lean uses the subagent markdown body as the nested session system prompt, adds a metadata-only skill catalog, skips prompt templates, themes, and context files, and loads extensions in tools-only/safety-hook mode so allowlisted extension tools remain available without startup context injection. Use explicit full only when a subagent intentionally needs the full Pi resource set. Also accepts camelCase sessionResources. |
lean_skills |
true |
Enable the lean child skill catalog. Project boolean overrides global; false disables it. |
lifecycle_passthrough |
["@thoth-agents/pi-claude-bridge", "@thoth-agents/pi-antigravity-bridge", "@thoth-agents/pi-background-tasks", "@thoth-agents/pi-openai-fast"] |
Trust list: in lean mode, packages with an exact matching nearest package.json name retain their full event lifecycle, including startup, shutdown, and model selection. Prompt-shaping events are observe-only as defense in depth, except that a before_provider_request return may replace the provider payload (see isolation below); not a sandbox. Project arrays replace global arrays; [] disables passthrough. Non-string entries and the adaptive-root package thoth-agents are rejected with a warning. |
history_panel_shortcut |
ctrl+, |
Shortcut used to open the subagents history/detail panel. Accepts modified Pi-style shortcuts such as ctrl+<letter>, ctrl+,, ctrl+shift+,, or shift+alt+,, and also accepts camelCase historyPanelShortcut. |
detail_cancel_shortcut |
x |
Shortcut for the subagents history/detail panel to cancel only the currently selected queued/running subagent. ctrl+... values are also registered as a Pi shortcut scoped by the active panel, so they still work when the TUI captures control keys; single-letter values are handled by the panel input. Accepts ctrl+<letter>, ctrl+shift+<letter>, ctrl+,, or one lowercase letter, and also accepts camelCase detailCancelShortcut. It is ignored when the panel is not active or the selected subagent is already finished. |
background_handoff_shortcut |
ctrl+h |
Shortcut used to send a running task-mode subagent to the background. Accepts ctrl+<letter> and also accepts camelCase backgroundHandoffShortcut. |
default_tools |
see below | Fallback tool allowlist used by the runner when an agent definition has an empty tool list. Explicit exact-name lists are recommended; supports the same manual globs (including ordinary *) over all registered root tools as frontmatter tools; all forms drop missing child implementations with a durable warning, failing only if every selected tool is missing. Omitted frontmatter tools uses the built-in default list. |
While tools are active, ordinary inactivity is checked against each tool's own budget, not the session budget. At tool start, finite positive numeric timeout seconds on bash/powershell, or timeout_seconds on any tool, extend the budget to the larger of tool_stall_timeout_ms and the declared timeout plus 30000 ms grace, capped at normalized max_total_timeout_ms. If both declarations are valid, the larger applies. Invalid, zero, negative, non-numeric, or absent declarations leave the tool budget unchanged; generic timeout on other tools is ignored. For example, bash with timeout: 1000 gets 1030000 ms by default. Stall errors identify the applied session/tool budget in milliseconds.
Pending questions, compaction, and auto-retry backoff suspend ordinary inactivity as before. The maintenance suspension ceiling and execution deadline remain independent and can abort earlier; subagent_extend changes only the execution deadline, not stall budgets.
Default tools:
["read", "memory_context", "memory_search", "memory_recall", "memory_get"]
The former UI selector mode: "opencode" | "claude" is no longer a supported config field. Do not add it. History/background visibility and task-to-background handoff are available together and are configured independently through their shortcut fields.
Subagent delegation tools are always blocked from subagent tool allowlists, even if listed:
subagent_run
subagent_list_agents
subagent_status
subagent_result
subagent_list_tasks
subagent_cancel
any tool starting with subagent_
Model profile resolution
Named profiles contain model/effort settings for subagents and an optional root orchestrator, not other configuration. Storage:
- Global:
<agentDir>/thoth/profiles.json, whereagentDirhonorsPI_CODING_AGENT_DIRand defaults to~/.pi/agent. - Project:
<project>/.pi/thoth/profiles.json.
Both files use this versioned schema (orchestrator is optional, and model and effort fields may be omitted):
{
"version": 1,
"active": "fast",
"profiles": {
"fast": {
"orchestrator": {
"model": "anthropic/claude-sonnet-4-5",
"effort": "medium"
},
"agents": {
"discovery": {
"model": "anthropic/claude-haiku-4-5",
"effort": "low"
}
}
}
}
}
Optional active means the global active profile in the global file, or the project pin in the project file. Global active must name a global profile (or default); a project pin may name a project or global profile (or default).
Selection precedence is session selection → project pin → global active → default. Inside a project, a project profile shadows a same-named global profile. Missing references produce a warning and fall back to the next level. The reserved, read-only virtual default is never stored: it has no overrides, so agents use their definition/shipped values and the fallback chain below.
Session selection is persisted in the Pi session, survives reload/resume, and never writes configuration files. Switching profiles applies at run time to new runs and continuations without rewriting definitions. Agents or fields absent from the selected profile use the same fallback chain.
Profile orchestrator
An optional orchestrator: { model, effort } beside agents controls the current Pi session, not a subagent named orchestrator:
- Activating with
u,g, orpapplies the effective profile's orchestrator live. - New sessions (
new, orstartupwith no message history anywhere in the session) apply project pin → global active →default. Resume, reload, fork, and startup with existing message history never apply it. - A profile without
orchestrator, includingdefault, leaves the session model untouched. A missing or unauthenticated model warns and keeps the current model and effort; unsupported effort is clamped with a notice.
The extension never writes Pi settings.json. Native /model behavior is unchanged, including any persistence of defaults it normally performs. A profile orchestrator overrides the starting model of new sessions; /model changes act as a session override until another profile activation or a new session applies an orchestrator.
Effective subagent model resolution order:
- Selected profile's
agents[agent].model - subagent frontmatter
model default_model- current orchestrator model
- unresolved
Effective effort resolution order:
- Selected profile's
agents[agent].effort - subagent frontmatter
effort/thinking_level/thinkingLevel default_effort- current orchestrator thinking level
- unresolved
If a configured model cannot be resolved, the runner reports an error. If a selected model fails or stalls and the current orchestrator model is different, the runner falls back to the current model.
Debug and interaction bridge logs
Debug logging is disabled by default. Enable it in global or project subagents.json:
{
"debug": true
}
When enabled, subagents write local debug/audit breadcrumbs to the executing project's .pi directory:
.pi/subagents-debug.log
The log is intended for runtime debugging of delegated sessions and generic interaction handoff issues. Interaction bridge entries include safe metadata such as task id, agent name, request id, kind, requester, prompt presence, and payload presence. They intentionally avoid storing raw private data beyond the bounded task/history surfaces already captured for debugging.
Useful event names:
runner_event— compact SDK event shape observed by the subagent runner.interaction_bridge_payload_detected— runner found a structured interaction request.interaction_bridge_payload_recovered_from_channel— runner recovered a request from the shared interaction channel.interaction_bridge_request_detected— manager received an interaction request from the runner.interaction_bridge_prompt_main_thread— manager is prompting the main user.interaction_bridge_user_response— main user response was published for the subagent to consume.
Tools exposed to the orchestrator
| Tool | Purpose |
|---|---|
subagent_list_agents |
List loaded markdown-defined subagents. |
subagent_run |
Delegate a task to exactly one subagent. Supports task and background mode. |
subagent_continue |
Enabled only when enable_continue: true. Resumes a completed, failed, or cancelled task in the same persisted nested Pi session, with an optional continuation-mode override. |
subagent_status |
Get status for a delegated task. |
subagent_send_message |
Queue a live message for an owned running background task. |
subagent_reply |
When enable_ask_orchestrator: true, answer an outstanding child question owned by the current parent Pi session. |
subagent_result |
Read the result for a delegated task. |
subagent_list_tasks |
List active and persisted delegated tasks for the current cwd. |
subagent_cancel |
Cancel a running delegated task. |
Only the main orchestrator should call these tools. Subagents are explicitly prevented from calling subagent_* tools.
Delegation controls use Pi's model-only exposure: they remain active for the orchestrator's model, while native executeTool and codemode cannot invoke them.
subagent_run
Parameters:
{
agent: string;
task: string;
context?: string;
mode?: "task" | "background";
}
Behavior:
- Invocation mode stays optional. Effective resolution is
input.mode ?? definition.subagent_mode ?? config.default_mode ?? "background". An explicitmode: "task"remains effective when the user asks to wait. mode: "task"waits for completion and returns compact task summaries.- Successful task results contain only the last assistant message with non-empty text, not earlier narration or progress notes. A textless trailing message falls back to the latest text message. Continuations select only from the current continuation's messages; earlier text remains in transcript/history.
mode: "background"returns task IDs immediately. Respond to the user and wait for the automatic completion/failure turn; do not sleep, poll status, or fetch results just to wait. Use status/result tools only when you explicitly need an intermediate status or stored result.- Batch input is intentionally unsupported: call
subagent_runonce per subagent so each delegation has an isolated lifecycle, result, and failure surface. - Double Escape during task-mode execution cancels running subagents and aborts the main turn.
Examples:
// Omitted mode: use the selected definition or config; otherwise background.
{ agent: "analyst", task: "review the plan" }
// Explicit request to wait: task mode is preserved.
{ agent: "reviewer", task: "review the plan", mode: "task" }
subagent_continue
subagent_continue is disabled by default. Set effective enable_continue: true and then /reload or restart Pi before expecting the tool to appear.
When effective enable_continue is false, the tool is not registered, direct or stale continuation attempts receive a generic unavailable response, historical task and continuation records remain visible, and failed/cancelled/interrupted/stopping terminal results plus terminal background notifications do not recommend continuation. Total-timeout partial context still reports subagent_continue: disabled; other terminal output does not mention the tool.
Parameters:
{
task_id: string;
prompt: string;
mode?: "task" | "background";
model?: string;
effort?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
}
Behavior:
- Continuations keep the same
task_idand exact persisted nested Pi session. - New continuations and continuation guidance are available only while the task cwd resolves
enable_continue: true. - Effective continuation mode resolves once as
input.mode ?? previous_task.effective_mode ?? previous_task.mode ?? config.default_mode ?? "background". mode: "task"waits, renders(task), and remains eligible for manualctrl+hhandoff.mode: "background"returns immediately, renders(background), and relies on the automatic completion notification.- The shared Work panel shows an
Agents · N runningsection while work is active, with one compact row per eligible task and+N morecounting only eligible overflow. Live tasks and current-prompt failures remain eligible, alongside at most the 3 latest current-prompt completions; earlier terminal tasks stay in history. While idle with no live tasks, it collapses toAgents · N done · M failedusing session totals. Each row shows a running braille animation (or a distinct queued/terminal glyph), agent, concise task label and tool uses, lifetime input/output tokens, context percentage, average output speed (N tok/s) and active elapsed time, plus task cost. Metrics use semantic icons in nerd/unicode modes and text labels in ASCII; reserved widths keep wrapping stable across number-format boundaries. Running/queued rows retain a warning-colored⚠ N droppedcount when tools were dropped. The task label truncates before warnings and metrics; narrow widths move metrics to continuation rows. Token counts exclude caches. Output speed divides accumulated measured assistant output tokens by generation time, excluding tools and compaction; its counters persist across continuations. Unavailable live values show?, while measured zeroes remain visible; persisted history rows omit missing metrics and separators. Resolved model, activity and other details remain in the existing task panel. With an empty root editor, press ← to focus Work, ↑↓ to select across sections, Enter to open the selected task (or history on the collapsed Agents line), or x twice to cancel a running task. Esc/→ return to the editor. Unfocused ↑↓ retain prompt history, and overlays, dialogs and the task panel receive their keys. The pi-core host alone owns the Work widget, navigation listener and running-only refresh lifecycle. Separate foreground task-mode double-Escape and manual handoff listeners reuse the host's editor-focus, overlay and suspension guard without requiring empty input; without an installed Work host they retain their existing handling. - When
modeis omitted, the continuation preserves the previous task attempt's effective mode. Legacy records without a valid saved mode fall back throughdefault_modeand thenbackground. - Model and effort overrides still require an explicit user decision before use.
Timeout attention and subagent_extend
Before the current deadline, the root receives one automated subagent-attention follow-up with remaining time, extensions used/remaining, recent progress/checkpoint updates, and a partial output preview tail. Held notices are dropped if the attempt or deadline is no longer current. Like other subagent notifications, attention is child input, not user authorization.
For background runs, a best-effort checkpoint steering request asks the child to report done/pending work and touched files through notify_orchestrator({ message: "..." }) only when it is in the verified child selection for the current attempt, then continue. Enqueue does not prove consumption or that a checkpoint arrived.
{ task_id: "subtask_reviewer_...", extra_ms: 600000 }
Root-only subagent_extend({ task_id, extra_ms? }) grants time only to a running task owned by the exact originating parent session. Omitted extra_ms defaults to timeout_ms; explicit values must be positive integers. Grants are clamped to max_total_timeout_ms and limited by max_timeout_extensions. Unknown, foreign, terminal, stopping, or already-expired tasks are rejected, as are exhausted extension counts or ceilings. Extend only on evidence of useful progress; silence leaves the deadline in force.
On total timeout, the task remains failed with category total_timeout. Completion notifications and subagent_result include partial context: received progress/checkpoints, preview tail, extensions used, nested-session availability, and whether subagent_continue is enabled. This is not a final result or a guarantee of resumability; continuation remains opt-in.
subagent_send_message
Use subagent_send_message only for a running background task owned by the exact originating parent session. Successful enqueue is not delivery.
{ task_id: "subtask_reviewer_...", message: "Please include the missing constraint." }
Successful response:
{
"status": "queued",
"task_id": "subtask_reviewer_...",
"pending_message_count": 1,
"message": "Message accepted into the steering queue; this does not prove model consumption."
}
Rejected ownership/runtime examples:
{
"status": "rejected",
"reason": "not_owner",
"message": "Only the exact originating parent Pi session may message this live background task."
}
{
"status": "rejected",
"reason": "unsupported_runtime",
"required_pi_version": ">=0.99.0",
"detected_pi_version": "0.98.0",
"message": "Live background messaging requires Pi runtime >=0.99.0; detected 0.98.0."
}
Live-message requirements, visibility, and lifecycle:
- Live steering requires Pi runtime
>=0.99.0and an available nested SDKsession.steer(...)bridge. Compatibility is detected from the Pi SDK version already loaded by the runner; known old or unknown runtimes fail closed. - Ownership is exact: only the parent Pi session that launched the currently running background attempt can send to it. Continuations rebind ownership to the parent session that starts that attempt.
- A same-parent message may be accepted before the nested steering bridge is ready. It remains in a bounded pending queue and is forwarded exactly once when readiness is established.
status: "queued"proves queue acceptance, not model consumption. The owning/subagentstask detail timeline renders each message chronologically as queued and then consumed when the SDK confirms consumption, including FIFO handling of identical message text.- When the bridge is ready, the tool awaits Pi's asynchronous steering acknowledgment.
status: "handled"means an input extension handled the message, clears its pending delivery expectation, and does not prove model consumption. A native rejection returnsstatus: "rejected"withreason: "enqueue_failed"and removes that message's pending entry. Pre-ready acceptance remains queued until the bridge forwards it; a later failure contributes to the terminal undelivered count. - Active
subagent_statussurfacespending_message_count. Terminalsubagent_resultand completion notifications surfaceundelivered_message_count, including0. - Pending queue entries are discarded on completion, cancellation, shutdown, restart, or continuation; they are not replayed into a new attempt.
- Message text is private to the owning task detail timeline and persisted task-detail snapshot. Lists, widgets, completion notifications, result summaries, logs, and unrelated parent sessions expose only safe counts/metadata.
- Live task-mode rendering shows the latest three safe activity labels; the compact Work panel shows task labels and metrics, with activity available in task details.
subagent_reply
{ task_id: "subtask_analyst_...", request_id: "question-uuid", message: "Keep runtime scope only." }
Only the exact originating parent Pi session may reply. request_id may be omitted only when that task has exactly one pending question. Unknown tasks, unknown/stale requests, ambiguous replies, unavailable caller identity, foreign sessions, and empty replies return clear errors without consuming a question. A successful reply resolves that child tool call with the reply text; it is not a steering message or a new child session.
Questions arrive as automated subagent-question messages with task id, agent, UUID request id, and question text. They trigger a parent turn using follow-up delivery, like completion notifications. They are subagent input, not user messages or user authorization. The orchestrator may ask the human a material decision with its own user-question tool before answering through subagent_reply.
Tools exposed only to selected children
ask_orchestrator
{ message: "Does the approved scope include a migration?" }
- The tool is injected in-process for every child when
enable_ask_orchestratoris true unless denied bydisallowed_tools, regardless oftoolsselection; it is not registered for the root. - It always uses
model-onlyexposure: direct model calls work with or without codemode, but scripts and native nested-tool calls cannot invoke it. - A question blocks until the parent replies, and the child may ask repeatedly in the same live session. Replies are correlated by task id and UUID request id.
- Each question rejects on
ask_timeout_msexpiry, task cancellation, or session shutdown. Waiting suspends stall inactivity (stall_timeout_ms); the inactivity budget resumes after the last pending question ends. The execution deadline continues while waiting; onlysubagent_extendgrants more time within the configured bounds, so long human escalation can still exhaust the task's total budget. subagent_statusandsubagent_list_tasksexposepending_question_count,pending_questions(request_id,message,created_at), and recentprogress_updatesin compact details and text. Pending questions are live-only and cannot be answered after the parent session ends.- Use questions for material alignment or decisions, not as a substitute for the child's own discovery, and never to delegate. This channel does not change the separate human interaction bridge described below.
notify_orchestrator
{ message: "Discovery complete; implementation is underway." }
- Injected for every child when
enable_notify_orchestratoris true (default), unless denied bydisallowed_tools, independently ofenable_ask_orchestratorand the tool selection form. Oracle can notify while ask remains denied. - Returns immediately and keeps the latest five
progress_updateson the task without injecting a parent message or triggering a turn. Progress remains available in task details, status/list tools and timeout context. - Like ask, it is child-only and
model-only: codemode scripts cannot invoke it. Both tools take only{ message }; ask carries questions only.
Commands and shortcuts
| Entry point | Description |
|---|---|
/subagents |
Open the session-focused TUI subagent history panel. |
/subagents-model |
Manage named model profiles and select them for the session, project, or globally. |
/subagents-tools |
Edit tools in resolved global or project definitions; reset requires adapter defaults. |
ctrl+, |
Open the TUI subagent history panel by default. Configurable via history_panel_shortcut in subagents.json. |
x |
Cancel the currently selected queued/running subagent from the open history/detail panel by default. Configurable via detail_cancel_shortcut in subagents.json. |
ctrl+h |
Send the running task-mode subagent task to the background by default. Configurable via background_handoff_shortcut in subagents.json. |
ctrl+o |
Expand or collapse rendered tool output and subagent responses in the active execution/detail view. |
ctrl+t |
Show or hide assistant thinking blocks in the open subagent execution panel, using Pi's app.thinking.toggle keybinding. |
/subagents-model shows profiles with global/local scope, shadowing and session/project/global active markers. Its sidebar appears at 90 columns or wider; narrower terminals use a stacked layout. Legend: ● effective, S session, P project pin, G global active, ~ shadowed. Browsing does not activate a profile. The orchestrator is the first detail row (read-only in default, shown as “session model” when unset); a drift indicator shows when the effective profile's orchestrator differs from the current session model/effort.
| Key | Action |
|---|---|
| ←/→ | Browse profiles. |
| ↑/↓ | Select the orchestrator or an agent. |
| Enter | Edit the selected row's model/effort. |
m / e |
Edit model only / effort only. |
o |
Copy the current session model/effort into the selected profile's orchestrator as an unsaved draft; save with s. |
n / c |
New from default / clone selected profile; choose global or project scope. |
s |
Save the draft or edits. |
r / d |
Rename / delete a profile. |
u |
Toggle this Pi session's selection. |
g |
Toggle global active. |
p |
Toggle this project's pin. |
Pressing u, g, or p on that pointer's current selection clears it and applies the resulting effective profile's orchestrator, if set. Picker “reset” restores default's effective model or effort for that agent. On default, o offers creating a new profile.
New and cloned profiles are in-memory drafts until s and cannot be activated before saving. Saving an unedited new profile stores a full copy of default's effective model/effort for every listed agent; saved profiles are self-contained snapshots. Editing default offers creating a new profile instead; it cannot be renamed or deleted. Renaming carries session, project pin and global active pointers that resolve to the profile to its new name; deleting confirms and clears those pointers. Closing with unsaved changes asks for confirmation.
Both list editors use pi-core's shared shell with selectedBg rows, terminal-cell width handling, cursor-centered viewports, wheel navigation and dirty-discard confirmation. Native CSI-u/kitty keys work without per-panel bindings. The overlay host releases regular-mode mouse reporting on close, rejection or disposal; fullscreen-owned tracking is unchanged. The tools table uses a wide layout at 84 columns.
Non-overlay fallbacks (ui.select and non-TUI) support profile listing and activation only; ui.select sets selections without toggling them off. To edit without the overlay, edit the appropriate thoth/profiles.json file directly, or tools in the selected Markdown definition.
Task history
Task history is stored in a global data/cache location, while each row remains scoped by project cwd:
$XDG_DATA_HOME/pi/subagents/subagents-history.sqlite
Fallback:
~/.local/share/pi/subagents/subagents-history.sqlite
Environment overrides:
PI_SUBAGENTS_HISTORY_DB_PATH=/absolute/path/to/subagents-history.sqlite
PI_SUBAGENTS_HISTORY_HOME=/absolute/path/to/subagents-history-home
The history DB stores:
- task metadata;
- status and timestamps;
- model/effort used;
- usage stats when available;
- result/error/output preview;
- delegated user prompt and subagent system prompt separately;
- compact thread snapshots;
- task events.
When debug: true is configured, the extension also may write debug diagnostics to:
.pi/subagents-debug.log
History and debug logging are best-effort: failures to persist them should not break delegation.
Generic interaction handling
Subagents run in isolated sessions, but any human interaction must happen on the main thread. The extension uses one generic protocol for all such cases.
A subagent-side tool or extension can publish or return an interaction request:
{
"type": "interaction_required",
"requestId": "req-123",
"kind": "operator-decision",
"origin": "subagent",
"requester": { "subagentName": "analyst", "taskId": "subtask_..." },
"prompt": {
"title": "Choose strategy",
"message": "How should the subagent continue?",
"choices": ["safe", "fast"]
},
"payload": { "any": "structured data needed to answer" },
"response": { "expected": "choice" }
}
The parent manager surfaces the request to the main thread, collects a response with select, confirm, input, or editor, publishes:
{
"type": "interaction_response",
"requestId": "req-123",
"status": "answered",
"value": "safe"
}
Then the subagent is retried so the subagent-side tool/extension can consume the response and continue. For unknown or rich interaction kinds, the parent falls back to an editor with the request payload so the user can return arbitrary text or JSON.
Background subagent tasks cannot request interactive main-thread handling. Rerun in task mode if human interaction is needed.
Prompt and memory behavior
In the default lean mode, the runner treats the subagent markdown body as the nested session system prompt. The delegated user prompt contains only the orchestrator-provided context and task. The runner does not inject AGENTS.md, workflow skills, memory startup context, or generated memory constraints into the delegated user prompt.
Lean children discover a metadata-only skill catalog (name, description, exact file location) through native discovery for their cwd: user skills, configured packages including manifest pi.skills, and trusted project .pi/skills and ancestor .agents/skills. The SDK appends the catalog to the specialist system prompt when read or bash is available; skill bodies are loaded only on demand. disable-model-invocation skills are hidden.
Optional definition frontmatter skills: [tdd, "review-*"] filters skill names using glob patterns; omission includes all discovered skills, and skills: [] includes none. Global/project subagents.json accepts lean_skills: false to disable catalogs (default true, project overrides global). Explicit skill paths in assignments remain valid.
Discovery is offline: missing packages are skipped, never installed, including during loader reload. Child settings are separate from the parent. Children within the parent's project reuse its session trust; other cwd values use the persisted native project-trust decision, defaulting to untrusted. Unavailable SDK discovery/trust APIs, skipped packages, validation errors and unmatched filters produce task-details/transcript diagnostics, not invented entries. Lean children still omit context files, prompt templates, themes, append-system files and root lifecycle injection. Full resource mode is unchanged.
In lean mode, non-listed extensions keep tools/safety-hook isolation: selected extension tools and tool-safety hooks (tool_call, tool_result, and user_bash) remain available; other handlers are stripped, except session_shutdown for load-time provider owners. Packages in lifecycle_passthrough retain all event handlers, including session_start, session_shutdown, and model_select. Child startup (reason: "startup") is awaited after parent provider replay and tool-selection verification, before the first prompt. Startup handler errors are non-fatal task-history diagnostics. Teardown emits shutdown once per child before disposal, including failure, cancellation, timeout, and verification failure (where startup has not yet run); generic cleanup remains best-effort with a five-second bound. The listed background-task fork runs its shutdown handlers once first, using the public child context and an independent ten-second bound per handler, so a stalled handler in another package cannot skip child-job cleanup before disposal.
For listed packages, before_agent_start, agent_start, turn_start, context, context_with_system, input, before_provider_request, and before_provider_headers are observe-only: each invocation receives its own clone of event data, with opaque live members such as AbortSignal and functions passed through, unchanged context, and its awaited return discarded, except before_provider_request: its handler still receives a clone, but a non-undefined return replaces the provider payload (this is how @thoth-agents/pi-openai-fast sends service_tier: "priority" in children). All other events pass unchanged. This is defense in depth, not a sandbox: the list trusts packages with the child's live SessionManager and Pi API. A listed extension can still change the child session or prompt through those APIs. Do not list untrusted extensions. The adaptive-root injector package thoth-agents can never receive passthrough and is rejected with a config warning.
Package identity uses the nearest manifest of the real extension file, stops at the first manifest, and fails closed on missing, unreadable, or invalid manifests. Commands, flags, and shortcuts remain stripped in lean mode; full resource mode is unchanged.
The default list contains @thoth-agents/pi-claude-bridge, @thoth-agents/pi-antigravity-bridge, @thoth-agents/pi-background-tasks, and @thoth-agents/pi-openai-fast; explicit [] disables it, and a project array replaces the global array. These listed packages receive their full lifecycle in lean children. Use @thoth-agents/pi-background-tasks for shell jobs: child jobs stop on completion, cancellation, error, or parent-driven teardown (including root reload), without stopping sibling or root jobs. Explicit trust lists must include the fork to retain this cleanup; passthrough is not a sandbox. An Antigravity child starts its Pi-tool MCP bridge lazily when using an antigravity model (at startup, model selection, or before its first provider stream), with private per-instance discovery by default. Children that never use Antigravity do not start a bridge or spawn agy.
Memory behavior should be specified in each subagent markdown definition. A subagent can use memory only when its tool allowlist includes the relevant memory tools.
Context7 access is controlled by each subagent definition's tool allowlist. Grant external documentation tools only to agents that need them.
Bundled resources
This package bundles:
index.tsandsrc/**— the Pi extension runtime.skills/subagents-configuration/SKILL.md— configuration guidance for agents that need to explain, create, or edit subagent definitions and global/project settings. It requires explicit scope selection and unresolved behavior decisions before edits.
Subagent definitions are intentionally user/project configuration, not hard-coded package behavior. Add them globally in $PI_CODING_AGENT_DIR/agents/*.md or $PI_CODING_AGENT_DIR/subagents/*.md, or project-locally in .pi/agents/*.md or .pi/subagents/*.md. Do not inspect node_modules/@thoth-agents/pi-subagents/agents for definitions; that path is not part of the package design and may not exist.
Development
This package is a member of the thoth-agents pnpm workspace; the root pnpm-lock.yaml pins the development Pi SDK and TUI to 1.0.2. Run focused native SDK and renderer checks with 0.99.0 as well, then restore the locked tree with pnpm install --frozen-lockfile from the repository root before final validation.
Install dependencies once, from the repository root:
pnpm install
Run tests:
pnpm --filter @thoth-agents/pi-subagents run test
Run typecheck:
pnpm --filter @thoth-agents/pi-subagents run typecheck
Verify the package contents:
pnpm --filter @thoth-agents/pi-subagents run pack:dry-run
Run the full local check:
pnpm --filter @thoth-agents/pi-subagents run check
Workspace releases
This package is published to npm by the root v*.*.* tag release workflow
together with the other pi-packages/* packages. Publish
@thoth-agents/pi-core first on first publication. Use pnpm pack /
pnpm publish so the workspace:^ dependency becomes a semver range in the
published manifest; prepublishOnly runs the package check for manual publishes.
Related project docs
README.md— package usage, configuration, and development notes.skills/subagents-configuration/SKILL.md— subagent configuration policy.- Pi package docs —
docs/packages.mdin the Pi coding-agent distribution.