Plan: Agent & Skill Frontmatter Fix + End-to-End Verification

plan-2026-02-28-agent-skill-frontmatter Plan

plan completed

Vision

The team of AI agents that runs Lucas Draney's operations. Each agent has a defined personality, role, SOPs, and toolset. Betty Sue coordinates from the main session, spawned agents execute in isolation. Every agent is documented, every workflow is an SOP, every interaction follows convention.

Projects & Repos Touched

Project/Repo Platform Role in this plan
claude-custom Forgejo Agent .md files and skill SKILL.md files live here (~/.claude/agents/, ~/.claude/skills/). This is the enforcement layer — hooks, frontmatter, settings.
pal-e-docs (knowledge) Forgejo Agent profiles, skill notes, SOPs, templates, enforcement docs — all need alignment. This is where the SOPs live (owned by AI Agency).

Context

On 2026-02-28, we discovered that all agent files in ~/.claude/agents/ are plain markdown without YAML frontmatter. Claude Code requires YAML frontmatter (name and description at minimum) to recognize files as subagents. Without it, they're invisible — Claude Code doesn't know they exist.
Similarly, all skill files in ~/.claude/skills/*/SKILL.md are missing frontmatter. They work as slash commands via backwards compatibility with the old .claude/commands/ format, but they lack configuration (tool restrictions, model selection, context forking, agent delegation).
The project page (project-ai-agency) falsely claims "Profile complete" for all agents. The previous plan (plan-2026-02-25-agent-profiles) delivered markdown content but not Claude Code-compliant configuration.
Additionally, multiple pal-e-docs notes are stale: enforcement architecture references deprecated agent names, hook events reference has wrong matcher info for SubagentStart, templates don't document frontmatter, and the agent-workflow SOP uses deprecated names. Approximately 25 notes are also assigned to wrong projects — see todo-reassign-notes-to-ai-agency for the full inventory.

What's already done

  • [x] Agent profile content written in pal-e-docs (agent-qa, agent-dev, agent-issue-creator, agent-betty-sue)
  • [x] Agent .md files exist in ~/.claude/agents/ (qa.md, dev.md, issue-creator.md, betty-sue.md)
  • [x] Skill SKILL.md files exist in ~/.claude/skills/ (plan, review-pr, implement-phase, fix-review, create-issue, ssh-client-setup)
  • [x] check-agent-spawn.sh hook enforces "no plan, no agent" on Agent/Task tool (PreToolUse)
  • [x] SOP: Claude Config Development is accurate — no changes needed
  • [x] YAML frontmatter on agent files — PR #41 merged
  • [x] YAML frontmatter on skill files — PR #41 merged
  • [x] Agent ↔ skill wiring (context: fork + agent field) — PR #43 merged (convenience wiring, not enforcement)
  • [x] Ownership boundary documented — project-claude-config and project-ai-agency updated with enforcement stack
  • [x] SOP/template/enforcement doc alignment — Phase 4 DONE (2026-03-01)
  • [x] Note project reassignment (~25 notes) — todo-reassign-notes-to-ai-agency DONE
  • [x] SubagentStart docs corrected — cannot block, can only inject context (2026-03-01). All notes updated: hook-events-reference, enforcement-architecture, agent-spawn-conventions, convention-agent-skill-mcp-wiring.
  • [x] MCP-in-forked-context test gate PASSED (2026-03-01) — /review-pr forgejo_admin/claude-custom#43 invoked by user. QA agent successfully called mcp__pal-e-docs__get_note, mcp__forgejo__review_pr, and mcp__forgejo__comment_on_pr from inside forked context. MCP tools inherit correctly.
  • [x] Hook enforcement — PR #45 merged (2026-03-01). SubagentStart context injection + frontmatter PreToolUse hooks. All agents blocked from pal-e-docs writes. QA/Issue Creator blocked from Write/Edit/Bash. Verified live 2026-03-01.

Previous Plan

plan-2026-02-25-agent-profiles

Depends On

None.

Decisions Made

Decision Rationale
<strong>Enforcement stack: hooks are the only hard guarantee</strong> Agents wrap skills. Skills wrap MCP tools. But none of that is enforcement — it's organizational convenience. The only guaranteed enforcement mechanism is hooks (exit 2 blocks execution). Agent <code>disallowedTools</code> and skill <code>context: fork</code> are useful for organizing work but are not enforcement boundaries. True QA enforcement and template compliance must be done via hooks.
<strong>Ownership boundary: AI Agency owns SOPs, Claude Config enforces them</strong> Claude Config is the technical enforcement layer — hooks, frontmatter, settings.json. It implements SOPs; it doesn't own them. SOPs, agent profiles, skill definitions, templates, and architecture docs are owned by AI Agency. The boundary: "what should happen" = AI Agency, "how it's technically enforced" = Claude Config.
betty-sue.md stays as-is (no subagent frontmatter) Betty Sue is the main session personality injected via SessionStart hook, not a spawned subagent. Making it a subagent would conflict with the main session.
Use <code>disallowedTools</code> instead of <code>tools</code> for restricting agents Per docs: when <code>tools</code> is omitted, agents inherit ALL tools including MCP. Using <code>disallowedTools</code> is cleaner — block what you don't want. The <code>tools</code> field uses internal tool names only (Read, Grep, Glob, Bash, Edit, Write) — MCP tools are NOT listed in the <code>tools</code> field.
Use <code>mcpServers</code> to control MCP access per-agent Per docs: <code>mcpServers</code> field controls which MCP servers are available. Each entry is a server name referencing an already-configured server or inline definition.
<strong>SubagentStart CANNOT block — enforcement asymmetry (corrected 2026-03-01)</strong> Per official Claude Code docs (re-verified 2026-03-01): "SubagentStart hooks cannot block subagent creation." Exit code 2 only shows stderr to user. SubagentStart CAN inject <code>additionalContext</code> into the subagent. This means native delegation cannot be prevented — only guided. Previous plan incorrectly assumed SubagentStart could block via exit 2. All docs corrected.
<strong>Layered defense for native delegation</strong> Since SubagentStart can't block: (1) SubagentStart injects plan context via additionalContext — guidance, (2) Frontmatter PreToolUse hooks enforce tool restrictions inside agents — hard enforcement, (3) disallowedTools provides organizational belt to the frontmatter hook suspenders. This gives us hard tool enforcement even though we can't block the spawn itself.
<strong>Skills should use context: fork — CONFIRMED (2026-03-01)</strong> MCP-in-forked-context test passed. <code>/review-pr</code> invoked live, QA agent successfully used mcp__pal-e-docs__get_note, mcp__forgejo__review_pr, and mcp__forgejo__comment_on_pr from inside forked context. MCP tools inherit into forked subagent context. No revert needed.
<strong>No agent writes to pal-e-docs — broadened 2026-03-01</strong> Original constraint was "Dev agent can't update pal-e-docs notes." Broadened to: ALL agents are blocked from ALL pal-e-docs write operations (7 tools: create_note, update_note, delete_note, update_note_links, create_project, create_repo, update_repo). Rationale: main session owns docs, agents own repos. No exceptions.
<strong>disallowedTools strips tools from palette — discovered 2026-03-01</strong> Testing revealed that <code>disallowedTools</code> removes tools from the agent's tool palette entirely — the agent cannot even attempt the call. This is stronger than frontmatter PreToolUse hooks (which intercept the call). For internal tools (Write/Edit/Bash), disallowedTools is defense layer 1. For MCP tools, frontmatter PreToolUse hooks are defense layer 1 since disallowedTools can't filter individual MCP tools.
This is one plan, not a parent plan Everything here is one coherent fix: align ~/.claude/ files with Claude Code's actual feature set, and align pal-e-docs with reality. Splitting would create coordination overhead with no benefit.

Documentation Cross-Reference (re-verified 2026-03-01)

Claims verified against official Claude Code docs:

Subagent frontmatter (source)

  • Required fields: name (lowercase, hyphens) and description
  • tools field: Comma-separated internal tool names. Inherits ALL tools including MCP if omitted.
  • disallowedTools field: Tools to deny, removed from inherited or specified list. Verified: strips tools from palette entirely — agent cannot even attempt the call.
  • mcpServers field: Server name referencing already-configured server OR inline definition
  • isolation field: "worktree" for git worktree isolation
  • skills field: Skills to preload into context. Full content injected. Subagents don't inherit skills from parent.
  • memory field: user/project/local. Automatically enables Read/Write/Edit for memory management.
  • hooks field: PreToolUse, PostToolUse, Stop (converted to SubagentStop at runtime). Scoped to this subagent only. YAML syntax confirmed — same structure as settings.json but in YAML. Verified: PreToolUse hooks fire inside subagent context and block via exit 2.
  • background field: Set to true to always run as background task.
  • maxTurns field: Max agentic turns before subagent stops.
  • permissionMode field: default, acceptEdits, dontAsk, bypassPermissions, or plan.
  • Subagents cannot spawn other subagents.
  • Subagents receive only their system prompt + basic env, NOT the full Claude Code system prompt.

Frontmatter hooks syntax (confirmed 2026-03-01)

All hook events are supported in frontmatter. For subagents, Stop hooks are automatically converted to SubagentStop. Hooks use the same configuration format as settings-based hooks but are scoped to the component's lifetime.

Skill frontmatter (source)

  • No required fields. Only description is recommended.
  • context: fork: Runs in isolated subagent context. Skill content becomes the prompt. NO conversation history. Only works for skills with explicit task instructions.
  • agent: Which subagent type when context: fork. Built-in (Explore, Plan, general-purpose) OR custom from .claude/agents/.
  • disable-model-invocation: true: Only user can invoke.
  • argument-hint: Hint shown during autocomplete for expected arguments.
  • user-invocable: Set to false to hide from / menu.
  • allowed-tools: Tools Claude can use without asking permission.

Hooks (source)

  • SubagentStart: CANNOT block (exit 2 only shows stderr to user). CAN inject additionalContext. Supports matchers by agent type name. Command-only hook type.
  • SubagentStop: CAN block via decision: "block" (prevents subagent from stopping). Supports matchers by agent type name. All four hook types supported.
  • PreToolUse on Agent: CAN block. Enforcement point for "no plan, no agent" via manual Agent tool calls.
  • Subagent frontmatter hooks: PreToolUse, PostToolUse, Stop supported. Scoped to subagent lifetime only. Hard enforcement inside agents.

Phases

Phase 1: Agent frontmatter [DONE]

Slug: phase-2026-02-28-1-agent-frontmatter
Goal: Add YAML frontmatter to all agent .md files so Claude Code recognizes them as subagents.
Owner: Agent: Dev
Issue: #40 — combined with Phase 2
PR: #41 — merged

Phase 2: Skill frontmatter [DONE]

Slug: phase-2026-02-28-2-skill-frontmatter
Goal: Add YAML frontmatter to all skill SKILL.md files.
Owner: Agent: Dev
Issue: #40 — combined with Phase 1
PR: #41 — merged

Phase 3: Wire skills to agents — CONVENIENCE WIRING [DONE — FULLY VERIFIED]

Slug: phase-2026-02-28-3-skill-agent-wiring
Goal: Skills that spawn work should delegate to the correct agent via context: fork.
Layer: Convenience — routes work to the right agent but does NOT enforce anything. See enforcement stack in Decisions Made.
Owner: Agent: Dev
Issue: #42 / issue-claude-custom-skill-agent-wiring (resolved)
PR: #43 — merged. QA approved.
MCP-in-forked-context test: PASSED (2026-03-01). User invoked /review-pr forgejo_admin/claude-custom#43. QA agent ran inside forked context and successfully called mcp__pal-e-docs__get_note, mcp__forgejo__review_pr, and mcp__forgejo__comment_on_pr. MCP tools inherit into forked subagent context. Phase 3 is fully complete.

Phase 4: Docs, templates, and SOP alignment [DONE]

Slug: phase-2026-02-28-4-docs-alignment
Goal: Update ALL stale pal-e-docs notes to reflect reality. Reassign scattered notes to correct projects per ownership boundary. Purge deprecated agent names.
Owner: Main session (Betty Sue)
Completed: 2026-03-01
Deliverables:
  • 25+ notes reassigned from Claude Config/pal-e-docs to AI Agency project
  • "Devy"/"Mandy" purged from enforcement-architecture, agent-paradigm, agent-workflow, pr-lifecycle
  • template-agent — Frontmatter Fields section (12 YAML fields) + File Format section added
  • template-skill — Frontmatter Fields table (9 fields) + Wiring Pattern section + updated SKILL.md example with frontmatter
  • enforcement-architecture — Full rewrite: enforcement stack hierarchy, SubagentStart/SubagentStop in Pillar 1, mcpServers/disallowedTools in Pillar 4, "Two Spawn Paths" table
  • hook-events-reference — SubagentStart/SubagentStop rows fixed. Added detail section with matcher examples and input schema.
  • agent-workflow — "Two Spawn Paths" section added (manual vs native delegation)
  • agent-spawn-conventions — "Dual Enforcement" section + "Native Delegation vs Manual Spawning" comparison table
  • agent-dev, agent-qa, agent-issue-creator — Frontmatter Fields tables added with exact values from ~/.claude/agents/ files
  • convention-agent-skill-mcp-wiring — New convention note: full wiring pattern, enforcement stack, current wiring table, dual source of truth
  • todo-reassign-notes-to-ai-agency — marked done
Docs correction (2026-03-01): After Phase 4 completed, we verified against official Claude Code docs that SubagentStart CANNOT block — only inject context. Four notes corrected: hook-events-reference, enforcement-architecture, agent-spawn-conventions, convention-agent-skill-mcp-wiring. "Dual Enforcement" renamed to "Enforcement Asymmetry" across all docs.

Phase 5: Hook alignment — LAYERED DEFENSE [DONE — VERIFIED]

Slug: phase-2026-02-28-5-hook-alignment
Goal: Add SubagentStart context injection + frontmatter PreToolUse hooks for defense-in-depth. Manual spawns are already enforced (PreToolUse on Agent tool). Native delegation needs layered defense since SubagentStart cannot block.
Layer: Mixed — SubagentStart is guidance (additionalContext), frontmatter PreToolUse is hard enforcement (exit 2 blocks tool use).
Owner: Agent: Dev
Issue: #44 / issue-claude-custom-phase5-layered-defense-hooks (resolved)
PR: #45 — merged. QA approved (3 review rounds). Scope broadened during review: all agents blocked from all pal-e-docs writes (not just Dev from notes).
Enforcement Asymmetry (verified 2026-03-01):
Spawn path Can block spawn? Can inject context? Can enforce tool use?
Manual (Agent tool) <strong>Yes</strong> — PreToolUse deny Yes — via prompt Yes — PreToolUse hooks
Native delegation <strong>No</strong> — SubagentStart cannot block Yes — additionalContext Yes — frontmatter PreToolUse hooks
Live test results (2026-03-01):
Agent Action tested Result Enforcement layer
QA Write tool <strong>BLOCKED</strong> <code>disallowedTools</code> strips from palette — can't even attempt
QA Edit tool <strong>BLOCKED</strong> <code>disallowedTools</code> strips from palette
QA mcp__pal-e-docs__update_note <strong>BLOCKED</strong> Frontmatter PreToolUse hook (<code>block-docs-writes.sh</code>, exit 2)
Dev mcp__pal-e-docs__create_note <strong>BLOCKED</strong> Frontmatter PreToolUse hook (<code>block-docs-writes.sh</code>, exit 2)
Dev mcp__pal-e-docs__update_note <strong>BLOCKED</strong> Frontmatter PreToolUse hook (<code>block-docs-writes.sh</code>, exit 2)
Dev Write tool (no issue) <strong>BLOCKED</strong> Settings PreToolUse hook (<code>check-issue.sh</code> — bonus layer)
Dev Read tool <strong>ALLOWED</strong> No restriction — correct
Key finding: disallowedTools strips internal tools (Write/Edit/Bash) from the agent's tool palette entirely — the agent cannot even attempt the call. This is defense layer 1 for internal tools. For MCP tools, frontmatter PreToolUse hooks are defense layer 1 since disallowedTools cannot filter individual MCP tools (only mcpServers controls server-level access). The existing check-issue.sh hook provides a bonus layer for Dev's Write/Edit calls — they require an active issue even when the tool is available.

Key Files

Phase File Repo/Location Change
1 ~/.claude/agents/{qa,dev,issue-creator}.md claude-custom Add YAML frontmatter
2 ~/.claude/skills/*/SKILL.md (6 files) claude-custom Add YAML frontmatter
3 ~/.claude/skills/{review-pr,implement-phase,fix-review,create-issue}/SKILL.md claude-custom Add context: fork + agent (convenience)
4 ~25 pal-e-docs notes pal-e-docs Reassign to AI Agency project per ownership boundary
4 enforcement-architecture, agent-paradigm, agent-workflow, pr-lifecycle pal-e-docs Purge deprecated agent names, add enforcement stack
4 template-agent, template-skill pal-e-docs Add frontmatter sections
4 enforcement-architecture, hook-events-reference pal-e-docs Add enforcement stack, fix SubagentStart info
4 agent-workflow, agent-spawn-conventions pal-e-docs Add native delegation + enforcement asymmetry
4 agent-dev, agent-qa, agent-issue-creator pal-e-docs Add frontmatter fields tables
4 convention-agent-skill-mcp-wiring pal-e-docs New convention note
5 ~/.claude/hooks/inject-subagent-context.sh claude-custom New — SubagentStart context injection script
5 ~/.claude/settings.json claude-custom Add SubagentStart hook with matchers (context injection)
5 ~/.claude/hooks/block-write-tools.sh claude-custom New — blocks Write/Edit/Bash (for QA + Issue Creator frontmatter hooks)
5 ~/.claude/hooks/block-docs-writes.sh claude-custom New — blocks ALL pal-e-docs write MCP calls (for ALL agents)
5 ~/.claude/agents/{qa,dev,issue-creator}.md claude-custom Add frontmatter PreToolUse hooks (hard enforcement) — both write tools + docs writes

