---
status: done
claimed-by: "019fba91-eabf-76ae-b086-a37ac061d6e8"
claimed-at: "2026-07-31T21:14:15-04:00"
completed-at: "2026-07-31T21:14:49-04:00"
parent: "[[002-pi-subagents-map]]"
blocked-by: []
tags:
  - ticket/research
---

# Subagent security and trust research

## Question

What security, trust, project-local configuration, tool inheritance, extension inheritance, and user-confirmation rules should the implementation spec require for spawning child Pi agents safely?

## Answer

Pi subagents must be specified as local-agent orchestration, not as a sandbox or privilege boundary.
Pi has no built-in sandbox, extensions run with the permissions of the user that started Pi, and project trust only controls whether project-local resources are loaded.
Source: `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/security.md`.

The implementation should default to a conservative child environment.
A child should inherit the parent model and safe read/write tool surface only when explicitly allowed by the selected agent definition or spawn request.
It should not inherit project-local extensions, project-local settings, project packages, prompt files, MCP-like external services, or arbitrary environment variables by default.
If a child runs in the same process user account, any stronger isolation claim must be rejected unless the child is routed through a real container, VM, micro-VM, remote sandbox, or equivalent OS boundary.
Source: `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/containerization.md`.

The parent extension may load user-level agent definitions without a project trust decision, because user/global Pi resources are already in the user's local trust boundary.
Project-level agent definitions should load only after the same project trust decision that protects `.pi/settings.json`, `.pi/extensions`, `.pi/skills`, `.pi/prompts`, `.pi/themes`, `.pi/SYSTEM.md`, `.pi/APPEND_SYSTEM.md`, and project `.agents/skills`.
Source: `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/security.md`.

The child-spawn tool must be allowlisted by explicit active tools and must perform a local preflight before starting a subprocess.
That preflight should validate the agent name, context mode, working directory, tool policy, model, extension inheritance, project trust state, and whether the requested spawn can write to the workspace.
If the request asks for risky capabilities, the tool should ask for user confirmation in TUI/RPC modes and auto-deny or require a preconfigured allow rule in print/JSON headless modes.
Pi docs say extension UI has `hasUI` true in TUI and RPC modes and false in print and JSON modes, so the extension must not depend on dialogs when `ctx.hasUI` is false.
Source: `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/extensions.md`.

## Findings

### Pi's security boundary

Pi runs as a local coding agent with the permissions of the user account that starts it.
It treats files writable by that user as inside the same local trust boundary.
Source: `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/security.md`.

Pi does not include a built-in sandbox.
Built-in tools can read files, write files, edit files, and run shell commands with the permissions of the Pi process.
Extensions are TypeScript modules with the same permissions.
Source: `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/security.md`.

Pi documentation explicitly says real isolation must come from an operating-system, virtualization, or container boundary.
For untrusted repositories, generated code that is not closely monitored, or unattended automation, Pi recommends running in a contained environment.
Source: `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/security.md` and `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/containerization.md`.

Containerization patterns documented by Pi include running the whole Pi process in Docker, routing built-in tools into a Gondolin micro-VM, or running Pi in OpenShell.
The docs warn that extensions run wherever the Pi process runs and that host Pi with tool-routing still leaves other custom extension tools running on the host unless they also delegate operations.
Source: `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/containerization.md`.

### Project trust

Project trust controls whether Pi loads project-local settings, resources, packages, and extensions.
It is not a sandbox and does not restrict what the model can ask tools to do after work starts in a directory.
Source: `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/security.md`.

Pi considers a project to need trust when it finds `.pi/settings.json`, `.pi/extensions`, `.pi/skills`, `.pi/prompts`, `.pi/themes`, `.pi/SYSTEM.md`, `.pi/APPEND_SYSTEM.md`, or project `.agents/skills` in the current directory or an ancestor.
A bare `.pi` directory does not require trust.
Source: `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/security.md`.

