Enforcement Architecture
Enforcement Architecture
The pal-e enforcement stack is built on four enforcement layers that work together within Agency. Each layer has a distinct role. (Note: these are enforcement layers within the Agency pillar, not the three operating model pillars — Platform, Docs, Agency. The headings below use "Pillar" to mean "enforcement layer" for historical reasons.)
Enforcement Stack (Hierarchy)
Agents wrap skills. Skills wrap MCP tools. But none of that is enforcement — it's organizational convenience. The only guaranteed enforcement mechanisms are hooks and
disallowedTools. Everything else can be bypassed.
Three Enforcement Mechanisms (Verified 2026-03-01)
Live testing revealed three distinct enforcement mechanisms, each with different properties:
| Mechanism | Scope | How it works | What it blocks | Strength |
|---|---|---|---|---|
| <strong><code>disallowedTools</code></strong> | Inside agent | Strips tools from the agent's tool palette entirely — agent cannot even attempt the call | Internal tools only (Write, Edit, Bash, etc.). Cannot filter individual MCP tools. | Strongest — tool doesn't exist in agent's world |
| <strong>Frontmatter PreToolUse hooks</strong> | Inside agent | Hook script runs on every tool call matching the matcher. Exit 2 = blocked. | Any tool including MCP tools. The only way to block individual MCP tool calls inside agents. | Strong — hook fires, exit 2 blocks, agent sees denial message |
| <strong>Settings PreToolUse hooks</strong> | Main session + agents | Hook script runs on every matching tool call at session level. | Any tool. Fires in main session AND inside agents (but frontmatter hooks are preferred for agent-specific rules). | Strong — same mechanism, broader scope |
Key insight:
disallowedTools is the strongest enforcement for internal tools (Write/Edit/Bash) because the tool simply doesn't exist in the agent's palette. But it cannot filter individual MCP tools — only mcpServers controls server-level access. To block specific MCP tools (like mcp__pal-e-docs__update_note), you MUST use frontmatter PreToolUse hooks.Defense-in-depth example (QA agent):
disallowedTools: Write, Edit, Bash— strips from palette (can't even try)- Frontmatter hook
block-write-tools.sh— catches Write/Edit/Bash if disallowedTools somehow fails (belt and suspenders) - Frontmatter hook
block-docs-writes.sh— blocks all 7 pal-e-docs write MCP tools (only way to block these) - Settings hook
check-issue.sh— bonus layer, gates file writes behind issue tracking
Pillar 1: Hooks Enforce
Hooks are the hard enforcement layer. They can't be bypassed by the agent.
- SessionStart: Injects project context, SOPs, bug/TODO counts
- PreToolUse: Blocks bad actions (main commits, unauthorized merges, missing issues). Also enforces "no plan, no agent" on manual Agent tool spawns.
- PostToolUse: Reminds workflows (review-fix loop, main fast-forward)
- SubagentStart: CANNOT block agent creation. CAN inject
additionalContextinto the subagent. Supports matchers by agent type name. Use for injecting plan context, SOPs, or instructions into spawned agents. - SubagentStop: CAN block via
decision: "block"(prevents subagent from stopping). Supports matchers by agent type name. - Frontmatter PreToolUse: Hooks defined inside agent .md files. Fire during subagent lifetime. Hard enforcement for tool restrictions inside agents. This is the ONLY way to block individual MCP tool calls inside agents.
Key property: Hooks fire on both Bash commands AND MCP tool calls. Separate scripts handle each input format (bash command strings vs MCP JSON params). Frontmatter hooks provide defense-in-depth inside subagent contexts.
Pillar 2: MCP Provides Data
MCP tools are the queryable knowledge layer. Agents pull context on demand.
- pal-e-docs MCP: SOPs, conventions, plans, templates, project pages — all as notes
- forgejo-mcp: Git operations (issues, PRs, branches, reviews) as SOP-aware compound tools
Key property: Data is structured and tagged. Agents query by tag intersection, not by remembering file paths. All agents are read-only consumers of pal-e-docs — only the main session (Betty Sue) writes.
Pillar 3: Skills Guide Workflows
Skills define multi-step procedures that use MCP tools and follow SOPs.
/plan: Fetches plan template from pal-e-docs, creates plan as note, archives previous/review-pr: Orchestrates review-fix loop using MCP tools for Forgejo, CLI for GitHub
Key property: Skills reference templates and SOPs from pal-e-docs by slug. The skill definition is thin; the content lives in pal-e-docs. Skills can delegate to agents via
context: fork + agent field — this is convenience wiring, not enforcement. It makes the right thing easy but doesn't make the wrong thing impossible.Pillar 4: Agents Do Work
Agents are the execution layer. They follow SOPs, use skills, and query MCP.
- Betty Sue: Main session coordinator. Plans, manages knowledge, spawns agents. Not a subagent — injected via SessionStart hook. The only entity that writes to pal-e-docs.
- Dev Agent: Writes code, manages repos, creates PRs. Worktree isolation. Frontmatter PreToolUse hooks block all pal-e-docs writes (verified).
- QA Agent: Reviews PRs for correctness and SOP compliance.
disallowedToolsstrips Write/Edit/Bash from palette (verified — can't even attempt). Frontmatter hooks block pal-e-docs writes (verified). - Dottie: Documentation librarian. Executes doc updates, content audits, bulk cleanup under Betty Sue's direction.
general-purposesubagent type. pal-e-docs read/write + Forgejo read-only. Frontmatter hooks block code writes (verified).
Key property: Agents are stateless across sessions. Context comes from pal-e-docs (project pages, active plans), not from memory. No agent can write to pal-e-docs — this is enforced at the hook level, not just by convention.
How They Compose
- Agent starts → Hook (SessionStart/SubagentStart) injects project context from MCP (pal-e-docs)
- Agent receives task → queries MCP for SOPs and current state
- Agent follows Skill workflow (
/plan,/review-pr) which uses MCP tools - Hooks guard every tool call — blocking bad actions, reminding workflows
- Main session (Betty Sue) updates MCP (pal-e-docs) with results — agents never write docs
Two Spawn Paths — Asymmetric Enforcement
There are two ways agents get spawned. They have different enforcement capabilities:
| Spawn path | Mechanism | Can block spawn? | Can inject context? | Can enforce tool use? |
|---|---|---|---|---|
| Manual (Agent tool) | Betty Sue calls Agent tool with prompt | <strong>Yes</strong> — <code>PreToolUse</code> deny via <code>check-agent-spawn.sh</code> | Yes — via prompt | Yes — PreToolUse hooks |
| Native delegation | Claude Code routes to subagent via frontmatter | <strong>No</strong> — SubagentStart cannot block | Yes — <code>additionalContext</code> | Yes — frontmatter PreToolUse hooks |
Mitigation strategy: Since native delegation cannot be blocked, we use a layered approach:
- SubagentStart hook: Inject plan context and SOP instructions via
additionalContext— guidance, not enforcement - Frontmatter PreToolUse hooks: Hard enforcement inside the agent — QA can't Write, no agent can write to pal-e-docs
- disallowedTools: Strips restricted tools from palette entirely — strongest enforcement for internal tools
Design Principles
- Three enforcement layers — disallowedTools strips from palette, frontmatter hooks block inside agents, settings hooks block at session level
- Defense-in-depth — multiple layers catch what others miss. disallowedTools can't filter MCP tools, but frontmatter hooks can. Settings hooks catch what frontmatter hooks don't scope to.
- MCP is the single source of truth — no scattered local files
- Skills are thin — they reference pal-e-docs, not inline content
- Agents are stateless — context comes from the system, not memory
- Main session owns docs, agents own repos — enforced by hooks, not just by convention
- Fail-open on reads, fail-closed on writes — if pal-e-docs is down, hooks still block bad actions but don't block reads
agent-paradigm— the 5-layer model (Events → Hooks → MCP → Skills → Agents)agent-workflow— practical agent workflow SOPhook-events-reference— all events with blocking, matcher, and enforcement asymmetry detailsagent-spawn-conventions— the "no plan, no agent" axiom and enforcement asymmetryproject-claude-config— the technical enforcement layerproject-ai-agency— the system that defines what gets enforced- Procedures:
sop-hook-block-recovery— recovery procedure when enforcement hooks block unexpectedly