01 — Execution & ownership
DEPENDENCIES, NOT NETWORK HOPSRunnerPool reserves capacity and deadlines, then synchronously invokes AgentRegistry to commit the parent fence and intent. Only successful commitment enables progress and execution. A failed uncommitted admission clears its own references before releasing the logical lane, so delayed finalization cannot revoke a newer retry. Runtime prepares configuration; Runner coordinates ChildSession and safe cleanup.
read_text / list_files when absent from parent tools.
Controller ·
Runner · Runtime
Capabilities follow tools, not inherited text. Append inherits the
parent policy without resource catalogs, followed by the fixed subagent role. Replace
starts with the optional prompt_instruction_path file, then the fixed
role, without the parent prompt. These inputs form the native preamble. The SDK then
renders the agent body as <addendum>, eligible skills, cwd and the
indirect MCP catalog. Replace requires a nonempty body. Disabled definitions and
unknown semantic fields fail closed.
Shared workspace and stable authority. Named agents may mutate the
parent workspace through selected tools. Same-path directory replacement revokes
retained authority. Parent-dispatched tools retain permission hooks and combined
cancellation. The SDK's native write/edit queue serializes
same-file operations within its process/module; it does not cover bash,
MCP or the whole workspace. Native child conversation retention is separate from
volatile run answers.
Session passes native systemPrompt, appendSystemPrompt and
selected-only skillsOverride inputs to the SDK resource loader. No custom
composer or forced final prompt remains. The task is a separate initial user message
inside <subagent_task>, with &<> escaped as
XML text. Optional reference warning and REFERENCE JSON come before that
task block. Each spawn starts a new conversation without parent entries; follow-up
retains only that child’s native history.
One resource owner, one completion coordinator. Session implements SDK
construction, binding, events and teardown. The native provider bridge uses public
Provider.streamSimple and lazyStream, not an agent stream
override. It owns producer settlement, late fetch acquisition and reader cleanup;
terminal delivery alone cannot release a request. Before each dispatch, ParentProvider
checks the actual system text and effective tool declarations, including dynamic SDK
changes. Runner orders abort() → Budget.drain() → close() before Pool
settlement. Abort starts MCP closure but waits only for SDK abort. After operation
drainage, close joins MCP and provider closure alongside SDK shutdown/disposal; an idle
SDK no longer waits for MCP closure. Final settlement still requires every owner.
Session reports transport promises into Runner's existing ledger; it does not create a
second ledger or custom conversation engine.
ChildSession implementation.
02 — Lifecycle & completion
spawn_agent creates a new agentId and first
runId. followup_task({ agentId, requestId, message }) gives
an idle agent a fresh foreground runtime with current policy/tools and its native
conversation. A running agent instead receives steering and a receipt with no usage or
independent answer; the original run retains its remaining budget, deadline and
completion owner. Identical authorized retries return receipts without repeated
effects or usage. send_message stays supplemental data, not a task or new
turn.
close_agent({ agentId }) idempotently closes idle or history-unusable
agents and releases in-memory history and receipts. Active/blocked work must first be
interrupted and safely settled. Spawn, follow-up and close are direct model-only
tools, denied to children. subagent_inspect accepts one of
runId, agentId or
scope: "runs" | "agents"; no selector preserves run
inspection. Agent inspection returns metadata/receipts, never transcripts or
credentials. Controls, results, handoffs and activity require the same
parent/workspace and a branch containing the latest accepted input fence. Existing
activity presentation is unchanged.
AgentRegistry owns native SessionManager.inMemory() history until
explicit close or the parent extension generation ends. Idle history has no time-based
expiry. Reload, parent-session replacement and exit drain owned work, then discard
history. A later generation cannot reopen the conversation. Terminal results and
closed-agent tombstones retain their separate one-hour limits.
Memory capacity failures mark history history_unusable and stop
continuation rather than truncate it. Disk storage and backups are outside this
package; earlier disk files remain untouched, without migration or deletion. No
automatic replay or background execution is added. See the
memory-only history lifetime
and agent continuation guide.
Execution ending starts settlement, not release. Stop requests cancel further work; cleanup and accounting still own the slot and foreground completion.
Executor rejection is different from late cleanup. Rejection
immediately leaves the run blocked, with no future settlement continuation
or autonomous recovery. A blocked run marks pool health degraded but retains only its
own slot. Other free slots remain usable. That run's foreground completion and the
shutdown barrier remain pending while cleanup is unconfirmed. Stop during settlement
preserves the outcome; the 5s grace starts at the first stop request, not at entry to
settling.
One usage owner per path. Outer result carries child-model usage. Parent tool dispatch records nested tool usage; forwarded results omit duplicates. Parent SDK combines both exactly once.
Cleanup precedes completion. Runner waits for started delegated calls, callbacks, provider/transport cleanup, and safe SDK shutdown. A grace timeout reports blocked; it does not prove safety.
03 — Catalog & generation drain
SEPARATE LIFETIME · NO EXECUTION SLOT
AgentCatalog owns one catalog API list task per generation; admitted named runs discover
independently. Concurrent lists return busy; unsafe or draining catalogs
return unavailable. Discovery starts no child, provider call, or tool
execution.
Child-owned selected MCP
NO PARENT MCP FALLBACK
mcp: [figma-bridge] selects only entries in
mcp-sub-agents.json. ChildSession connects every selected server before
prompting. Parent MCP, codemode, search/resource routes and declared aggregators are not
inherited.
- Small model context
-
Default codemode exposure uses native child
ALL_TOOLS,searchTools(),describeTool()andtools.mcp__…(). Native child tool_search activates deferred tools; direct tools are declared and hidden tools remain unreachable. The SDK server catalog advertises indirect codemode/deferred access; direct tools use declarations. No parent registry is inherited. - Owned from acquisition
- Abort starts MCP closure and SDK cancellation concurrently, then Runner drains Budget. First-close failures remain unsafe. Native registrations and nested calls retain time and output budgets. Each actual tool call consumes one start; codemode itself consumes neither the tool allowance nor a leaf concurrency slot.
- Explicit permissions
- Selected user-configured servers authorize child-local calls; parent permission extensions are not inherited. Stdio receives minimal operational environment plus explicit values. HTTP redirects and oversized bodies are rejected.
Supported: stdio and HTTPS/loopback HTTP with explicit env/header credentials. OAuth/provider-token auth and command-based secrets remain unsupported. Native resources, dynamic tool-list refresh and schema validation follow main Pi within the selected server set. See configuration and native SDK boundaries. No live user MCP server was used for local validation.
Explicit child skills
PARENT ACTIVATION UNCHANGED
The extension catalogs bounded local default/settings/package candidates, including
parent-disabled skills. Only explicitly selected names, descriptions and locations go to
the native resource loader. The SDK renders <skills> when native
read or bash is selected; a hidden direct declaration uses
indirect-access wording. Empty tools, read_text alone and arbitrary
custom/MCP readers do not qualify. Candidate and selected frontmatter are read and
revalidated. Runtime execution preparation validates selected bodies and computes the
continuation fingerprint without inserting bodies into the initial prompt. Explicit
selection opts in disable-model-invocation: true skills under the same
reader gate. No package installation, network lookup or parent activation changes occur.
Package manifest exclusions still apply; duplicate names keep the first valid discovered
skill.
Unknown dynamic roots require explicit local settings paths.
skill_add_folders and skills: all are removed. Append replaces
parent skill, tool and MCP catalogs and removes this extension's exact native delegation
rules. Generated parent cwd is removed only when no custom cwd section was supplied;
explicit custom cwd policy is preserved. Other policy sections are preserved; opaque
forced prompts fail. Neither mode inherits parent package/extension skill catalogs.
Omitted or empty skill selection advertises none and performs no skill discovery.
@name task requests parent-model delegation through
spawn_agent({ agent, task }); it does not guarantee execution. See
source coverage and migration.
Diagnose without unlocking
OBSERVATIONS, NOT SAFETY EVIDENCE
subagent_inspect({ runId }) separates pool phase from Runner stage. The
no-ID form also includes catalog health and origin-authorized scan diagnostics. These
snapshots never change admission, cancellation or completion.
- Where and how long
- Current stage, phase/stage age, admission and first-stop time. Monotonic durations freeze at terminal completion; repeated cancellation does not reset them.
- What still owns work
-
pendingToolsandpendingTransportscount tracked top-level calls and provider requests through cleanup, not every nested operation or socket. Zero is not proof of safety. - Recovery distinction
-
Blocked
recovery: await_owned_workmay still settle safely.recovery: containment_requiredmeans no automatic recovery continuation.stage: mcp_closemeans SDK cleanup attempts finished while MCP closure remains pending. None of these observations authorizes force release or automatic replay.
Bounded, owner-only activity. ID-specific inspect adds budget-admission totals and up to eight recent SDK tool names/states. Names are capped at 128 UTF-8 bytes; arguments, results, raw errors, prompts and credentials are excluded. Activity is absent from progress, final/cancel responses and no-ID lists. Tool names can identify servers; the same session and submission-anchor ancestry is required.
Containment is not recovery. A blocked run retains its own slot; other free slots remain usable. Unsafe catalog cleanup disables only catalog listings. Unsafe cleanup retains its owner's foreground completion and shutdown barrier. Remaining capacity does not isolate shared-workspace or external effects. Process termination may lose volatile results and usage; never automatically replay accepted work.
SDK adapter is in Session. Runner retains orchestration and budgets.
Stable SDK >=1.4.0 <2.0.0 is supported. The development workspace
uses SDK 1.4.0.
Runtime bounds
COOPERATIVE LIMITS, NOT ISOLATION- Execution
-
3 runs by default · startup 60s · invocation
30m · stop grace 5s. Full →
busy; draining →unavailable; degraded → remaining capacity usable. No queue. SetmaxConcurrentRunsfrom 1 through 32 in usersub-agents.json; reload to apply. Each provider owner serializes its requests through transport cleanup. Each run permits 256 actual tool starts and 4 concurrent leaf tools. Codemode itself is excluded; each nested tool call consumes one start. - Preparation
-
Per file 64 KiB · candidate reads 8 MiB · roots
32 · entries 4096 · depth 16 ·
prompt/configuration 4 MiB. Preparation checks raw inputs;
preflight leaves
rendered_promptunchecked, along withskill_body_validationwhen skills are selected. Startup checks the SDK prompt, and each dispatch checks final system text plus effective tool declarations. - Retention
-
32 terminal answers · 1h ·
256 KiB per answer · 32 open agents ·
256 MiB generation history. Volatile and origin-scoped. Active or
blocked ownership never expires. Each serialized tool result or update has a
64 MiB ceiling, checked after JSON serialization. SDK text
formatting/spill and structured results remain native. No aggregate tool-result
memory is reserved. Cumulative model tokens are uncapped unless the definition sets
max_model_tokens.
Turn, invocation, and tool deadlines enter safe guard: no new work, up to 30s to finish existing operations, then one no-tools handoff (up to 60s / 2,048 output tokens, within a 90s window). The result remains incomplete. Hard cancellation and token caps still win; unresolved cleanup retains ownership and prevents summarization.
These bounds do not universally cap provider retries, billing, process memory, or non-cooperative operations. No timeout proves cleanup safety. Preparation limits · Run budgets · Pool and retention
Source index
0e74535 BASE + CHILD MCP · 2026-10-17- Fixed parent delegation and child role text; no runtime dependencies.
- Tool registration, origin checks, parent adapters, shutdown; separately owned catalog lifetime and bounded description rendering.
-
src/runner-pool/index.tsAtomic admission, deadlines, authoritative phases, cancellation, drain, bounded terminal records. - Policy capture, preparation/execution order, one pending-work ledger, budgets and final cleanup coordination.
- ChildSession owns SDK lifecycle and message accounting. ParentProvider owns serialized native model requests and transport cleanup. ChildTools owns native tool activation, guarded registration and selected-server readiness. Resources installs the explicit loader, prompts and request-local context.
-
src/runtime/index.tsBounded preparation and native prompt inputs; SDK owns final rendering, with no live session ownership in Runtime. - Definition resolution, fail-closed parsing, bounded traversal and owned file reads.
- Selected skills, tool construction and forwarding, preparation/output limits.
-
src/runtime/mcp.tsSelected-only separate user configuration, validation and explicit environment resolution. -
src/session/mcp/Owned clients/transports, bounded HTTP I/O, direct/deferred visible tool registry and schema-gated calls.