Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions plugins/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand All @@ -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 |

Copilot AI Mar 21, 2026

Copy link

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 /tmp file accumulation problem. Consider adjusting the wording here as well to avoid misleading users.

Suggested change
| [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 |
| [tmp-cwd-cleanup](./tmp-cwd-cleanup/) | Cleans up orphaned `/tmp/claude-*-cwd` files on session exit, working around a Bash tool `/tmp` file accumulation issue ([#8856](https://github.com/anthropics/claude-code/issues/8856)) | **Hook:** Stop - Deletes accumulated working-directory tracking files owned by the current user |

Copilot uses AI. Check for mistakes.
Comment on lines 27 to +29

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR title/description focus on adding the agents-md plugin, but this change also adds a new tmp-cwd-cleanup plugin entry. Either update the PR description/title to include this additional plugin, or split it into a separate PR to keep review scope clear.

Copilot uses AI. Check for mistakes.

## Installation

Expand Down
9 changes: 9 additions & 0 deletions plugins/agents-md/.claude-plugin/plugin.json
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

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

author.email is present but set to an empty string. Elsewhere in this repo, plugin manifests either provide a real email (e.g., plugins/security-guidance/.claude-plugin/plugin.json:5-8, plugins/hookify/.claude-plugin/plugin.json:5-8) or omit optional fields. Consider removing the email field when unknown to avoid publishing empty contact metadata.

Suggested change
"name": "Claude Code Community",
"email": ""
}
}
"name": "Claude Code Community"
}
}

Copilot uses AI. Check for mistakes.
64 changes: 64 additions & 0 deletions plugins/agents-md/README.md
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` |
15 changes: 15 additions & 0 deletions plugins/agents-md/hooks/hooks.json
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"
}
]
}
]
}
}
109 changes: 109 additions & 0 deletions plugins/agents-md/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

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

list[Path] / list[str] type hints require Python 3.9+. Other plugin hook scripts avoid this, so this hook may fail on systems where python3 is 3.8 (e.g., Ubuntu 20.04) with a SyntaxError before it can emit hook output. Use typing.List/typing.Sequence annotations or remove these subscripting type hints to keep compatibility.

Copilot uses AI. Check for mistakes.
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

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hook_input is loaded but never used. If the intent is only to consume stdin per the hook protocol, consider dropping the assignment and just calling json.load(sys.stdin) (or reading and ignoring) to avoid dead code.

Suggested change
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 uses AI. Check for mistakes.

# Determine the project root. The hook runs with cwd set to the project
# directory; fall back to CLAUDE_PROJECT_ROOT if provided.
project_root_env = os.environ.get("CLAUDE_PROJECT_ROOT", "")
start_dir = Path(project_root_env) if project_root_env else Path.cwd()

# 1. Collect project-tree AGENTS.md files (closest → furthest from root).
project_files = find_agents_md_files(start_dir)

# 2. User-level AGENTS.md at ~/.claude/AGENTS.md (lowest priority).
user_file = Path.home() / ".claude" / FILENAME
user_files = [user_file] if user_file.is_file() else []

# Final order: user-level first (lowest priority), then project files
# from outermost → innermost (matching how CLAUDE.md precedence works).
all_files = user_files + list(reversed(project_files))

if not all_files:
# Nothing to inject — exit silently.
sys.exit(0)

# Read and concatenate.
sections: list[str] = []
for path in all_files:
try:
content = path.read_text(encoding="utf-8").strip()
if content:
sections.append(
f"<!-- AGENTS.md: {path} -->\n{content}"
Comment on lines +81 to +82

Copilot AI Mar 21, 2026

Copy link

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.

Suggested change
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 uses AI. Check for mistakes.
)
except OSError:
pass # Unreadable file — skip silently.
Comment on lines +77 to +85

Copilot AI Mar 21, 2026

Copy link

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.

Copilot uses AI. Check for mistakes.

if not sections:
sys.exit(0)

combined = "\n\n".join(sections)
context = (
"The following instructions come from AGENTS.md file(s) found in this "
"project. AGENTS.md is a cross-tool standard (used by Cursor, Codex, "
"Amp, and others) equivalent to CLAUDE.md. Treat these instructions "
"with the same weight as CLAUDE.md:\n\n" + combined
)

output = {
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": context,
}
}
print(json.dumps(output))
sys.exit(0)


if __name__ == "__main__":
main()
9 changes: 9 additions & 0 deletions plugins/tmp-cwd-cleanup/.claude-plugin/plugin.json
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)",

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The description calls this a "memory leak", but the plugin appears to address orphaned temp files accumulating in /tmp (a filesystem/resource leak). Consider updating wording to avoid misleading users about the failure mode.

Suggested change
"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)",

Copilot uses AI. Check for mistakes.
"author": {
"name": "Claude Code Community",
"email": ""
Comment thread
YoshKoz marked this conversation as resolved.
Resolved
}
}
41 changes: 41 additions & 0 deletions plugins/tmp-cwd-cleanup/README.md
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

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The markdown table in the Hook section starts with || ..., which renders as an extra empty column in most Markdown parsers. Other plugin READMEs in this repo use single leading pipes for tables (e.g., plugins/hookify/README.md). Consider switching to | Event | ... | formatting so the table renders correctly.

Copilot uses AI. Check for mistakes.
53 changes: 53 additions & 0 deletions plugins/tmp-cwd-cleanup/hooks/cleanup_cwd_files.py
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()
15 changes: 15 additions & 0 deletions plugins/tmp-cwd-cleanup/hooks/hooks.json
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"
}
]
}
]
}
}
Loading