Commit Graph

4 Commits

Author SHA1 Message Date
Claude 7d22a50c37 feat(plugin): /claude-to-agents — convert CLAUDE.md to AGENTS.md for codex / gemini users
Cross-tool adoption. Codex, Gemini Code Assist, and any AI tool honouring
the AGENTS.md convention can now read the same instructions as Claude,
without the user maintaining two files by hand.

hooks/claude-to-agents.py (new, standalone, idempotent):
  - argparse: --mode={symlink,copy,inline-chain} (default symlink),
    --source (default CLAUDE.md), --output (default AGENTS.md), --force.
  - Symlink mode: ln -s CLAUDE.md AGENTS.md. Windows falls back to
    --copy with a stderr notice.
  - Copy mode: byte-for-byte snapshot via shutil.copyfile.
  - Inline-chain mode: depth-first walk of @path imports, recursive,
    cycle-safe (each file read at most once). Output flattens every
    chained sub-file under <!-- inlined from <rel> --> markers and
    strips two flavours of Claude-only scaffolding:
      • The @path import lines themselves (other tools don't resolve
        them).
      • Backlink quote-blocks ("> Parent context: ..." /
        "> Chained import: `@../CLAUDE.md`") that we emit on every
        sub-CLAUDE.md.
  - Safety: existing AGENTS.md (file or symlink) is renamed to
    AGENTS.md.backup.<UTC-ts> before overwrite. --force skips the
    backup. Microsecond timestamp precision so back-to-back writes
    don't collide.
  - Exit codes: 0 success, 1 user error (missing source / unknown
    mode), 2 filesystem error (symlink failure).

command/claude-to-agents.md (new slash command):
  - allowed-tools: Read, Write, Glob, Bash(python3:*), Bash(ls:*),
    Bash(test:*), Bash(readlink:*).
  - disallowedTools: WebFetch, WebSearch (no exfiltration vector).
  - argument-hint and when_to_use surface the three modes.
  - Body specifies a heuristic: default to --symlink for single-file
    projects, recommend --inline-chain when find . -name CLAUDE.md
    returns more than one. Documents per-mode verification commands.

.claude-plugin/plugin.json:
  Registers ./command/claude-to-agents.md alongside the existing two.

install.sh + install.ps1:
  Banner and uninstall sections list the new command. The command
  install loop already iterates command/*.md so the file itself is
  copied automatically.

README.md:
  /claude-to-agents added to "What's Included" under Slash commands
  with a one-paragraph description covering all three modes.
  Quick Stats: "2 slash commands" -> "3 slash commands".

CHANGELOG.md:
  New "wave 5" entry under [Unreleased].

Verified (7/7 integration checks):
  - Plugin manifest registers the command; all 9 referenced paths
    resolve on disk.
  - Slash command frontmatter has all required fields including
    WebFetch in disallowedTools.
  - Script has executable bit set.
  - Both install scripts list claude-to-agents.md.
  - install.sh passes bash -n.
  - End-to-end against a synthetic chained CLAUDE.md tree with a
    deliberate back-import cycle: symlink mode creates valid symlink;
    copy mode produces bytewise-identical AGENTS.md and backs up the
    prior symlink (1 backup); inline-chain mode inlines both
    sub-files, strips backlinks AND chain-import lines, handles the
    cycle (each file read once), backs up the prior file (2 backups
    total).
  - Missing source returns rc=1 with stderr message.
2026-05-19 02:04:00 +00:00
Claude e33fa8326b feat(plugin): command metadata, scoped skills, local-tier support, layered hooks, Stop audit
Wave 3 - adoption hardening. Patterns adapted (in original prose, with
attribution) from MIT-licensed shanraisshan/claude-code-best-practice.

Commands (command/enhance-claude-md.md, command/sync-claude-md.md):
- Add allowed-tools / disallowedTools / argument-hint / when_to_use so the
  commands auto-suggest in the slash menu and avoid permission prompts.
- disallowedTools blocks WebFetch + WebSearch on both commands.
- Drop the previous broken hooks block (array-of-{matcher, commands} shape
  did not match canonical schema; was never firing).

Skills:
- skill/karpathy-guidelines/SKILL.md: paths: glob over 23 code-file
  extensions, so the guardrails auto-load only when editing source, not
  markdown or data.
- skill/SKILL.md: model: haiku, effort: medium, paths: scoped to CLAUDE.md
  + AGENTS.md + .claude/rules/*.md so validator/generator passes run
  cheaply without changing the user-facing model.

CLAUDE.local.md personal tier:
- skill/validator.py BestPracticesValidator now accepts filename=; any
  *.local.md basename waives the 150-line cap.
- hooks/validate-claude-md.py reads the exempt suffix from hooks-config.
- .gitignore covers CLAUDE.local.md, **/CLAUDE.local.md,
  .claude/settings.local.json, hooks/hooks-config.local.json.

Layered hook config:
- hooks/hooks-config.json: committed defaults
  (validateClaudeMd.enabled/maxLines/exemptFilenameSuffix/exitCodeOnViolation,
  stopAuditLine.enabled).
- hooks/validate-claude-md.py merges hooks-config.json +
  hooks-config.local.json key-by-key; honours enabled=false (silent
  exit 0), configurable cap, configurable exit code.

Stop audit hook:
- hooks/audit-claude-md.py walks the project tree, prints one stderr
  line: total tracked / OVER cap / near cap (>=80%). Respects
  stopAuditLine.enabled from config.
- hooks/hooks.json registers Stop event with matcher "".

Guardian fail-closed contract:
- agent/claude-md-guardian.md Safety & Validation section now explicitly
  requires Skill-tool invocation (no inline paraphrase of SKILL.md),
  abort on missing validated output, never auto-commit, and respect
  local hook config.

Verified (8/8 smoke tests):
- Both commands parse with new fields and no broken hooks block.
- karpathy paths: 23 globs, includes .py/.ts/.go/.rs.
- skill model=haiku effort=medium with CLAUDE.md path scope.
- Validator: *.local.md (300 lines) -> pass; CLAUDE.md (300) -> fail;
  legacy ctor without filename -> default behavior preserved.
- hooks-config.json valid; validateClaudeMd.enabled=true, maxLines=150.
- Hook validator: default rc=2 on bloated, rc=0 when local override
  disables it, rc=0 on *.local.md (exempt).
- Stop hook entry present; audit script: rc=0 with "5 CLAUDE.md tracked".
- Regression: large-fullstack root still 52 lines with chain imports.
2026-05-19 02:04:00 +00:00
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
Reza Rezvani 37422c1667 Initial commit: ClaudeForge v1.0.0 2025-11-12 11:19:48 +01:00