When trust is declined, Pi skips protected resources.
`AGENTS.md` and `CLAUDE.md` context files still load regardless of project trust unless context loading is disabled.
Source: `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/security.md`.

Project-local extensions load only after project trust is resolved.
Before trust is resolved, only context files, user/global extensions, and CLI extensions load, and only those extensions can handle the `project_trust` event.
Source: `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/security.md` and `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/extensions.md`.

Non-interactive modes do not show a trust prompt.
Without a saved trust decision, `defaultProjectTrust: "ask"` and `"never"` ignore project resources, while `"always"` trusts them.
The CLI can override trust for one run with `--approve` or `--no-approve`.
Source: `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/security.md` and `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/settings.md`.

### Extension and tool inheritance risks

Extensions can register custom tools, intercept or block tool calls, inject context, customize compaction, and modify provider requests.
Source: `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/extensions.md`.

Extensions can override built-in tools such as `read`, `bash`, `edit`, `write`, `grep`, `find`, and `ls` by registering a tool with the same name.
Pi displays an interactive warning when this happens.
Source: `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/extensions.md`.

Custom tools are available to the model when registered and active.
Pi exposes `pi.setActiveTools()` and `pi.getActiveTools()` to enable or disable tools at runtime.
Source: `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/extensions.md`.

A child Pi subprocess that starts normally in the same project may load its own global and trusted project resources.
Therefore "inherits parent tools" and "starts Pi in the same directory" are not equivalent.
The implementation must explicitly choose and document whether a child runs with only the subagent runner's controlled tools, with user/global Pi resources, or with full trusted project resources.
Source basis: Pi resource loading and trust behavior in `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/security.md`, `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/settings.md`, and `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/extensions.md`.

### Environment and credential inheritance

Commands run by Pi's built-in bash tool receive `PI_SESSION_ID`, `PI_SESSION_FILE`, `PI_PROVIDER`, `PI_MODEL`, and `PI_REASONING_LEVEL`.
Custom bash tools expose this session environment by default unless `exposeSessionEnvironment` is disabled.
Source: `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/environment-variables.md`.

The Pi process also reads variables such as `PI_CODING_AGENT_DIR`, `PI_CODING_AGENT_SESSION_DIR`, `PI_PACKAGE_DIR`, `PI_OFFLINE`, `PI_SKIP_VERSION_CHECK`, and provider credentials such as API keys.
Source: `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/environment-variables.md`.

A child subprocess will inherit the parent process environment unless the runner deliberately supplies a sanitized environment.
This is standard process behavior and follows from the subprocess-based runtime decision in [[020-pi-subagents-pi-runtime-research]].
The implementation should therefore pass only required Pi/provider/session variables and should strip stale parent `PI_SESSION_*` variables unless the child intentionally reports against the parent.

### User confirmation and headless behavior

Pi extensions can use UI helpers such as `confirm`, `select`, `input`, and `notify`.
`ctx.hasUI` is true in TUI and RPC modes, and false in print and JSON modes.
Source: `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/extensions.md`.

A subagent extension cannot safely depend on interactive confirmation in print or JSON mode.
For headless runs, risky spawns should be denied unless a global user setting or explicit spawn parameter already authorizes the requested class of operation.
Source basis: non-interactive trust behavior in `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/security.md` and UI mode behavior in `/nix/store/rg248h9sz8dylm8p6a9w9fj4zrv4sgm5-pi-coding-agent-0.82.1/lib/node_modules/pi-monorepo/docs/extensions.md`.

## Required rules for the implementation spec

### Trust rules

- User-level agent definitions may load from `~/.pi/agent/agents/` without project trust.
- Project-level agent definitions in `.pi/agents/` must be treated as protected project resources.
- If Pi does not natively consider `.pi/agents/` a trust-triggering resource, the extension must only discover it after an already-trusted project decision or must create its own equivalent trust gate.
- Declined project trust must prevent project agent definitions, project extension inheritance, project package inheritance, and project prompt inheritance from affecting children.
- Untrusted project files may still be read by the child through normal tools after the user asks to work in that repository, so prompts must not describe project trust as prompt-injection protection.

