--- kind: architecture name: pi-approval-architecture description: > Documents pi's approval model vs Hermes, what commands are available, and the architectural constraints that prevent mid-turn tool approval in pi. Updated with /approve and /deny stub commands for cross-agent UX consistency. agent: abiba version: 1.0.0 --- # Pi Approval Architecture ## TL;DR | Feature | Hermes | Pi (Abiba) | |---------|--------|------------| | `/approve` command | ✅ Full — unblocks agent | ✅ Stub — acknowledges, no blocking | | `/deny` command | ✅ Full — blocks agent | ✅ Stub — acknowledges, no blocking | | Dangerous command detection | ✅ 40+ patterns + Tirith | ❌ None (LLM judgment only) | | Mid-turn tool approval | ✅ Agent thread blocks on Event | ❌ No hook in agent loop | | Smart approval (aux LLM) | ✅ `approvals.mode: smart` | ❌ N/A | | Yolo mode | ✅ `/yolo`, `approvals.mode: off` | ❌ N/A | | Permanent allowlist | ✅ `command_allowlist` + `shell-hooks` | ❌ N/A | | Session-scoped approval | ✅ `approve_session()` | ❌ N/A | | Approval timeout | ✅ 60s default, configurable | ❌ N/A | ## Why Pi Can't Do Mid-Turn Approval Pi's agent loop is **418 lines** of TypeScript. It's deliberately minimal: ``` LLM decides → calls tool → tool executes immediately → output goes to LLM → repeats ``` There is no middleware between "LLM decides to call bash" and "bash executes." The extension system (`injectIntoSession`) feeds messages IN but doesn't intercept tool calls mid-turn. Hermes has a full approval pipeline: ``` LLM decides → check_all_command_guards() → if dangerous → notify_cb → block thread → user responds /approve → resolve_gateway_approval() → Event.set() → unblock ``` This pipeline is deeply integrated into Hermes' gateway, tool executor, and session management. Replicating it in pi would require rewriting the core agent loop — violating pi's design constraint of minimal core. ## What Pi HAS: `/approve` and `/deny` Stubs Added to prevent `/approve` and `/deny` from being forwarded to the LLM as garbled input. When a user types these commands to Abiba: - **`/approve`** → "Pi doesn't have pending approvals. Commands execute immediately." - **`/approve session`** → Same response - **`/deny`** → Same response + "For Hermes agents (Tanko, Mumuni), these work with their built-in approval system." This keeps the UX consistent across agents — users can type `/approve` anywhere without getting confused by LLM responses. ## Pi's Full Command Set (Hermes Parity) | Command | Handler | Description | Hermes Equivalent | |---------|---------|-------------|-------------------| | `/status` | System | PM2 processes, containers, session info | `/status` | | `/retry` | Session | Re-injects last user message | `/retry` | | `/continue` | Session | Continues truncated response | `/continue` | | `/new [topic]` | Session | Clears conversation context | `/new` | | `/stop` | Control | Interrupts current LLM processing | `/stop` | | `/model [name]` | Info | Show current model, list available | `/model` | | `/compact` | Session | Requests context compaction | `/compact` | | `/yolo` | Stub | Pi has no approval system — accepted for UX | `/yolo` | | `/verbose` | Stub | Verbosity controlled by prompt, not toggle | `/verbose` | | `/approve` | Stub | Pi executes immediately — no approvals | `/approve` | | `/deny` | Stub | Pi executes immediately — no approvals | `/deny` | | `/help [cmd]` | Info | Shows command help | `/help` | ## What Pi COULD Add (Without Core Changes) These would work within pi's current architecture: 1. **Pre-message dangerous command scan**: Before forwarding an agent response to Zulip, scan the text for dangerous bash commands and add a warning banner. Doesn't prevent execution but alerts user. 2. **User-facing approval prompt injection**: When user asks pi to do something dangerous (detected via regex on user input), pi could respond with a confirmation request before proceeding. This works because it's at the message level, not mid-turn. 3. **Response rate-limiting**: If pi generates many bash commands rapidly, throttle and ask for confirmation. Works within the extension's send path. ## Files | File | Purpose | |------|---------| | `/root/.pi/agent/extensions/zulip/index.js` | Pi Zulip extension with command system | | `/root/prose-contracts/zulip-approval-fix.prose.md` | Hermes Zulip approval fix | | `/root/prose-contracts/pi-approval-architecture.prose.md` | This document | ## Related - Hermes `tools/approval.py` — Full approval pipeline (dangerous patterns, Tirith, smart mode) - Hermes `gateway/slash_commands.py:_handle_approve_command` — Slash command handler - Hermes Zulip adapter fix — HTML stripping for command detection