Repository navigation
Add agents-md plugin: auto-load AGENTS.md at session start (#6235) #37241
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,6 +12,7 @@ Learn more in the [official plugins documentation](https://docs.claude.com/en/do | |
|
|
||
| | Name | Description | Contents | | ||
| |------|-------------|----------| | ||
| | [agents-md](./agents-md/) | Loads `AGENTS.md` files into context at session start, making Claude Code compatible with the cross-tool agent instruction standard used by Cursor, Codex, and Amp ([#6235](https://github.com/anthropics/claude-code/issues/6235)) | **Hook:** SessionStart - Injects `AGENTS.md` content as `additionalContext`, mirroring `CLAUDE.md` discovery | | ||
| | [agent-sdk-dev](./agent-sdk-dev/) | Development kit for working with the Claude Agent SDK | **Command:** `/new-sdk-app` - Interactive setup for new Agent SDK projects<br>**Agents:** `agent-sdk-verifier-py`, `agent-sdk-verifier-ts` - Validate SDK applications against best practices | | ||
| | [claude-opus-4-5-migration](./claude-opus-4-5-migration/) | Migrate code and prompts from Sonnet 4.x and Opus 4.1 to Opus 4.5 | **Skill:** `claude-opus-4-5-migration` - Automated migration of model strings, beta headers, and prompt adjustments | | ||
| | [code-review](./code-review/) | Automated PR code review using multiple specialized agents with confidence-based scoring to filter false positives | **Command:** `/code-review` - Automated PR review workflow<br>**Agents:** 5 parallel Sonnet agents for CLAUDE.md compliance, bug detection, historical context, PR history, and code comments | | ||
|
|
@@ -25,6 +26,7 @@ Learn more in the [official plugins documentation](https://docs.claude.com/en/do | |
| | [pr-review-toolkit](./pr-review-toolkit/) | Comprehensive PR review agents specializing in comments, tests, error handling, type design, code quality, and code simplification | **Command:** `/pr-review-toolkit:review-pr` - Run with optional review aspects (comments, tests, errors, types, code, simplify, all)<br>**Agents:** `comment-analyzer`, `pr-test-analyzer`, `silent-failure-hunter`, `type-design-analyzer`, `code-reviewer`, `code-simplifier` | | ||
| | [ralph-wiggum](./ralph-wiggum/) | Interactive self-referential AI loops for iterative development. Claude works on the same task repeatedly until completion | **Commands:** `/ralph-loop`, `/cancel-ralph` - Start/stop autonomous iteration loops<br>**Hook:** Stop - Intercepts exit attempts to continue iteration | | ||
| | [security-guidance](./security-guidance/) | Security reminder hook that warns about potential security issues when editing files | **Hook:** PreToolUse - Monitors 9 security patterns including command injection, XSS, eval usage, dangerous HTML, pickle deserialization, and os.system calls | | ||
| | [tmp-cwd-cleanup](./tmp-cwd-cleanup/) | Cleans up orphaned `/tmp/claude-*-cwd` files on session exit, working around a Bash tool memory leak ([#8856](https://github.com/anthropics/claude-code/issues/8856)) | **Hook:** Stop - Deletes accumulated working-directory tracking files owned by the current user | | ||
|
Comment on lines
27
to
+29
|
||
|
|
||
| ## Installation | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,9 @@ | ||||||||||||||||
| { | ||||||||||||||||
| "name": "agents-md", | ||||||||||||||||
| "version": "1.0.0", | ||||||||||||||||
| "description": "Automatically loads AGENTS.md files into context at session start, making Claude Code compatible with cross-tool agent instruction files used by Cursor, Codex, Amp, and others", | ||||||||||||||||
| "author": { | ||||||||||||||||
| "name": "Claude Code Community", | ||||||||||||||||
| "email": "" | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
Comment on lines
+6
to
+9
|
||||||||||||||||
| "name": "Claude Code Community", | |
| "email": "" | |
| } | |
| } | |
| "name": "Claude Code Community" | |
| } | |
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| # agents-md | ||
|
|
||
| Automatically loads `AGENTS.md` files into Claude Code's context at session start, making it compatible with the cross-tool agent instruction standard used by Cursor, OpenAI Codex, Amp, and others. | ||
|
|
||
| **Fixes:** [#6235 – Feature Request: Support AGENTS.md](https://github.com/anthropics/claude-code/issues/6235) | ||
|
|
||
| ## The problem | ||
|
|
||
| Claude Code reads `CLAUDE.md` (and `CLAUDE.local.md`) from the project directory tree to understand project-specific instructions. Most other AI coding tools use `AGENTS.md` for the same purpose — this is coalescing into a [cross-tool standard](https://agents.md/). | ||
|
|
||
| Without this plugin, teams that use both Claude Code and other tools must either: | ||
| - Maintain two separate instruction files (`CLAUDE.md` and `AGENTS.md`) in sync, or | ||
| - Symlink one to the other (fragile on Windows, confusing for contributors) | ||
|
|
||
| ## What this plugin does | ||
|
|
||
| Registers a `SessionStart` hook that mirrors Claude Code's own `CLAUDE.md` discovery logic: | ||
|
|
||
| 1. Walks up the directory tree from the project root, collecting every `AGENTS.md` found. | ||
| 2. Also checks `~/.claude/AGENTS.md` for user-level instructions. | ||
| 3. Injects all found content as `additionalContext` — the same mechanism used internally for `CLAUDE.md`. | ||
|
|
||
| The file lookup order (lowest → highest priority) matches `CLAUDE.md` precedence: | ||
|
|
||
| ``` | ||
| ~/.claude/AGENTS.md ← user-level (lowest priority) | ||
| /path/to/repo/AGENTS.md ← repo root | ||
| /path/to/repo/subdir/AGENTS.md ← subdirectory (highest priority) | ||
| ``` | ||
|
|
||
| ## Installation | ||
|
|
||
| Install via the `/plugin` command inside Claude Code: | ||
|
|
||
| ``` | ||
| /plugin install agents-md | ||
| ``` | ||
|
|
||
| Or add it manually to your `.claude/settings.json`: | ||
|
|
||
| ```json | ||
| { | ||
| "plugins": ["agents-md"] | ||
| } | ||
| ``` | ||
|
|
||
| ## Usage | ||
|
|
||
| Just drop an `AGENTS.md` in your project root (the same place you'd put `CLAUDE.md`) and start a Claude Code session. The file is loaded automatically — no configuration needed. | ||
|
|
||
| ``` | ||
| my-project/ | ||
| ├── AGENTS.md ← loaded by this plugin (and by Cursor, Codex, Amp, …) | ||
| ├── CLAUDE.md ← loaded natively by Claude Code | ||
| └── src/ | ||
| ``` | ||
|
|
||
| Both files are loaded; `CLAUDE.md` instructions take precedence where they overlap. | ||
|
|
||
| ## Hook | ||
|
|
||
| | Event | Effect | | ||
| |-------|--------| | ||
| | `SessionStart` | Finds and injects `AGENTS.md` file(s) as `additionalContext` | |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| { | ||
| "description": "Loads AGENTS.md files into context at session start, mirroring how Claude Code handles CLAUDE.md", | ||
| "hooks": { | ||
| "SessionStart": [ | ||
| { | ||
| "hooks": [ | ||
| { | ||
| "type": "command", | ||
| "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/load_agents_md.py" | ||
| } | ||
| ] | ||
| } | ||
| ] | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,109 @@ | ||||||||||||||||
| #!/usr/bin/env python3 | ||||||||||||||||
| """SessionStart hook: inject AGENTS.md files as additionalContext. | ||||||||||||||||
|
|
||||||||||||||||
| Claude Code natively reads CLAUDE.md (and CLAUDE.local.md) from the project | ||||||||||||||||
| tree and the user's ~/.claude/ directory. Many other AI coding tools — Cursor, | ||||||||||||||||
| OpenAI Codex, Amp, and others — use AGENTS.md for the same purpose, creating | ||||||||||||||||
| a cross-tool standard. | ||||||||||||||||
|
|
||||||||||||||||
| This hook mirrors Claude Code's own CLAUDE.md discovery logic: | ||||||||||||||||
| 1. Walk up from the project root, collecting every AGENTS.md found. | ||||||||||||||||
| 2. Also check ~/.claude/AGENTS.md for user-level instructions. | ||||||||||||||||
|
|
||||||||||||||||
| All found files are concatenated and injected via additionalContext so Claude | ||||||||||||||||
| sees them exactly as if they had been written in CLAUDE.md. | ||||||||||||||||
|
|
||||||||||||||||
| See: https://github.com/anthropics/claude-code/issues/6235 | ||||||||||||||||
| https://agents.md/ | ||||||||||||||||
| """ | ||||||||||||||||
|
|
||||||||||||||||
| import json | ||||||||||||||||
| import os | ||||||||||||||||
| import sys | ||||||||||||||||
| from pathlib import Path | ||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| FILENAME = "AGENTS.md" | ||||||||||||||||
| # Limit how many directory levels we climb (same spirit as CLAUDE.md behaviour). | ||||||||||||||||
| MAX_DEPTH = 20 | ||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| def find_agents_md_files(start_dir: Path) -> list[Path]: | ||||||||||||||||
| """Walk upward from start_dir collecting AGENTS.md files (innermost first).""" | ||||||||||||||||
| found: list[Path] = [] | ||||||||||||||||
|
Comment on lines
+31
to
+33
|
||||||||||||||||
| current = start_dir.resolve() | ||||||||||||||||
|
|
||||||||||||||||
| for _ in range(MAX_DEPTH): | ||||||||||||||||
| candidate = current / FILENAME | ||||||||||||||||
| if candidate.is_file(): | ||||||||||||||||
| found.append(candidate) | ||||||||||||||||
| parent = current.parent | ||||||||||||||||
| if parent == current: | ||||||||||||||||
| break # reached filesystem root | ||||||||||||||||
| current = parent | ||||||||||||||||
|
|
||||||||||||||||
| return found | ||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| def main() -> None: | ||||||||||||||||
| # Consume stdin (required by hook protocol). | ||||||||||||||||
| try: | ||||||||||||||||
| hook_input = json.load(sys.stdin) | ||||||||||||||||
| except Exception: | ||||||||||||||||
| hook_input = {} | ||||||||||||||||
|
Comment on lines
+51
to
+53
|
||||||||||||||||
| hook_input = json.load(sys.stdin) | |
| except Exception: | |
| hook_input = {} | |
| json.load(sys.stdin) | |
| except Exception: | |
| # Stdin may be empty or invalid; ignore to satisfy hook protocol. | |
| pass |
Copilot
AI
Mar 21, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The injected marker includes the full path (<!-- AGENTS.md: {path} -->), which will be an absolute path for ~/.claude/AGENTS.md and can leak the local username/home directory into the model context. Consider emitting only path.name or a redacted label like user-level / repo-root to preserve privacy.
| sections.append( | |
| f"<!-- AGENTS.md: {path} -->\n{content}" | |
| marker_source = "user-level" if path == user_file else "repo-root" | |
| sections.append( | |
| f"<!-- AGENTS.md: {marker_source} -->\n{content}" |
Copilot
AI
Mar 21, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Path.read_text(..., encoding="utf-8") can raise UnicodeDecodeError, which is not an OSError. A non-UTF8 AGENTS.md would crash the hook and potentially prevent context injection. Catch UnicodeDecodeError (or broader Exception) or pass errors="replace"/"ignore" to read_text so the hook remains non-fatal.
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,9 @@ | ||||||
| { | ||||||
| "name": "tmp-cwd-cleanup", | ||||||
| "version": "1.0.0", | ||||||
| "description": "Cleans up orphaned /tmp/claude-*-cwd working directory tracking files on session stop, working around a memory leak in the Bash tool (issue #8856)", | ||||||
|
||||||
| "description": "Cleans up orphaned /tmp/claude-*-cwd working directory tracking files on session stop, working around a memory leak in the Bash tool (issue #8856)", | |
| "description": "Cleans up orphaned /tmp/claude-*-cwd working directory tracking files on session stop, working around a filesystem/resource leak in the Bash tool (issue #8856)", |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| # tmp-cwd-cleanup | ||
|
|
||
| A workaround plugin for [issue #8856](https://github.com/anthropics/claude-code/issues/8856): the Bash tool creates a `/tmp/claude-<hex>-cwd` file after every shell command to track the working directory, but never deletes it. On active systems these files accumulate into the thousands and eventually slow down `/tmp` lookups. | ||
|
|
||
| ## What it does | ||
|
|
||
| Registers a **Stop hook** that deletes all `/tmp/claude-*-cwd` files owned by the current user when the Claude Code session ends. | ||
|
|
||
| ``` | ||
| /tmp/claude-02a6-cwd (22 bytes — deleted on exit) | ||
| /tmp/claude-1f3b-cwd (22 bytes — deleted on exit) | ||
| ... | ||
| ``` | ||
|
|
||
| ## Installation | ||
|
|
||
| Install via the `/plugin` command inside Claude Code: | ||
|
|
||
| ``` | ||
| /plugin install tmp-cwd-cleanup | ||
| ``` | ||
|
|
||
| Or add it manually to your `.claude/settings.json`: | ||
|
|
||
| ```json | ||
| { | ||
| "plugins": ["tmp-cwd-cleanup"] | ||
| } | ||
| ``` | ||
|
|
||
| ## Notes | ||
|
|
||
| - Only removes files owned by the **current user** (safe on shared systems). | ||
| - Exits `0` so it never blocks session teardown. | ||
| - This plugin is a stopgap; the proper fix is to call `unlinkSync` in the Bash tool implementation immediately after reading the cwd file ([upstream tracking issue #8856](https://github.com/anthropics/claude-code/issues/8856)). | ||
|
|
||
| ## Hook | ||
|
|
||
| | Event | Matcher | Effect | | ||
| |-------|---------|--------| | ||
| | `Stop` | _(all)_ | Deletes `/tmp/claude-*-cwd` files owned by current user | | ||
|
Comment on lines
+39
to
+41
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| #!/usr/bin/env python3 | ||
| """Stop hook: clean up orphaned /tmp/claude-*-cwd files. | ||
|
|
||
| The Bash tool writes a small temp file to /tmp/claude-<hex>-cwd after each | ||
| command to capture the resulting working directory, but never deletes it. | ||
| On active systems these files accumulate into the thousands and eventually | ||
| slow down /tmp lookups (see issue #8856). | ||
|
|
||
| This hook runs on session Stop and removes any such files owned by the | ||
| current user, providing a clean-up path until the upstream fix lands. | ||
| """ | ||
|
|
||
| import glob | ||
| import json | ||
| import os | ||
| import sys | ||
|
|
||
|
|
||
| def main() -> None: | ||
| # Consume stdin (required by the hook protocol) but we don't need it. | ||
| try: | ||
| json.load(sys.stdin) | ||
| except Exception: | ||
| pass | ||
|
|
||
| uid = os.getuid() if hasattr(os, "getuid") else None # no-op on Windows | ||
| removed = 0 | ||
| errors = 0 | ||
|
|
||
| for path in glob.glob("/tmp/claude-*-cwd"): | ||
| try: | ||
| # Only remove files owned by the current user (safety check). | ||
| if uid is not None and os.stat(path).st_uid != uid: | ||
| continue | ||
| if os.path.isfile(path): | ||
| os.unlink(path) | ||
| removed += 1 | ||
| except OSError: | ||
| errors += 1 | ||
|
|
||
| # Exit 0 so the Stop event is never blocked. | ||
| # Optionally surface a brief summary via systemMessage. | ||
| if removed > 0: | ||
| result = {"systemMessage": f"tmp-cwd-cleanup: removed {removed} orphaned file(s)."} | ||
| if errors: | ||
| result["systemMessage"] += f" ({errors} error(s) skipped)" | ||
| print(json.dumps(result)) | ||
|
|
||
| sys.exit(0) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| { | ||
| "description": "Cleans up orphaned /tmp/claude-*-cwd working directory tracking files when the session stops", | ||
| "hooks": { | ||
| "Stop": [ | ||
| { | ||
| "hooks": [ | ||
| { | ||
| "type": "command", | ||
| "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/cleanup_cwd_files.py" | ||
| } | ||
| ] | ||
| } | ||
| ] | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This entry describes the underlying issue as a "memory leak", but the plugin behavior and README describe a
/tmpfile accumulation problem. Consider adjusting the wording here as well to avoid misleading users.