Verification

  • [x] claude agents lists qa, dev, issue-creator — PR #41 merged
  • [x] Ownership boundary documented on project-claude-config and project-ai-agency
  • [x] Enforcement stack documented (hooks > agents > skills > MCP)
  • [x] Skill-to-agent wiring merged — PR #43 (convenience layer)
  • [x] template-agent has frontmatter section — Phase 4
  • [x] template-skill has frontmatter section — Phase 4
  • [x] No deprecated agent names in any pal-e-docs note — Phase 4
  • [x] All operational notes assigned to AI Agency project per ownership boundary — Phase 4
  • [x] hook-events-reference shows SubagentStart CANNOT block + CAN inject context — corrected 2026-03-01
  • [x] enforcement-architecture includes enforcement asymmetry — corrected 2026-03-01
  • [x] agent-spawn-conventions documents enforcement asymmetry — corrected 2026-03-01
  • [x] MCP tools work inside forked subagent context — PASSED 2026-03-01. /review-pr invoked, QA agent used pal-e-docs + forgejo MCP successfully.
  • [x] /review-pr runs inside QA agent context via context: fork — verified 2026-03-01
  • [x] SubagentStart hook injects additionalContext into spawned agents — verified 2026-03-01. Both QA and Dev agents received context guidance on spawn.
  • [x] QA agent cannot use Write, Edit, or Bash — verified 2026-03-01. disallowedTools strips them from palette entirely.
  • [x] QA agent CAN use mcp__forgejo__review_pr and mcp__pal-e-docs__get_note — verified via /review-pr test 2026-03-01.
  • [x] Dev agent cannot write to pal-e-docs — verified 2026-03-01. block-docs-writes.sh blocks create_note, update_note with exit 2.
  • [x] Dev agent launches in worktree — verified 2026-03-01 during Phase 5 implementation (agent ran in isolation: worktree).
  • [x] Frontmatter PreToolUse hooks fire inside subagent context — VERIFIED 2026-03-01. QA: pal-e-docs update_note blocked. Dev: pal-e-docs create_note and update_note blocked. Hard enforcement working.
  • [x] All agents blocked from ALL pal-e-docs writes (7 tools) — broadened from "Dev only" to "all agents" during QA review 2026-03-01.

