[FEATURE] Load trusted hooks from nested repositories / --add-dir directories (multi-repo sessions leave nested guardrails off)
Summary
Claude Code loads hooks only from the session root's settings files (~/.claude/settings.json, project-root .claude/settings.json / settings.local.json, managed policy, plugins, skill/subagent frontmatter). There is no way to load hooks belonging to a nested repository inside the workspace, nor from directories added with --add-dir — the docs note --add-dir grants file access only and is not scanned for settings.
Request: a sanctioned, trust-gated way to load a nested repo's project hooks when a session rooted at a parent directory works inside that nested repo.
Motivating use case
Multi-repo agent workflows keep dependent checkouts inside the primary repo — e.g. a .extern-repos/<repo>/ convention: the session is rooted at the parent, and the agent clones a dependency there to make a coordinated change. Two things go wrong today:
- The nested repo's hooks are silently off. Its
.claude/settings.jsonis never loaded, so its project-specific guardrails (lint-on-save, TDD guards, protected-path checks) do not fire while an agent edits it — precisely the situation where guardrails matter most. - The parent's hooks misfire there. Parent hooks keep firing while cwd is inside the nested checkout; any hook written as a bare-relative command (
python .claude/hooks/check.py) resolves against the nested repo and fails with ENOENT, wedging every tool call. (This half has an established workaround —$CLAUDE_PROJECT_DIR— per the resolution threads of #50960 / #42282.)
We currently work around (1) with an external dispatcher: a PATH binary compiled into the parent's hook config that detects cwd containment in a nested repo, suppresses the parent's repo-specific hooks, and runs the nested repo's hooks rooted at that repo behind a prompt-once trust record. Design record: zackees/clud#965. It works, but every multi-repo harness is forced to reinvent this outside the trust model rather than inside it.
Why hooks are excluded today (acknowledged)
Agents, workflows, and output-styles are discovered by walking up from cwd, but hooks deliberately are not: hooks are arbitrary code execution, gated per-folder by the workspace trust dialog (and allowManagedHooksOnly for enterprises). Auto-loading a nested repo's hooks would run code from a folder the user never trusted. This request is not to bypass that — it is to extend the existing trust mechanism to cover the nested case.
Proposed behavior (any of these would work)
- Trust-dialog extension: when tool calls begin operating inside a nested repo that carries its own
.claude/settings.jsonhooks, offer the existing workspace-trust dialog for that folder; on acceptance, load its hooks scoped to operations within that subtree, withCLAUDE_PROJECT_DIRset to the nested repo's root for those hook invocations. --add-diropt-in: a flag or setting (e.g.--add-dir <path> --trust-hooks, or"additionalDirectories": [{"path": ..., "loadHooks": true}]) that loads a listed directory's project hooks after the same trust acceptance.- Settings key in the parent: parent project declares
"nestedHookRoots": [".extern-repos/*"]; matching repos' hooks load after per-folder trust acceptance, scoped to their subtree.
Scoping rule in all variants: a nested repo's hooks fire only for tool operations whose cwd/target falls inside that repo's subtree; the parent's hooks could optionally be suppressed there or keep firing (parent-controlled).
Related issues
- #8810 (closed, completed) — hooks broken when launching from a subdirectory; this request is the inverse: session at the root, work happening deeper.
- #50960, #42282 (closed, not planned) — cwd drift breaking bare-relative hook commands;
$CLAUDE_PROJECT_DIRis the accepted workaround but only helps the parent repo's hooks. - #83636, #76708 (open) — hook-time cwd reported stale/reset; noted here because any nested-hook scoping rule needs a reliable cwd to key on.
- #2365 (closed) — Better Monorepo Support; nearest prior request, did not cover hooks.
Environment
- Claude Code 2.x, observed across Windows and macOS; behavior is per current docs (hooks reference, settings reference), not version-specific.