feat: add readonly mode with bash safety and spawn child filtering#7
feat: add readonly mode with bash safety and spawn child filtering#7ofriw wants to merge 96 commits into
Conversation
…acklist and git allowlist
…with TUI indicator
…and spawn child filtering
…only when no branch entries exist
…, and TUI warning
…ion, and redirect analysis
…ges, and CLI flag behavior
|
Summary: GH-2’s readonly-mode safety value is aligned, but concrete bash mutation bypasses and a no-UI toggle crash mean the PR should not merge as-is. Business / Product AssessmentVerdict: REQUEST CHANGES Strengths
In Scope Issues
Out of Scope Issues
Technical AssessmentVerdict: REQUEST CHANGES Input Boundary Shape Risk AssessmentStatus: Triggered Strengths
In Scope Issues
Out of Scope Issues
Reusability
review generated with CURe v. 0.7.3 · multi-stage - stages: 4 · sha 6540936 · model gpt-5.5/high · tok 8m/82k/8m · session agenticoding-pi-agenticoding-pr7-20260528-053241-21cc · 16m32s |
… temp-dir path checking
…dren, and watchdog throttling
Merge conflicts resolved:
- agenticoding.test.ts: accept main's deletion, port ~2000 lines
of readonly tests into tests/unit/ (6 new files, 198 tests)
- notebook/rehydration.ts: take main's typed approach, add null
guard for malformed branch entries
- package.json: union of both sides' devDependencies
- handoff.test.ts, watchdog.test.ts: update expectations for
readonly-aware pendingRequestedHandoff shape
Replaces npm audit with audit-ci to allowlist unavoidable shrinkwrap-pinned vulns (ws, protobufjs, undici via pi-coding-agent) with expiry tracking. Adds config-invariants tests to validate allowlist freshness and CI ordering.
Note: This PR was generated by an AI agent. If you'd like to talk with other humans, drop by our Discord!
Readonly Mode — Safety Net for AI Agent Operations
Context
The agent had unrestricted filesystem access. Any operation — reading config, exploring code, reviewing a PR — could accidentally overwrite files,
rm -rfsomething important, ornpm installunwanted dependencies. There was no way to constrain it to read-only operations short of not using it.What This Changes
This PR introduces a readonly mode — a guardrail that, when active, prevents the agent from modifying the filesystem. The agent can still read everything, navigate, search, debug, and plan. It just can't write (except to the OS's temp dir).
Three ways to activate it:
/readonlycommand orCtrl+Shift+Rshortcut — instant togglepi --readonlyflag — locks down from the first turnreadonly: truein their YAML frontmatter — readonly activates automatically when that skill/command is invoked. Think "review my PR" = readonly, "implement this feature" = unrestricted.How It Works (Two-Layer Enforcement)
Layer 1 — OS Sandbox (macOS
sandbox-exec, Linuxbubblewrap): Wraps bash commands in a kernel-enforced sandbox that denies file writes outside the OS temp directory. This is the real enforcement — the OS stops writes at the syscall level.Layer 2 — Command Pattern Classifier (all platforms, fallback): Parses bash commands and classifies each segment — allows reads and temp-directory writes, blocks anything that modifies the project. Recursively unwraps
sudo,env,eval,execto inspect the real payload. Blocks package managers (npm install,pip install, etc.) unconditionally — they write to unpredictable locations.On macOS/Linux both layers work together (classifier runs first for a clear block reason, then sandbox wraps if allowed).
Critical — please read: Pattern classification is theoretically impossible to make complete. Shell injection,
evalchains, interpreter inline code (python -c "..."),xargswrapping — bypasses are inherent to the problem, not bugs in the implementation. The classifier is a best-effort guardrail, not a security boundary. On macOS/Linux, the OS sandbox provides real enforcement underneath. On Windows, only the classifier applies — which means readonly there is fundamentally a best-effort guardrail and cannot be hardened to real enforcement without OS-level sandboxing support.The Hard Part — Handoff Integration
Readonly mode creates a tension: if handoff is blocked, the user is trapped in a session they can't escape. The solution is a narrow, explicit bypass:
/handoff <direction>→ a temporary bypass flag is setThis means readonly is never a trap, but accidental handoffs don't happen either.
What Was Removed
/handoffcommand pathInfrastructure Along the Way
These aren't readonly-specific but live on this branch:
0.78.1 → 0.79.6: SDK fixes and featuresfileURLToPath,path.joinfor WindowsBreaking Changes? None.
Readonly defaults to off. Every new module is opt-in additive. Existing sessions, skills, prompts, and workflows are completely unaffected.
Value to the Project
readonly: truein their skill definitionspi --readonlyfor automated read-only workflowsAttached is an agent optimized description of the changes in this PR - AGENT_REVIEW.md