Skip to content

feat: follow inclusion graph from memory files to expand /reflect target scope#35

Open
alonl wants to merge 1 commit into
BayramAnnakov:mainfrom
alonl:feat/inclusion-graph-targets
Open

feat: follow inclusion graph from memory files to expand /reflect target scope#35
alonl wants to merge 1 commit into
BayramAnnakov:mainfrom
alonl:feat/inclusion-graph-targets

Conversation

@alonl
Copy link
Copy Markdown

@alonl alonl commented May 2, 2026

Closes #34.

Summary

  • Memory files (CLAUDE.md, AGENTS.md, rule files) often delegate guidance to other docs via Claude Code's @filename includes or markdown links. Today those docs are outside /reflect's scope, so a learning that belonged in standards.md drifts into CLAUDE.md.
  • find_claude_files() now performs a bounded BFS over @-includes and inline markdown links from the discovered memory files and surfaces the reached .md docs as type='referenced' entries with referenced_from + depth provenance.
  • Routing UI offers them like CLAUDE.md targets; user picks per-learning.

Concrete example

CLAUDE.md  →  @AGENTS.md  →  [Coding Standards](./docs/standards.md)
                          →  [Architecture](./docs/architecture.md)

After this change, all four files are reachable as /reflect targets.

Constraints honored

  • Bounded traversalDEFAULT_INCLUSION_DEPTH = 3
  • Bounded breadthDEFAULT_INCLUSION_MAX_NODES = 200
  • Bounded readsMAX_INCLUSION_FILE_BYTES = 1 MiB
  • Cycle-safe — visited-set; A→B→A and self-references don't loop
  • Shortest-path provenance — BFS dequeue order; pinned by test_bfs_shortest_path_provenance
  • Skips fenced code blocks — both ``` and ~~~
  • Skips external URLs — any scheme (https:, mailto:, …)
  • Skips same-file anchors[text](#section); in-page anchors stripped from path links
  • .md-only targets — checked on both the raw target and the resolved path, so a symlinked evil.md → /etc/passwd is rejected
  • Allowlisted paths — resolved paths confined to {root_dir, get_claude_dir()}; pasted-in [x](/etc/passwd.md) can't surface arbitrary filesystem paths
  • Email-safe regex(?<![\w.])@… lookbehind prevents matching foo@bar.md
  • Inline markdown links only — reference-style [text][ref] is intentionally not handled

API

find_claude_files(root_dir, follow_includes=True, max_depth=3, max_nodes=200) — defaults on; pass follow_includes=False or max_depth=0 to opt out. 'referenced' entries carry referenced_from and depth.

Files changed (~783 LOC: 282 impl + 495 tests + 11 docs)

  • scripts/lib/reflect_utils.py_parse_inclusions, _resolve_inclusion, _format_relative_path, _follow_inclusion_graph, plus the find_claude_files() integration
  • tests/test_memory_hierarchy.py — 34 new tests across 4 classes covering parsing, resolution, traversal, security clamps, and the read_all_memory_entries integration
  • commands/reflect.md — adds Referenced Docs row to target table, updates type list, extends --targets display, adds routing hint
  • README.md — one bullet under Multi-Target Sync

Test plan

  • 222 existing tests still pass unchanged
  • 34 new tests pass (256 total)
  • Smoke test on this repo's own CLAUDE.md: surfaces RELEASING.md (real [RELEASING.md](RELEASING.md) link in CLAUDE.md)
  • capture_learning.py and check_learnings.py hooks still run
  • Python 3.9 verified locally; type hints stay 3.8-compatible
  • macOS /tmp/private/tmp symlink handled
  • Security: out-of-allowlist paths rejected; symlink-to-non-md rejected
  • DoS: 1 MiB file cap, 200-node fanout cap

Backward compatibility

  • Existing types unchanged
  • New keys (referenced_from, depth) only on 'referenced' entries
  • All existing tests that filter by type or assert assertIn("root", types) continue to pass

🤖 Generated with Claude Code

…gets

Memory files (CLAUDE.md, AGENTS.md, rule files) often delegate guidance
to other docs via Claude Code's @-include syntax or standard markdown
links. Those docs were previously outside /reflect's scope, so a
learning that belonged in standards.md drifted into CLAUDE.md.

find_claude_files() now does a bounded BFS over @-includes and inline
markdown links from the discovered memory files and surfaces the reached
.md docs as type='referenced' entries with referenced_from + depth
provenance. Routing UI offers them like CLAUDE.md targets.

- Bounded depth (default 3 hops), node fanout (default 200), per-file
  read (1 MiB)
- BFS dequeue order guarantees shortest-path provenance
- Cycle-safe via visited set
- Skips fenced code blocks, external URLs, same-file anchors
- Resolved paths confined to {root_dir, get_claude_dir()} so pasted-in
  [x](/etc/passwd.md) can't surface arbitrary filesystem paths
- .md suffix re-checked on the resolved path (rejects evil.md → /etc/passwd
  symlinks)

Closes BayramAnnakov#34

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@alonl alonl force-pushed the feat/inclusion-graph-targets branch from a45c298 to 87c604e Compare May 2, 2026 13:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Follow inclusion graph from memory files to expand /reflect target scope

1 participant