{
  "id": "agents",
  "runtimeRequirements": [
    "Loaded by default through package.json#pi.extensions",
    "agent definition catalog and validation",
    "M10 runner contract exists before execution",
    "createAgentSession SDK host required before /agent run or spawn_agent executes",
    "completed agent runs return the exact real non-empty child text; JSON-looking text is not parsed and model-written markers or result envelopes are unsupported",
    "named-tool evidence is collected only from exact SDK tool_execution lifecycle events and passed through AgentChildOutputStats.recordedToolNames; aggregate toolCalls/toolResults never fabricate a tool name",
    "agent observe / agent summary render an on-demand bounded snapshot of current and recent live rows from agentLiveStore.rows; done/cancelled/error rows stay terminal, not running, with currentTools/currentToolArgs/currentToolStartMs cleared and elapsedMs frozen at terminal transition",
    "agent observe / agent summary / agent drill use the shared AgentLivePanel row contract and show source-backed optional metadata only when present",
    "Shared command UI lifecycle clears transient agent list/inspect/observe/summary widgets and status on the next unrelated user input or slash command, EXCEPT a live task/spawn_agent progress widget whose key is pinned for the duration of its run and is not cleared until the run finishes",
    "the current adapter does not use a first-class createAgentSession JSON schema/response_format mode; agent output remains text-only even when a newer Pi host exposes additional structured-output capabilities",
    "named agent.systemPrompt is layered onto current child sessions through SDK appendSystemPromptOverride; bare children receive no package role prompt",
    "spawn_agent is the canonical subagent-spawn tool; it accepts one required task string, starts a bare child when agent is omitted, resolves explicit names only from project/user catalogs, creates one child, returns exact text in content, and keeps runtime metadata in details",
    "SDK children always exclude spawn_agent, so direct agent-to-agent nesting is blocked even for tools=[*]; write-capable children may retain workflow",
    "readOnly=true is host-enforced: the child allowlist is narrowed to read, grep, find, ls, yield, and explicitly requested git_read; bash, write, edit, workflow, and unknown tools are removed; git_read invokes only allowlisted local Git query subcommands without a shell and rejects mutating or process-spawning options",
    "spawn_agent spawns a headless child agent session via the createAgentSession SDK host; it fails closed with an honest reason when that host is unavailable",
    "the agent parameter of spawn_agent advertises the resolved first-match-wins catalog as bounded name - description lines (at most 12 entries, each description clamped to 96 characters, overflow stated as +N more); it is republished on every agent discovery pass including one before_agent_start refresh per turn, and it never replaces the unknown-agent check",
    "unknown-agent errors include available project/user agents, /agent list hint, and a diagnostic .locus/runtime/artifacts/*.json artifact",
    "/agent list and /agent inspect project existing catalog facts into typed VIEW blocks; full TUI catalogs use the shared inline editor-replacement surface while RPC/passive fallback stays compact with source counts, hidden count, and recovery controls",
    "unknown-target and headless settled-run chrome use typed ERROR/RESULT blocks without replacing the domain-owned live fleet, focus, drill, stop, resolver, or runtime store",
    "unknown or incomplete agent command syntax renders a typed WARN with no-action evidence and exact usage recovery",
    "task returns isError=true for unknown-agent and child-session failed/blocked/cancelled results",
    "nested createAgentSession runs do not claim inherited parent yolo/approval policy; Pi native approval happens before the task tool handler",
    "agent context extras are opt-in via LOCUS_AGENT_CONTEXT_EXTRAS=1 and default off",
    "optional memory context uses LOCUS_AGENT_MEMORY_FILE or defaults to <projectRoot>/MEMORY.md; missing files are a non-fatal diagnostic",
    "optional skill context uses explicit LOCUS_AGENT_PRELOAD_SKILLS entries only; no default preload list is configured",
    "skill names resolve through .agents/skills/<name>/SKILL.md then .pi/skills/<name>/SKILL.md under the project root, preserving Pi progressive-disclosure boundaries",
    "/ps opens the existing fleet selector, /ps <target> opens the canonical resolved row, and /agent ps plus /agent drill remain stable compatibility paths",
    "Pi command-context custom UI plus public AssistantMessageComponent and ToolExecutionComponent are required for the native viewer; missing capability is reported explicitly and RPC/headless modes keep passive text fallback",
    "the native viewer uses the shared inline editor-replacement surface and Pi assistant/tool components inside one terminal-height follow-tail viewport, so an update above a tall tool cannot trigger Pi's clear-screen/clear-scrollback full redraw; its fixed start header, labeled request/runtime sections, double-rule message editor boundary, and bottom live-status rule make the viewport zones explicit; PgUp/PgDn and Home/End inspect retained history, Ctrl+O toggles tool detail, Esc closes without child abort, and the timeline's content, byte, and node retention bounds still apply",
    "while an SDK child turn is actively streaming and the host exports Pi's native ExtensionEditorComponent, the viewer accepts editor input and sends Enter submissions through the execution-authority-checked steering seam; settlement or execution replacement removes that seam and returns the retained view to read-only",
    "AgentLiveStore owns live-row lifecycle while _shared/agent-runtime/agent-live-transcript.ts owns one bounded typed timeline with stable block ids, complete assistant snapshots, structured tool lifecycle, cwd, redaction, and latestMessage projection; raw AgentLiveRow.eventLines remain diagnostic data",
    "terminal assistant stopReason=error surfaces errorMessage before the generic empty-result fallback; completed children still require a real non-empty answer and side-effect-only success is not part of the contract",
    "child turn_end assistant usage updates live tokenCount during execution; final getSessionStats tokens replace it with cumulative truth, and workflow parallel/pipeline summary rows show the sum of token-bearing descendants",
    "the passive fleet renders below the editor; bare Up/Down always remain owned by Pi editor/history, while /ps opens fleet management and shift+down remains the terminal-compatible entry fallback; aggregate rows stay visible as headings but only leaf rows are selectable or actionable, then configured select keys navigate, Enter drills the exact leaf row, x asks for confirmation before aborting its active SDK child, and Esc returns to the editor without stopping it",
    "when Pi app.interrupt Escape would abort an active parent turn with live agent rows, a Yes/No confirmation is required first; closing fleet/drill views reports that active agents continue running",
    "agentLiveStore is process-shared through a versioned global symbol because Pi loads package entrypoints through independent jiti instances with moduleCache disabled",
    "the shared inline interaction slot fences Pi's own close callback by slot ownership: a component the host silently replaced can no longer run the host's editor-restore path, so a late timeout, abort, or queued key from a superseded prompt cannot blank the interaction that replaced it, and the incumbent is retired only once the newcomer's factory has produced a component, so a request that never appears cannot take the slot; when a factory rejects, Pi restores the editor over the live component anyway, so the incumbent is explicitly retired on that path too and its owner is told rather than left awaiting a surface that is off the screen; a retired caller sees the typed stale error and reports benign replacement rather than failure — /ps and the agent view say so and name the retry"
  ],
  "stateUsed": [
    "in-memory discovered agent definitions",
    "agent discovery diagnostics",
    "process-shared agentLiveStore.rows, per-row cancellation and active-turn input handlers, AgentLiveRow.transcript typed blocks and latestMessage projection, and AgentLiveRow.eventLines as diagnostic store data",
    "process-shared ephemeral fleet selection state",
    "AgentLiveRow optional metadata for source-backed activity/model/path/tool/result fields",
    "runtime result artifacts",
    "optional child prompt memory from <projectRoot>/MEMORY.md",
    "optional child prompt skills from .agents/skills/<name>/SKILL.md and .pi/skills/<name>/SKILL.md",
    "runtime result artifacts"
  ],
  "provides": {
    "tools": ["spawn_agent"],
    "commands": [
      "agent list",
      "agent inspect",
      "agent run",
      "agent observe",
      "agent summary",
      "agent drill",
      "agent ps",
      "ps"
    ],
    "hooks": ["session_start", "session_shutdown", "before_agent_start", "input"],
    "shortcuts": ["shift+down"]
  },
  "uiLifecycle": {
    "commands": [
      {
        "name": "agent",
        "taxonomy": ["transient-widget", "status", "overlay-selector", "artifact-write"],
        "transient": ["widget:agents", "status:agents"],
        "persistent": []
      },
      {
        "name": "ps",
        "taxonomy": ["transient-widget", "overlay-selector"],
        "transient": ["widget:agents", "status:agents"],
        "persistent": []
      }
    ]
  },
  "permissions": {
    "filesystem": {
      "read": [
        ".agents/agents/*.md",
        "~/.agents/agents/*.md",
        "MEMORY.md",
        ".agents/skills/*/SKILL.md",
        ".pi/skills/*/SKILL.md"
      ],
      "write": [".locus/runtime/artifacts/*.json", ".locus/runtime/reports/*.jsonl"]
    },
    "subprocess": ["git (allowlisted local read-only queries through git_read)"],
    "network": [],
    "browser": false,
    "models": false,
    "ui": [
      "setWidget",
      "setStatus",
      "notify",
      "custom",
      "registerShortcut",
      "confirm",
      "onTerminalInput",
      "getEditorText"
    ]
  },
  "risk": "high",
  "docsPath": "extensions/agents/README.md",
  "tests": [
    "tests/extensions/agents/catalog/agents-discovery.test.ts",
    "tests/extensions/agents/catalog/agent-catalog-hint.test.ts",
    "tests/shared/agent-runtime/agent-runner.test.ts",
    "tests/shared/agent-runtime/agent-sdk-host.test.ts",
    "tests/shared/agent-runtime/agent-live-store.test.ts",
    "tests/shared/agent-runtime/agent-command-run.test.ts",
    "tests/extensions/agents/fleet/agent-observer.test.ts",
    "tests/extensions/agents/operator/agent-observer-text.test.ts",
    "tests/extensions/agents/fleet/agent-drill.test.ts",
    "tests/extensions/agents/fleet/agent-fleet-menu.test.ts",
    "tests/extensions/agents/entrypoint/agent-live-store-entrypoints.test.ts",
    "tests/contracts/extensions/runtime-registration.test.ts",
    "tests/shared/operator/operator-interaction-slot.test.ts"
  ]
}
