-
Notifications
You must be signed in to change notification settings - Fork 594
refactor: rework claude files #22473
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
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| # `.claude/` | ||
|
|
||
| Project-level Claude Code configuration for aztec-packages. This file documents layout decisions; the filesystem describes the contents. | ||
|
|
||
| ## Layout rules | ||
|
|
||
| 1. Universal content lives at repository root: `CLAUDE.md`, `.claude/agents/`, `.claude/scripts/`, and the root `settings.json` hooks. | ||
| 2. Subdirectory `.claude/` directories hold only component-specific skills, permission allowlists, and settings. Content is not merged upward. | ||
| 3. A subdirectory that has its own `.claude/` must symlink `agents/` to the repository root's `.claude/agents/`. Claude Code's ancestor walk stops at the nearest `.claude/` and does not merge ancestors, so subdirectories otherwise shadow the root agents. Subdirectories without their own `.claude/` inherit the root automatically. `skills/` is intentionally *not* symlinked — skills are scoped to their subdir (root skills are repo-wide workflows; `yarn-project/.claude/skills/` are TS-specific; etc.). | ||
| 4. Prefer XML-tagged sections inside `CLAUDE.md` for prose guidance. A `.claude/rules/` directory is only warranted when a rule needs YAML frontmatter (e.g. path-scoped `paths:` metadata) that `CLAUDE.md` cannot express. `.claude/rules/` without frontmatter does not auto-load when Claude Code is started from a subdirectory, so plain rules files are strictly worse than inlining into `CLAUDE.md`. | ||
|
|
||
| ## Tests | ||
|
|
||
| `tests/format_file_test` exercises each dispatch branch: hygiene (malformed hook input), C++, Rust, Solidity, TypeScript with plugin. Invocation via `./.claude/bootstrap.sh test_cmds` follows the same convention as `ci3/bootstrap.sh`. | ||
|
|
||
| ## Adding new files | ||
|
|
||
| - A new agent used repository-wide: `.claude/agents/` at root. | ||
| - A new skill scoped to one component: `component/.claude/skills/`. | ||
| - A new hook: add a script to `.claude/scripts/`, register it in `.claude/settings.json` via `git rev-parse --show-toplevel` so the path resolves from any cwd, and add a test in `.claude/tests/`. You need to add it to each subdirectory where you want the hook active. | ||
| - A new `.claude/` subdirectory: symlink `agents/` back to the repository root's `.claude/agents/`. |
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| #!/usr/bin/env bash | ||
| # Bootstrap + test entry for the .claude/ tooling directory. Mirrors the shape | ||
| # used by ci3/bootstrap.sh: emits test commands via `test_cmds`, runs them via | ||
| # `test`. Keeps hook scripts and their tests as a self-contained component. | ||
| source $(git rev-parse --show-toplevel)/ci3/source_bootstrap | ||
|
|
||
| hash=$(cache_content_hash ^.claude) | ||
|
|
||
| function test_cmds { | ||
| # source_base cd's us into .claude/, so glob relative-to-here, but emit paths | ||
| # relative to the git root (same convention used by ci3/bootstrap.sh). | ||
| for f in tests/*; do | ||
| [[ -x "$f" ]] || continue | ||
| echo "$hash ./.claude/$f" | ||
| done | ||
| } | ||
|
|
||
| function test { | ||
| echo_header ".claude tests" | ||
| test_cmds | filter_test_cmds | parallelize | ||
| } | ||
|
|
||
| case "$cmd" in | ||
| "") | ||
| test | ||
| ;; | ||
| *) | ||
| default_cmd_handler "$@" | ||
| ;; | ||
| esac |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| #!/usr/bin/env bash | ||
| # PostToolUse hook: format files after Edit/Write by dispatching to the right | ||
| # formatter based on extension. Reads Claude Code's hook JSON from stdin. | ||
| # | ||
| # Never fails the edit — prints hints to stderr on missing tools and exits 0. | ||
|
|
||
| set -u | ||
|
|
||
| input=$(cat) | ||
| file=$(printf '%s' "$input" | jq -r '.tool_input.file_path // empty') | ||
|
|
||
| [[ -z "$file" ]] && exit 0 | ||
| [[ ! -f "$file" ]] && exit 0 | ||
|
|
||
| hint() { printf 'format-file.sh: %s\n' "$*" >&2; } | ||
|
|
||
| case "$file" in | ||
| *.ts|*.tsx|*.js|*.jsx|*.mjs|*.cjs|*.json) | ||
| root="" | ||
| if [[ -n "${CLAUDE_PROJECT_DIR:-}" ]] && [[ -f "$CLAUDE_PROJECT_DIR/yarn-project/package.json" ]]; then | ||
| root="$CLAUDE_PROJECT_DIR" | ||
| else | ||
| root=$(git -C "$(dirname "$file")" rev-parse --show-toplevel 2>/dev/null || true) | ||
| fi | ||
| if [[ -n "$root" && -x "$root/yarn-project/node_modules/.bin/prettier" ]]; then | ||
| "$root/yarn-project/node_modules/.bin/prettier" --write --log-level=warn "$file" \ | ||
| || hint "prettier failed on $file" | ||
| else | ||
| hint "prettier not found — run yarn-project bootstrap to enable format-on-edit" | ||
| fi | ||
| ;; | ||
| *.cpp|*.cxx|*.cc|*.hpp|*.hxx|*.h) | ||
| cf="" | ||
| if command -v clang-format-20 >/dev/null 2>&1; then | ||
| cf=clang-format-20 | ||
| elif [[ -x /opt/homebrew/opt/llvm/bin/clang-format ]] && /opt/homebrew/opt/llvm/bin/clang-format --version 2>/dev/null | grep -q 'version 20'; then | ||
| cf=/opt/homebrew/opt/llvm/bin/clang-format | ||
| elif [[ -x /usr/local/opt/llvm/bin/clang-format ]] && /usr/local/opt/llvm/bin/clang-format --version 2>/dev/null | grep -q 'version 20'; then | ||
| cf=/usr/local/opt/llvm/bin/clang-format | ||
| fi | ||
| if [[ -n "$cf" ]]; then | ||
| "$cf" -i "$file" || hint "$cf failed on $file" | ||
| else | ||
| hint "clang-format 20 not found — install via 'apt install clang-format-20' (Linux) or 'brew install llvm' (macOS)" | ||
| fi | ||
| ;; | ||
| *.rs) | ||
| # rustfmt walks up from the file path to find .rustfmt.toml, which pins | ||
| # edition and style. Don't pass --edition here; it would override that. | ||
| if command -v rustfmt >/dev/null 2>&1; then | ||
| rustfmt "$file" || hint "rustfmt failed on $file" | ||
| else | ||
| hint "rustfmt not found — install via 'rustup component add rustfmt'" | ||
| fi | ||
| ;; | ||
| *.sol) | ||
| if command -v forge >/dev/null 2>&1; then | ||
| (cd "$(dirname "$file")" && forge fmt "$file") || hint "forge fmt failed on $file" | ||
| else | ||
| hint "forge not found — install foundry via 'curl -L https://foundry.paradigm.xyz | bash && foundryup'" | ||
| fi | ||
| ;; | ||
| *.nr) | ||
| # nargo fmt operates on whole crates, not individual files. | ||
| hint "nargo fmt is crate-scoped — run 'nargo fmt' from the noir project directory before committing" | ||
| ;; | ||
| esac | ||
|
|
||
| exit 0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| #!/usr/bin/env bash | ||
| # Regression test for the layout rule: every subdir that owns its own .claude/ | ||
| # must symlink agents/ to the repository root's .claude/agents/. Without the | ||
| # symlink, Claude Code's upward-walk stops at the subdir .claude/ and silently | ||
| # shadows every root agent. | ||
| # | ||
| # Only agents/ is checked — not skills/. Skills are intentionally per-subdir | ||
| # (the root has repo-wide workflow skills, yarn-project has TS-specific ones, | ||
| # etc.), and letting a subdir shadow root skills/ is the designed behavior. | ||
| # Agents, by contrast, are universal and need to be visible from every cwd. | ||
| # | ||
| # Runs from any cwd. | ||
|
|
||
| set -uo pipefail | ||
|
|
||
| ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd -P) | ||
|
|
||
| RED=$'\033[0;31m' | ||
| GREEN=$'\033[0;32m' | ||
| NC=$'\033[0m' | ||
|
|
||
| FAIL=0 | ||
| CHECKED=0 | ||
|
|
||
| fail() { echo "${RED}✗${NC} $1"; ((FAIL++)) || true; } | ||
| pass() { echo "${GREEN}✓${NC} $1"; ((CHECKED++)) || true; } | ||
|
|
||
| ROOT_AGENTS="$ROOT/.claude/agents" | ||
| [[ -d "$ROOT_AGENTS" ]] || { fail "root .claude/agents missing at $ROOT_AGENTS"; exit 1; } | ||
|
|
||
| # Every subdir .claude/ (excluding the root one) must expose an agents entry | ||
| # that resolves to the same inode as the root agents/ directory. | ||
| while IFS= read -r dir; do | ||
| [[ "$dir" == "$ROOT/.claude" ]] && continue | ||
| case "$dir" in | ||
| "$ROOT"/node_modules/*|*"/node_modules/"*) continue;; | ||
| "$ROOT"/noir/noir-repo/*) continue;; | ||
| esac | ||
| agents="$dir/agents" | ||
| if [[ ! -e "$agents" ]]; then | ||
| # Build the relative target (e.g. ../../.claude/agents) with POSIX tools | ||
| # so the hint is correct on macOS + Linux alike. | ||
| rel_root=${dir#$ROOT/} | ||
| depth=$(awk -F/ '{print NF}' <<<"$rel_root") | ||
| up=$(printf '../%.0s' $(seq 1 "$depth")) | ||
| fail "${dir#$ROOT/} has no agents/ — add symlink: (cd ${dir#$ROOT/} && ln -s ${up}.claude/agents agents)" | ||
| continue | ||
| fi | ||
| if [[ ! -L "$agents" ]]; then | ||
| fail "${dir#$ROOT/}/agents is not a symlink (must point at root .claude/agents/)" | ||
| continue | ||
| fi | ||
| # Resolve the symlink target and confirm it matches root agents. | ||
| resolved=$(cd "$(dirname "$agents")" && cd "$(readlink "$agents")" 2>/dev/null && pwd -P) || resolved="" | ||
| if [[ "$resolved" != "$ROOT_AGENTS" ]]; then | ||
| fail "${dir#$ROOT/}/agents resolves to $resolved, expected $ROOT_AGENTS" | ||
| continue | ||
| fi | ||
| pass "${dir#$ROOT/}/agents" | ||
| done < <(find "$ROOT" -type d -name .claude -not -path "$ROOT/noir/*" -not -path "$ROOT/**/node_modules/*") | ||
|
|
||
| echo | ||
| if (( FAIL == 0 )); then | ||
| echo "${GREEN}All $CHECKED subdir .claude/ directories expose agents/ correctly.${NC}" | ||
| exit 0 | ||
| else | ||
| echo "${RED}$FAIL subdir .claude/ directories are missing or have broken agents symlinks.${NC}" | ||
| exit 1 | ||
| fi | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Good catch. Does this apply to other folders as well, like skills?
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.
It would cause skills to be loaded multiple times I think. They are loaded dynamically just fine