Next Plan Seeds

  • Agent memory: add memory: user to agents so they build knowledge over time
  • Background agents: evaluate background: true for Dev agent during long implementations
  • Agent teams: evaluate Claude Code agent teams feature for multi-agent parallel work
  • Plugin packaging: package agents + skills as a Claude Code plugin for portability
  • plan-2026-02-25-agent-profiles — previous plan
  • todo-fix-agent-skill-frontmatter — the TODO that triggered this
  • todo-reassign-notes-to-ai-agency — note project reassignment + deprecated name cleanup (DONE)
  • agent-workflow — operating model SOP (updated Phase 4)
  • agent-spawn-conventions — spawn axiom + enforcement asymmetry (corrected 2026-03-01)
  • enforcement-architecture — four pillars + enforcement asymmetry (corrected 2026-03-01)
  • hook-events-reference — event reference + SubagentStart cannot block (corrected 2026-03-01)
  • convention-agent-skill-mcp-wiring — wiring convention (corrected 2026-03-01)
  • template-agent — agent template (updated Phase 4)
  • template-skill — skill template (updated Phase 4)
  • project-ai-agency — project page (updated with ownership boundary)
  • project-claude-config — project page (updated with enforcement stack)
  • sop-claude-config-development — development SOP (accurate, no changes)
  • Claude Code subagent docs
  • Claude Code skills docs
  • Claude Code hooks docs
  • Claude Code permissions docs