For the past three months, I have been building a mobile app with Claude Code (350+ files, 70+ database tables, BLE peer-to-peer, encrypted local database, cloud sync). Early on, I noticed a pattern no amount of CLAUDE.md rules could fix, where the agent kept making the same categories of mistakes across sessions. I wanted to pull my hair out (what little are left), and thought that just pushing through each bad session with enough stamina and optimism could get us through the mistakes and back on track. But every day came with new, "fun" surprises from Claude that were genuinely shocking.
The worst examples:
Added a forbidden database library 3 times after being told not to each time.
Leaked encryption metadata to the server (broke login for every user).
Spent 4+ hours debugging a Bluetooth package by guessing at the API instead of reading the docs, then fabricated a timeline when I asked how we ended up on a 2-year-old version.
Made a precise security fix that. broke backup restore because it never considered the full lifecycle
My CLAUDE.md grew to 50+ rules. At a certain point I realized that it was performative and silly. "These rules don't exist just to make me feel good, you know that right?" kind of energy. Claude recited them at session start and violated them with ease. So I stopped writing rules and asked three questions:
Why are you ignoring rules? ("I have to be honest with you. I can ignore rules by treating them more as suggestions. They can't always prevent the behavior...")
What file formats do you actually prefer for governance? ("YAML is a more efficient format long-term...")
If I gave you permission to redesign this system yourself, what would you build? ("The user is raising an interesting idea...")
That third question changed everything. It proposed shell hooks that mechanically block violations. Not instructions to follow, but constraints it physically can't bypass.
Over hundreds of sessions, that seed grew into PACT (Programmatic Agent Constraint Toolkit). The core insight, in Claude's own words:
Rules are suggestions. Infrastructure is law.
The four pillars:
Mechanical enforcement: PreToolUse hooks that block forbidden patterns before the edit lands.
import hive? Blocked.print()instead of the logger? Blocked. Editing a file you haven't read? Blocked. Zero willpower required.Context replacement: A YAML architecture map (SYSTEM_MAP.yaml) that describes every data flow: database table → service → state management → UI screen → cascade behavior. The agent reads this instead of spending 15-20 minutes re-reading source files each session.
Self-evolving reasoning: Instead of rules ("always check dependencies"), cognitive redirections that are questions: "What depends on this, and what does this depend on?" Questions engage reasoning in a way rules don't. The agent can add new redirections when it catches itself making assumptions. Future sessions inherit the self-awareness.
Structure/behavior separation: Architecture maps (what files exist) stay separate from lifecycle flows (what happens across app states). Prevents the two most common doc failures: maps becoming essays nobody reads, and flows duplicating structure that goes stale.
The results over 3 months:
Forbidden library violations: 3 → 0 (mechanically blocked)
Files edited without reading: frequent → 0 (blocked)
Session onboarding: 15-20 min → 30 seconds
Instruction overhead: 50+ rules → 20 (hooks handle the rest)
Cross-session bug rediscovery: regular → declining (solutions knowledge base)
It's packaged as a Claude Code plugin marketplace, so you can install with two commands:
/plugin marketplace add jonathanmr22/pact
/plugin install pact@pactYou get 4 hooks (automatic) and 4 slash commands (/pact-init, /pact-check, /pact-flow, /pact-bug). Run /pact-init to scaffold the governance files into your project.
MIT licensed, totally free: https://github.com/jonathanmr22/pact
I'd be happy to answer questions about specific failures that led to specific features. Obviously every piece of this system exists because something broke, and I plan on keeping it updated over the long-term through more trial and error. For reference, I have a programming and statistical background, but not specifically in Flutter and Dart, which is what my project is partly based on and why I decided to use Claude in this case; I've been designing the current project on paper for 7+ years since grad school and had tried at least 5 or 5 other tools over that time period (remember Bubble.io?!) before Claude became widely available.
I'm thrilled that Claude has super charged my work despite the frustrations, but many devs knows that Claude is only as strong as the person who is babysitting and guiding. So I don't want to give the impression that this is a vibe code project. If you aren't reading its thoughts and hitting that stop button at least a few time a day, then you're in for some shocking results. And of course, using Claude as a method for actually learning the language that I didn't initially understand has paid dividends. Who knew Dart could be enjoyable?!
I hope this plugin has use for some of you out there.
