A sandbox is a new env type (`type: "gondolin"`): a long-lived Gondolin micro-VM on an SSH environment, with
listed host folders and an HTTP(S) host allowlist. The worker reaches it over SSH to the host, where p2's launcher
(plugins/envs/sandbox: native, or Docker when the host's Node/QEMU are too old) runs pi-env's daemon inside the VM,
so tools, workspace, terminals, uploads and MCP work unchanged. Names outside the allowlist are refused before
the host resolves them.
Conversations working in a sandbox cannot leave it: location tools, subagent spawn/configure, AgentLocations.move,
the terminal tool, and one-shot agents (which now inherit their caller's own location) all keep them there; only the
owner's Relocate moves a session out, after a confirmation. conversationConfinement() exposes it to plugins.
Owner-only management in the Envs sheet: sandboxes listed under their host, host test reports sandbox support,
create/edit/start/stop/restart/test, lock icons in the top bar and sidebar. Tests in test/p2/sandboxes.test.ts
(real VM cases with P2_TEST_GONDOLIN=1) and ui-sandboxes.test.ts; docs in docs/remote-envs.md.
- P2Tool: origin (any|owner) and scope (any|main|subagent) on the tool; the worker's
Durable registry checks them before each call (guardTool), no tool checks itself.
owner: location tools, reload_plugins, conversations, ports, MCP tools.
main: subagent, rename_session, conversations, ports, reload_plugins. subagent: team.
- originOf reads pi.live.run.inputs through tx.submission: the owner's only if every
input of the run is. Agent-written inputs record the writing turn's origin: subagent
tasks and one-shot prompts, team messages, reports (answerOrigin), peer messages.
No peer origin any more.
- Subagents and one-shot agents get their caller's tools (default all, tools narrows),
except scope main; with codemode the script-only tools; subagents get team. One-shot
agents keep codemode and agent. A send takes away what the caller can no longer give.
Each branch is a top-level conversation forked from another at an entry;
the session-scoped p2.main document lists them and names the current one.
Earlier branches are read-only. The main agent's per-agent state
(subagents, artifacts, voice and chat mode, pending move) stays on
conversation 1 for every branch.
- tree plugin: SessionTree (tree, navigate, select); the worker reports
main and branches to the catalog (Sessions v4, catalog schema 4)
- TUI: /tree and double Escape (pi's default "tree"), a tree selector
adapted from coding-agent
- web: Edit on user messages, Branch from here on answers, branch rows
under the session in the sidebar
- main-agent checks use the branch list instead of conversation 1
- search indexes each branch's own entries
Design: apps/p2/docs/tree.md
p2 (Pi Mobile on Chord v2) moves from pi-private into pi as one commit. Root scripts that loop all workspaces
use --if-present; npm test, ./test.sh and the release script cover packages/* only (p2: cd apps/p2 && npm test);
sync-versions also updates apps' workspace pins.