Course · Pi · Rebuild the defaults
Rebuild the defaults
The extension chapter left you able to add capability to Pi: a custom command, a custom tool, a hook that fires on every turn. It never asked whether you should. /stash finds the backlog entries in stash.db (the database of stash, the course’s running example, a small FastAPI feed reader), resync_feed re-runs a feed’s fetch and parse, and each does exactly what you told it to - which is exactly when a less comfortable thought shows up: what’s stopping it from growing into something you didn’t ask for?
Nothing. That’s not a bug you missed - it’s the whole design. Pi ships with no permission-prompt gate at all: no sandbox, no allow/ask/deny list, no confirmation before a bash call. Every tool call the model makes runs, full stop.
Pi states that position plainly rather than burying it: most permission-prompting is security theater, and allow-listing individual commands doesn’t scale, so Pi ships none of it. That’s a real, considered stance, not an oversight, and it’s worth sitting with before you reach for the fix.
Meanwhile stash stopped being a toy repo somewhere in the past two modules. stash.db now holds the deduped, re-synced library - every feed synced clean, twice, to prove the duplicate fix held. That file sits outside git, nothing backs it up, and it is the one irreplaceable thing this course has produced: lose it, and the recovery is re-adding every feed and re-syncing from an empty database. The .pi/ harness around it is real too, but it’s committed - you can rebuild it from history. The database you cannot.
So this module rebuilds guardrails, one at a time, and prices each one. This is the course’s control chapter - the principle about what guides execution, enforces boundaries, and lets you intervene - and its prices are paid in a second currency. The spend isn’t tokens this time - it’s turns. Call it the turn tax: every gate you bolt back on is free the moment it’s idle and costs you a real turn the moment it fires. Four times this module you’ll build something Pi left out (or, once, replace something it shipped), pay the tax to see what it actually costs, and decide - not guess - whether the bill was worth it.
Four stops, same running repo, same two questions at each one: what does this gate cost when it fires, and what does it buy you back?
- Permissions - a damage-control extension that reads a rule file and gates every
tool_call: some violations stop you outright, some let the agent adapt and keep moving. It goes first because it stands between the agent andstash.db. - Task discipline - Pi has no to-do list, on the view that structured task tracking confuses models more than it helps. You’ll build a stricter version anyway: a gate that blocks every other tool until exactly one task is in progress, with state rebuilt from session history instead of a side file.
- Plan mode - Pi has no dedicated planning posture at all. In its place: a
PLAN.mdhabit that persists across sessions and stays fully readable by both you and the agent, on the same hook you’ll recognize from the permission gate. - Statusline - Pi’s default footer already shows model, context percentage, and cost; you’ll replace it with one that also tracks a live tool tally, built from the same footer contract that statusline extensions in the wild reuse (the ones the package gallery turns up, at any rate - no census implied).
None of this makes Pi into Claude Code or Codex with a different paint job. It makes the guardrails a set of files you own, can diff, and can turn off the instant they get in your way. By the end you’ll have a real cost entry for each one, measured in turns instead of tokens, and a verdict on which of the four actually earned its keep.
Start with the sharpest of the four: stopping the agent from deleting the thing you can’t get back.