Files
prose-contracts/pi-approval-architecture.prose.md
T
Abiba b0c0331727 feat: infrastructure-control network-verification + IP-first doctrine, plus 3 supporting contracts
- infrastructure-control: add Section 5.3 (Network Verification & Routing) with
  dual-path checks, NetBird ingress health, DNS drift detection, and routing
  regression alerts. Add Section 7 (Configuration Doctrine — IP-First) mandating
  LAN IPs for all configs/agents, URLs reserved for human browser access only.
  Also enrich access matrix (Mumuni, Koonimo, LiteLLM Admin, Grafana entries),
  reachability matrix, and CT 116 nginx routing + Prometheus targets.
- build-zulip-plugin: fold Success Criteria into Maintains postconditions.
- pi-approval-architecture: new reference doc — pi approval model vs Hermes,
  architectural limits, /approve and /deny stub commands.
- zulip-approval-fix: new responsibility — documents the Zulip HTML/prefix bug
  that broke /approve and /deny, and the one-line fix applied.
2026-07-02 20:39:40 +00:00

108 lines
4.7 KiB
Markdown

---
kind: pattern
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