Files
ClaudeForge/agent/CLAUDE.md
T
Claude 0a34178e22 feat(plugin): fix guardian hooks, add InstructionsLoaded enforcement, .claude/rules emitter, AGENTS.md interop
Closes the gap between ClaudeForge and the Anthropic docs at
code.claude.com/docs/en/memory (and its linked hooks / skills / plugins
pages). Five tightly-scoped changes, each verified by smoke test.

A. Fix guardian hook frontmatter shape (agent/claude-md-guardian.md)

   The previous array-of-{event, commands} shape did not match the
   documented schema (hooks: { EventName: [{ matcher, hooks: [{ type,
   command }] }] }), so the guardian's hooks silently did not fire.
   Rewritten to the canonical keyed-object shape with PostToolUse,
   PreToolUse, SessionStart, and the new InstructionsLoaded event.

B+C. Plugin-level hooks/hooks.json + hooks/validate-claude-md.py

   New deterministic enforcement of the 150-line cap. The validator
   script reads the hook payload from stdin, extracts any referenced
   CLAUDE.md path (supports both PostToolUse tool_input.file_path and
   InstructionsLoaded path / file shapes), and exits 2 with stderr
   feedback when the file is over 150 lines. Wired to both PostToolUse
   on Write|Edit and InstructionsLoaded on every load_reason
   (session_start, nested_traversal, path_glob_match, include, compact).
   The cap is now enforced at every load *and* write, not only when the
   guardian decides to run sync.

D. ContentGenerator.generate_rules_file() (skill/generator.py)

   Emits path-scoped .claude/rules/*.md instruction files with name,
   description, and paths: glob frontmatter. Claude loads these
   lazily — only when accessing files matching the globs — so
   file-type-specific guidance no longer has to live in the root
   CLAUDE.md. Validates that paths is non-empty (ValueError otherwise).

E. AGENTS.md / .cursorrules / .windsurfrules interop

   command/enhance-claude-md.md Phase 1 now lists which sibling
   instruction files exist. ContentGenerator.generate_root_file() reads
   project_context['existing_instruction_files'] and prepends an
   ## External Instructions section with @AGENTS.md (etc.) imports, so
   repos already using other agent tooling can adopt ClaudeForge
   without losing their existing instructions.

Smoke tests (all pass):
- Guardian hooks frontmatter parses as a dict with 4 events, each
  carrying matcher + nested hooks array of {type, command} entries.
- hooks.json is valid JSON; PostToolUse matcher = Write|Edit;
  InstructionsLoaded matcher covers all five load_reason values.
- validate-claude-md.py: small file -> rc 0, bloated file (200 lines)
  -> rc 2 with stderr referencing the 150 cap, InstructionsLoaded
  payload shape also handled, non-CLAUDE.md paths ignored, no stdin
  -> rc 0.
- generate_rules_file emits valid frontmatter with paths glob and
  raises ValueError when paths is empty.
- generate_root_file inserts @AGENTS.md and @.cursorrules imports
  when existing_instruction_files lists them; omits the section
  otherwise.
- Regression: large-fullstack root still 52 lines with chain imports
  intact; all five sub-CLAUDE.md files in this repo still pass
  validator (status = pass).

Docs:
- agent/CLAUDE.md updated to show the canonical hook shape and the
  hook-driven validator wiring.
- skill/CLAUDE.md notes generate_rules_file and AGENTS.md interop.
- CHANGELOG.md documents all five changes under Unreleased.
2026-05-19 02:04:00 +00:00

76 lines
3.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
> Parent context: see the root [CLAUDE.md](../CLAUDE.md) for project-wide guidelines and behavioural rules.
> Chained import: `@../CLAUDE.md`
# Guardian Agent Development
Guidelines for the `claude-md-guardian` background-maintenance agent.
## File
`agent/claude-md-guardian.md` — installs to `~/.claude/agents/claude-md-guardian.md`.
## Modifying the Agent
1. Edit `agent/claude-md-guardian.md`.
2. YAML frontmatter fields to preserve:
- `permissions: [Bash, Read, Write, Edit, Grep, Glob, Skill]`
- `model: haiku` — token efficiency for routine sync runs.
- `color: purple` — visual indicator in Claude Code UI.
- `fork_safe: true` — agent runs independently.
- `hooks: [SessionStart, PreToolUse, PostToolUse]`.
3. Workflow phases inside the agent:
- **Assessment** — read `git diff` / `git status` / changed-file counts.
- **Analysis** — decide if changes are significant enough to update CLAUDE.md.
- **Update** — invoke the skill for targeted section updates rather than full regeneration (~7080% token saving vs. rewrite).
4. Re-install for testing: `cp agent/claude-md-guardian.md ~/.claude/agents/`.
## v2.0.0+ Frontmatter Reference
Hooks use Anthropic's canonical keyed-object schema (event → array of `{ matcher, hooks: [{ type, command }] }`):
```yaml
hooks:
PostToolUse:
- matcher: "Write|Edit"
hooks:
- type: command
command: "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/validate-claude-md.py"
InstructionsLoaded:
- matcher: "session_start|nested_traversal|path_glob_match|include|compact"
hooks:
- type: command
command: "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/validate-claude-md.py"
```
The array-of-`{event, commands}` shape used in earlier versions did not match the documented schema and silently did not fire.
## Skill ↔ Agent Integration
The agent uses `claude-md-enhancer` (the skill's frontmatter name; installed as `claudeforge-skill/`) as its core capability. Invoke it with `Skill: claude-md-enhancer` inside the agent workflow.
Hook responsibilities:
- **SessionStart** — check `git diff`; if significant drift is detected, invoke the skill for an incremental update.
- **PreToolUse** — validate before a CLAUDE.md edit lands.
- **PostToolUse** — after `Edit`/`Write` to any CLAUDE.md, the plugin-level `hooks/hooks.json` runs `hooks/validate-claude-md.py`. The script exits `2` with stderr feedback when the file is over 150 lines; the guardian then proposes a `/sync-claude-md` run.
- **InstructionsLoaded** — same script fires on every `load_reason` (`session_start`, `nested_traversal`, `path_glob_match`, `include`, `compact`), so the cap is enforced deterministically at load time, not just at write time.
## Agent ↔ Git
The agent watches for change signals via:
```bash
git diff --name-status HEAD~10
git log --since="1 week ago" --oneline --no-merges
git diff HEAD~10 -- package.json requirements.txt pyproject.toml go.mod Cargo.toml
```
Triggers an update when any of these hold:
- 5+ files modified since the last sync.
- New dependencies added to a manifest file.
- New top-level directories created (potential new sub-CLAUDE.md candidates).
- Manual invocation after a milestone or release.
When the agent runs sync, it follows `command/sync-claude-md.md`: never commit, leave the diff for the user to review.