Subagents

Claude Code can hand work to subagents (the Task / Agent tool), in the foreground or in the background. A subagent's tool calls go through the same Prismor hooks as the main agent's, tagged with the subagent's agent_id and agent_type, so the same policy applies to them. What changes is who hears about it: a subagent's blocks go to the subagent, and a background subagent's work never shows in the main chat. From the release after 1.61.0 (#628), Prismor tells the person what happened inside each subagent.

Codex (0.16x, spawn_agent) works the same way at the hook level: a subagent's calls arrive under the parent's session with the subagent's own thread id in agent_id, and Codex sends SubagentStop with the subagent's last message. Prismor attributes those calls to the subagent and enforces the same rules on them.

What is enforced

  • Every rule that applies to the main agent applies inside a subagent. Blocks are returned to the subagent with the usual reason, and the subagent reports them back to the main agent.

  • A subagent can't ask for approval. A rule whose action is step_up (approval needed) would raise an approval dialog in the main chat for a call the person never saw, and the whole session waits. Inside a subagent, a step-up is refused instead, with this reason:

    Prismor: this needs the user's OK, and a subagent cannot ask for it. Stop and report back to the main agent, which should ask the user or run it in the main conversation.

    The main agent can then ask in the open, and the person decides.

  • Driving the logged-in browser is a step-up. The rule browser-session-control catches connectOverCDP / connect_over_cdp, puppeteer.connect, chrome-remote-interface, loopback :92xx debugging ports and DevTools websocket paths. A subagent used a browser's logged-in sessions to reach a host that egress had just blocked; this closes that path for main agents and subagents alike.

What the person sees

Each screened call inside a subagent adds one line to a per-session ledger under ~/.prismor/subagents/. When the subagent finishes (SubagentStop), the ledger becomes one line in the main chat:

Prismor · general-purpose (ae5e3143): 4 tool calls screened · 1 needed your OK and were refused (browser-session-control) · 1 flagged (…). Details: prismor sessions --findings-only

The label is the subagent's type and the first 8 characters of its id. When Claude Code doesn't send a type (for some of its own internal helper agents), the label is just subagent.

Claude Code files a SubagentStop message under the subagent's own transcript, where nobody sees it. So Prismor queues the line and shows it with the next main-thread hook: after the Agent tool returns for a foreground subagent, or with the task-notification prompt for a background one, so it appears as the subagent finishes. A subagent that made no screened calls adds no line.

In the session view

prismor dashboard shows each turn's subagents as cards under the prompt that launched them: the task they were given, finished or not, how long they ran, their call count, blocked and warned counts, the files they changed, and the start of their own final report. "Show N calls" opens a subagent's calls. Work a subagent does after a later prompt stays with the turn that launched it.

The task name comes from the launch row for Claude Code (the Agent tool's description) and from the subagent's spawn path for Codex (/root/fix_build shows as "fix build"), read from its transcript at SubagentStop. The report is Claude's <task-notification> result, or Codex's last_assistant_message.

Subagent reports

A background subagent hands its report back as a <task-notification> prompt. These prompts are never blocked: a report that quotes an injection the subagent correctly refused used to be blocked by the judge, and the report was lost. A flagged report gets the same "treat as untrusted data" notice as tool output instead.

The result of the Task / Agent tool itself is not judged for prompt injection. It is either the parent's own brief echoed back or a report from a subagent whose calls were already screened; what happened inside is reported at SubagentStop.

Setup

Claude Code hooks register SubagentStop from the release after 1.61.0, and Codex hooks from the release after 1.61.5. Existing installs get it by re-running prismor setup or prismor install-hooks --agent claude|codex. prismor doctor reports the event in its hook health check. Codex versions that predate SubagentStop ignore the entry; their other hooks keep running (checked on Codex 0.145).

Limits

  • Subagent attribution and enforcement cover Claude Code and Codex. Other agents don't tag subagent calls with an agent_id.
  • The summary line reaches the person in Claude Code only. For Codex it is queued, but no main-thread hook Prismor installs fires at a point where Codex shows it; the dashboard has the same information.
  • Codex encrypts the brief it hands a subagent, so a Codex card is named by the subagent's spawn path, not the task text.
  • Without a semantic judge, file and shell output inside a subagent is not screened for prompt injection (the injection patterns only cover tool results). See Semantic Guard.

See also: Sessions and the dashboard · Prismor runtime.