Repository navigation
Description
Background
fbuild's .claude/settings.json declares a PreToolUse hook on
Bash|Shell|PowerShell that runs ci/hooks/tool_guard.py, which
forces all cargo / rustc / rustfmt invocations to go through
soldr cargo ... (massive speed-up via target-tree cache + zccache
seeding). The hook is critical: bare cargo build cold-builds the
workspace in ~2-3 minutes; soldr cargo build warm-hits in seconds.
Symptom
When an AI agent is running with a different project as its
Claude Code workspace root (e.g. running clud-pr against a fbuild
issue from a session whose project is FastLED), and cd's into a
fbuild worktree to do the work:
```
Agent session: project = FastLED/fastled
cd /c/Users/niteris/dev/fbuild/.claude/worktrees/
cargo build --release -p fbuild-cli # <-- bare cargo, NOT blocked
```
…the tool_guard.py hook does not fire. The build proceeds as bare
cargo build, missing all of soldr's caching, and takes minutes
instead of seconds.
Root cause
Claude Code loads hooks from .claude/settings.json at the session
project root, not from whatever directory commands execute in.
Sessions started in fastled10 load fastled10's hooks; even after
cd /c/Users/niteris/dev/fbuild/..., the fbuild hook is never
consulted because the harness's hook registry is fixed at session
start.
There's no built-in "discover hooks at the command's cwd" mechanism.
Impact
- The PR feat(symbols): standalone
fbuild symbols <elf>fine-grained bloat report #424 / feat(symbols): map-derived synthesis for anonymous rodata pools (closes #425) #427 stack's CI fix iterations rebuilt fbuild from
cold three times (~7 minutes each) instead of soldr-warm hits. - Anyone running cross-repo agents (clud-pr on a fbuild issue from a
FastLED workspace, or fbuild-dev work from a zccache workspace,
etc.) hits the same. - The
tool_guard.pyenforcement is meaningfully bypassable just by
running from outside the fbuild project root.
Possible fixes
- Symlink-style "reverse hook": when fbuild's
.claude/settings.jsonexists and we're inside its repo,
prepend its hook chain to whatever the session loaded. Probably
needs Claude Code support — this isn't a fbuild-only issue. - Wrapper script
cargoin fbuild's checkout: stick acargo
shim onPATH(via.cargo/config.toml's [alias] or a
bin/cargoscript in the worktree) that forwards to
soldr cargo. Works regardless of which project's hooks loaded. .cargo/config.tomlwith a[build]directive that points
rustc-wrapperat soldr. Doesn't catch non-cargo invocations
(rustfmt, clippy-driver) but covers the dominant case.- Agent-side hint: document in
CLAUDE.mdthat any agent
touching this repo should prefix withsoldrregardless of
where the hook is loaded. Cheapest fix, only works if agents
read CLAUDE.md. - Per-directory
.claudediscovery in the harness: the
harness could walk up from the current cwd and discover any
.claude/settings.jsonalong the way, layering them on top of
the session-level ones. This is a Claude Code feature request,
not a fbuild change — but fbuild benefits if it lands.
My recommendation: ship (2) wrapper script as a defensive
backstop, (4) CLAUDE.md hint for human readers, and file an
upstream request for (5) since it's the only solution that
generalises beyond fbuild.
Concrete reproduction
```bash
In a Claude Code session whose project = some other repo:
cd /path/to/fbuild
cargo build --release # observe: bare cargo runs, soldr cache untouched
soldr cargo build --release # observe: soldr warm-hits in seconds
```
Then in a Claude Code session whose project = /path/to/fbuild:
```bash
cargo build --release # observe: tool_guard.py blocks, asks for soldr
```
Diff the two: the only difference is which .claude/settings.json
the harness loaded at session start.
Workaround in use today
After this issue was noticed, the agent driving PR #424 / #427
switched to prefixing every cargo invocation with soldr manually.
This works but relies on agent discipline rather than enforcement.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsTriage
Activity