Repository navigation
Point Claude runs at path-scoped rules and nested memory - #2076
Merged
ppXD merged 1 commit intoOct 6, 2026
Merged
Conversation
ppXD
force-pushed
the
fix/load-nested-claude-memory-in-place
branch
from
October 6, 2026 18:48
a3230e4 to
a07d31e
Compare
ppXD
force-pushed
the
fix/point-claude-runs-at-scoped-rules-and-nested-memory
branch
from
October 6, 2026 18:49
0af35b9 to
a7c0bfb
Compare
ppXD
changed the base branch from
fix/load-nested-claude-memory-in-place
to
main
October 6, 2026 22:25
ppXD
force-pushed
the
fix/point-claude-runs-at-scoped-rules-and-nested-memory
branch
from
October 6, 2026 22:25
a7c0bfb to
a49d64e
Compare
No --add-dir loads a .claude/rules file scoped by paths:, and the settings pin shuts the route by which the unpinned CLI attached one once its Read tool opened a file the rule covers. Nested memory past the in-place budget was lost the same way, and memory loaded in place never reaches an Explore or Plan subagent, which the CLI starts without project memory but to which, unpinned, it attached a directory's memory once the subagent read below it. The pinned 2.1.263 still attaches a rule of the user's own, under CLAUDE_CONFIG_DIR/rules, whose paths: match a file it reads, matched relative to the run's cwd, subagents included. Each build now writes one such pointer rule per scoped repository rule, in every directory the walk finds, and one per nested directory that holds memory, as rules/codespace-repository-NNN.md in walk order. A pointer's globs are the repository rule's own as the CLI reads them, rebased onto the cwd the way gitignore anchors them: as written when the rule's directory is the cwd, below that directory when a slash anchors the glob, at any depth below it otherwise, a negation kept. A directory's pointer covers everything below it; past the budget its sentence says the memory was not preloaded, in place to read it only if it is not already in context. No repository byte reaches the config home. The user scope reads external imports, so a copied rule would hand the model whatever its @-lines name before the first request. A pointer names absolute paths of letters, digits and . _ + - / in backticks, never an @ anywhere, and re-emits only globs of those characters plus * ? and one leading !; anything else gets no pointer and a launch notice, and a memory file whose name holds anything else is left out of its directory's pointer alone. Each pointer is read back through the port of the CLI's own frontmatter parse and kept only when that gives exactly the globs written, so none is ever unconditional, which would load it up front at the user's authority; a glob holding ---, which brace expansion can make, would close the frontmatter early and is refused. A pointer is at most 4 KiB, naming its directory's memory files while they fit and counting the rest, and all pointers together at most 128 KiB, at most 128 of them: named one by one, thousands of rules made a pointer megabytes long, which ended the run on the read that attached it and could push the launch past its 16 MiB frame. A directory a pointer points into passes the same outside-link guard as an added one, against the same per-build budget, so 128 small directories of links no longer hold the build for minutes. The walk now continues past the budget so it finds every scoped rule and every directory to point at, and the over-budget notice says the run is pointed at that memory instead. Against the real binary a scoped rule's pointer attaches only on a read its glob covers, single- and multi-repo, never on another repository's read, and carries none of the rule's text or imports; copying the rule into the config home instead hands the run's MCP token to the model. A differential arm runs one corpus of glob shapes, a trailing slash, a doubled /** and a frontmatter past 4 KiB among them, through the unpinned CLI and the production run, requires the same rules to attach on the same reads, one pointer per scoped rule and none in the first request; dropping an unanchored glob's **/, anchoring on a trailing slash, the /** doubling or the ** rule's unconditional reading fails it. Past the budget, a read below one directory attaches that directory's pointer and no other, and none below a directory whose memory reaches outside. An Explore subagent's read below a directory loaded in place attaches its pointer, where the unpinned CLI attached the memory itself.
ppXD
deleted the
fix/point-claude-runs-at-scoped-rules-and-nested-memory
branch
October 6, 2026 22:26
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Pointer rules. Three kinds of memory never reach the model under the pin:
paths:(no--add-dirloads it);The pinned 2.1.263 still attaches a user rule under
CLAUDE_CONFIG_DIR/ruleswhosepaths:match a file its Read tool opens, in subagents too. Each build therefore writesrules/codespace-repository-NNN.md(ClaudeWorkspaceMemory.Pointers.cs):ClaudeRuleScope.Rebase);/<dir>. Past the budget its sentence says the memory was not preloaded; in place, it says to read the memory only if it is not already in context.No repository byte in the config home.
[A-Za-z0-9._+-/]in backticks, never an@, and globs re-emitted from a safe set.---, for example from{-,b}--x, is refused there.Bounds.
Test plan
NativeLaunchProtocol.FitsTheFrame);{-,b}--xrefused by the read-back;RealHarnessWorkspaceMemoryTests7/7. The large-tree arm now haspkg-out/CLAUDE.mdlinked outside: it gets no pointer and one notice. With the pointer guard off, the arm fails.RepositoryConfigE2ETests14/14. The workflow's repository-config gate, run against the TRX, printsAll 14 repository-config E2E cases and 14 markers ran and passed.gen/,src/**/**and a frontmatter past 4 KiB. It now requires one pointer per scoped rule, none for the**rule, and none in the first request. Each of these fails it:/**doubling;**as scoped;/etc, where bwrap binds them: one whoseCLAUDE.mdlinks outside, one whose scoped rule imports an outside file. Reads below them attach nothing, the launch names both, and no outside text reaches a request. With the pointer guard off, the arm fails.An_explore_subagent_is_pointed_at_nested_memory_loaded_in_place: unpinned, the CLI attachespkg/CLAUDE.mdto an Explore subagent's read belowpkg/. Pinned, the subagent never sees the in-place memory, and its read attaches the pointer. With in-place pointers off, the arm fails.ScriptedModelUpstreamgains a subagent script and an opt-in classifier verdict, so plan mode lets Explore start.nested-subagent-pointer claude-code single-repo Confined; the gate now prints its counts from the tuples it checks[repo-config-e2e] ran non-root scoped-rule-pointer claude-code single-repo Standard uid=1654