### Spawn confirmation rules

Require user confirmation before a spawn when any of these are true:

- The child can write to the parent workspace.
- The child can run shell commands.
- The child can access paths outside the project worktree.
- The child can inherit project-local extensions, packages, or settings.
- The child can install packages or run package manager hooks.
- The child can access network tools beyond the model provider connection.
- The child can use a higher-cost model than the parent.
- The child is fully independent and not attached to the parent status/lifecycle view.
- The child is requested from an untrusted or project-supplied agent definition.

In modes without UI, deny those spawns unless an explicit global allow rule is present.
Do not let project-local config grant those allowances for itself.

### Tool policy rules

- Default children to a minimal tool set.
- Treat tool access as an allowlist, not inherited ambient authority.
- Provide named policy presets only as neutral mechanics, such as `read-only`, `workspace-write`, and `full-parent-tools`, not as opinionated agent types.
- Do not pass the parent extension's complete tool registry by default.
- If a child needs a custom tool from the parent, pass that tool explicitly through a typed adapter or reject the spawn when no safe adapter exists.
- Deny nested subagent spawning by default, and require explicit opt-in plus a depth limit.
- For writing tools, keep Pi's file mutation queue behavior or equivalent serialization so parallel writes cannot race destructively.

### Extension and resource inheritance rules

- Do not load project-local extensions in children by default.
- Do not inherit project settings in children by default, except for trusted project settings explicitly marked as safe for children.
- Do not inherit prompt templates, skills, themes, packages, or model provider extensions merely because the parent has them.
- Prefer starting child RPC processes with a subagent-specific config directory or with explicit CLI/settings inputs when Pi supports that cleanly.
- If the implementation cannot prevent child subprocesses from loading ambient global Pi extensions, document that user/global Pi config is in the local trust boundary and expose an opt-out mode for stricter child runs.

### Environment and credential rules

- Sanitize child process environment.
- Pass provider credentials only when needed for the selected model.
- Strip stale parent `PI_SESSION_ID`, `PI_SESSION_FILE`, `PI_PROVIDER`, `PI_MODEL`, and `PI_REASONING_LEVEL` unless intentionally projecting parent metadata.
- Set child session storage explicitly so child transcripts are separated from parent transcripts.
- Do not expose parent session files to child prompts or status payloads unless the chosen context mode requires it.
- Avoid passing arbitrary shell environment variables into children, especially tokens and desktop/session variables, unless the user opts into ambient inheritance.

### Context and filesystem rules

- For `fork` mode, copy only the intended conversation/context slice and clearly label it as parent-derived.
- For `independent` mode, start with no parent transcript except the task prompt and selected agent definition.
- For workspace writes, prefer a temporary worktree or explicit output patch handoff when the task is adversarial, speculative, or review-oriented.
- Do not call a same-user subprocess "isolated" unless it is actually routed into an OS isolation boundary.
- If stronger isolation is requested, integrate with a container, VM, micro-VM, or OpenShell-like backend rather than adding in-process checks and calling them a sandbox.

### Audit and status rules

- Persist child spawn metadata in the parent session as non-prompt transcript entries where possible.
- Record child id, agent name, context mode, cwd, model, effective tool policy, trust source, start time, stop time, exit state, and output summary.
- Do not include secrets, full environment dumps, or provider auth material in parent-visible status.
- Show whether the child is running with project resources, user/global resources only, or sandboxed execution.

## Limitations

This research is based on Pi documentation and prior ticket decisions, not a fresh source-code audit of Pi's resource loader.
The implementation spec should verify exact CLI flags available for suppressing project resources or selecting config directories when the subprocess runner is designed.
