Absorb the Graphify (safishamsi/graphify, 2026) pattern into
JouleClaw substrate. Graphify turns any folder of code, SQL, R,
shell, docs, papers into a queryable knowledge graph; the load-
bearing claim is "where does billing deduct credits?" returns
the right files in ~1.7k tokens instead of ~123k.
WHY THIS GAP IS REAL
jouleclaw-graph-rag already shipped Entity / Edge /
KnowledgeGraph / InMemoryKnowledgeGraph primitives. What was
missing for the Graphify pattern:
1. corpus → typed graph
2. community detection over the graph
3. token-budgeted subgraph query
All three live in this crate as trait surfaces with deterministic
reference impls. Tree-sitter (real parsing) + Leiden (real
community detection) + LLM semantic labels stay as later
feature-gated extensions; v0 ships the doctrine-clean reference.
WHAT'S IN THE CRATE
GraphBuilder trait + LexicalCodeBuilder
build(&[(PathBuf, String)]) -> (InMemoryKnowledgeGraph,
CodeGraphReceipt)
Lexical regex-shaped patterns for Rust / Python / JS-TS /
Markdown / SQL / Shell / TOML. Each file becomes a `File`
entity; each detected definition (Function / Struct / Class /
Trait / Module / Table / Heading / Section) becomes a Symbol
entity connected to its file via a `contains` edge.
CommunityDetector trait + ConnectedComponents
detect(graph, ids, max_depth) -> CommunityMap
Reference: undirected connected-components clustering.
Deterministic — discovery order = input order. CommunityMap is
BTreeMap<String, CommunityId> (keyed by EntityId.0 because
EntityId doesn't impl Ord upstream).
BudgetedQuery trait + LexicalBudgetedQuery
query(graph, &[Entity], terms, token_budget) -> Subgraph
Lexical name + kind + description match → top entities, 1-hop
neighbour expansion, deterministic greedy fill within budget.
Takes &[Entity] rather than &[EntityId] because the upstream
KnowledgeGraph trait resolves by display name only and our
ids (`file:<path>`, `sym:<path>#<name>`) aren't names — the
caller has the entities, hands them in directly.
CodeGraphReceipt {
builder_id, corpus_hash, files, nodes, edges, skipped
}
Auditable shape per build. corpus_hash via canonical JSON of
sorted (path, content_hash) pairs — same corpus → byte-equal
hash.
DOCTRINE
- Deterministic-first: lexical patterns + connected components +
greedy budget fill. No inference in v0.
- No filesystem deps: builders accept &[(PathBuf, String)]; the
caller chooses the walker (walkdir / ignore / mocked / in-
memory).
- Reuses upstream Entity / Edge / KnowledgeGraph primitives so
the L1.25 GraphRagTier can consume this crate's output without
shim layers.
20 tests covering: corpus_hash stability + path-order
independence; empty-corpus error; builder id stability; receipt
counts + hash anchor; Rust function + struct extraction;
markdown heading extraction; SQL CREATE TABLE (uppercase)
extraction; contains-edge emission; unknown-extension skip
counting; language detection by extension; connected-components
group + singleton + id; budgeted-query top-match + truncation +
determinism; receipt + Subgraph + CommunityMap JSON round-trips.
cargo check --workspace --all-targets clean.
JouleClaw doctrine preserved: INGEST not COMPETE. The Graphify
pattern (codebase → typed graph → community-detected → budgeted
query) is now a typed primitive consumers can compose. Real
Tree-sitter + Leiden + LLM semantic labels remain natural
feature additions on top.
Co-Authored-By: Claude Opus 4.7 <[email protected]>