agents-md-loader #
A Claude Code plugin that automatically loads AGENTS.md files into context.
Why #
The coding harness ecosystem is has largely standardized on AGENTS.md
as a README for agents. However, Anthropic obstinately refuses
to support this, insisting on naming the file CLAUDE.md.
This means that developers who use Claude Code, like myself, resort to awkwardly asking
projects to symlink their AGENTS.md files to CLAUDE.md. I have made this request many times! But really,
I am the one who insists on using a non-standard coding harness, so it's
somewhat rude to ask projects to accommodate me.
This plugin fixes that, as far as is possible: it adds hooks to Claude Code
that automatically read AGENTS.md files most of the time when the harness would
normally read CLAUDE.md.
This plugin needs no per-repo setup and also handles nested AGENTS.md
files in subdirectories, matching how Claude Code lazily loads nested
CLAUDE.md files.
Installation #
From inside Claude Code:
/plugin marketplace add https://tangled.org/btao.org/claude-agents-md-loader.git
/plugin install agents-md-loader@btao
/reload-plugins
After installing, start a new session so the SessionStart hook fires.
To update later, after new commits are pushed:
/plugin marketplace update btao
How it works #
The plugin registers three hooks:
| Hook | Trigger | What it loads |
|---|---|---|
SessionStart |
session start / resume / clear / compact | every AGENTS.md from the working directory up to the filesystem root (loaded in full at launch) |
PreToolUse (Read/Edit/Write/MultiEdit/NotebookEdit) |
before Claude touches a file | any AGENTS.md in that file's directory chain that hasn't been loaded yet (on-demand, for subdirectories) |
UserPromptSubmit |
when you submit a prompt containing @path mentions |
any not-yet-loaded AGENTS.md in the directory chain of each mentioned file. @-mentions are read directly by Claude Code, bypassing the PreToolUse hook, so this closes that gap. Only @-tokens pointing at an existing file/dir count |
Each AGENTS.md is injected at most once per session via
hookSpecificOutput.additionalContext. Already-loaded files are tracked in a
per-session state file under $TMPDIR/agents-md-loader/. After /compact or
/clear, SessionStart re-fires (with source compact/clear) and the
state is reset, so AGENTS.md re-injects — mirroring how Claude Code re-reads
CLAUDE.md from disk at those moments. /resume keeps context intact, so it
does not reset.
Parity with CLAUDE.md — and its limits #
| CLAUDE.md behavior | This plugin | Notes |
|---|---|---|
| Root + ancestor files loaded at startup | ✅ faithful | via SessionStart |
| Nested files loaded when Claude works in a subtree | ⚠️ approximate | triggered by Read/Edit/Write/MultiEdit/NotebookEdit and by @path mentions in a prompt |
Re-injected after /compact or /clear |
✅ faithful | SessionStart re-fires with source=compact/clear; the state file is reset so every AGENTS.md re-injects. resume keeps context, so it does not reset. |
No double-load when CLAUDE.md already covers it |
✅ faithful | an AGENTS.md is skipped when a sibling CLAUDE.md is identical to it (e.g. symlinked) or @-imports it (the @AGENTS.md workaround), since Claude Code loads that CLAUDE.md — and its imports — itself |
Known limitations:
- It can't hook the literal "instructions are being read" moment — the
InstructionsLoadedhook cannot inject context. So it may not match Claude Code's behavior 100% of the time. - Nested loading triggers on the file tools listed above and on
@pathmentions in a prompt. ABashcommand likecd subdir && ...or aGrep/Globthat merely surfaces files in a subtree will not trigger a nested load the way Claude's internal file-access tracking does. @-mention loading matches the literal@tokentext (only when the path exists), so a stray@tokenthat happens to name a real directory will still load itsAGENTS.mdchain.
Requirements #
- Claude Code with plugin + hooks support.
jq(brew install jq)bash.
Development #
Run the test suite (needs only bash + jq):
tests/run.sh