A codemap writes a codebase's call graph as a set of GEML documents: one per container, methods as empty-bodied code blocks, edges as CSV tables, entry points in the meta. It is an application-layer profile: the core specification is untouched, and declaring profile = "geml-codemap/v1" admits three attribute keys on code. This page uses the generated documents in playground/codemap/ to line up the directory layout, the meta keys, the method block, the edge tables, the split of validation duties and the agent's consumption path against the profile document.
Settled fixed by the profile document. Observed not prescribed, this is what the tool does today. No implementation gap found on this page.
| Rule | Source | Status | |
|---|---|---|---|
| 1 | An application-layer profile, not part of the standard. The declaration admits three keys on code: anchor, name, entry-via (profiles.ts). Required: an old map without it gets one warning per code block; a rebuild fixes it. | §2 · §8.6 | Settled |
| 2 | Layout: under .geml-code-graph/, index.geml (repo metadata + module summary table), one <container>.geml per container, _index/name-lookup.json, _index/cross-stack.json, _build/ (intermediates; agents never read it). foldings.geml tunes build-time naming, style.geml tunes display: seeded on first build, never overwritten. | §1 | Settled |
| 3 | Container document name = display path sanitized (/→--, anything outside [A-Za-z0-9_.-]→-), -2 on collision. Build skips .gitignored files by default and --exclude drops more; edges to excluded symbols vanish with them. | §1 | Settled |
| 4 | Exactly one meta per document: profile (all), module (containers: display path, build root and common prefix stripped), src (real relative path), entry (methods called from outside the container, space-separated, checked by verify), resolution-default cpg / heuristic, repo commit container on the index, optional graph-depth. | §2 | Settled |
| 5 | Method block: code {#id src=path#Lstart-end anchor="…"}, empty body. src= is an ordinary attribute the agent follows to open the source; anchor= is the engine-level stable identity; name= is written only when sanitizing changed the id. | §3 | Settled |
| 6 | id = the method's short name sanitized; on a same-document collision every member gets -<first 6 of sha256(anchor)>, widening to 8, 10… if still colliding. A rename = a new id = dangling references = verify error, which is a feature. | §3 | Settled |
| 7 | Symbol-level classes: .leaf (zero outgoing edges including unresolved, and called), .accessor (bean-style get/set/is leaf, hidden by renderers by default), .test, .flow-entry. entry is never on a block, only in the meta. | §3 | Settled |
| 8 | Edge tables (empty ones are not emitted): #calls(from,to,kind,confidence), #called-by(from,to,kind,site), #unresolved(from,to; hidden), #api-calls / #api-served-by (cross-stack http edges), #ref-by reserved. References are #id or doc.geml#id; plain-text cells carry no commas or newlines and swap brackets for parentheses, because cells parse as inline content. | §4 | Settled |
| 9 | Cross-stack links: frontend and backend are matched by METHOD + normalized path into http edges; heuristic, so they live in their own tables and never mix into the verified #calls; the endpoint is an edge label, not a node; detectors are pluggable per language; _index/cross-stack.json records the audit. | §4.1 | Settled |
| 10 | Division of labour: geml check handles structure, id uniqueness, native references; CSV cells and meta values are opaque to the standard, on purpose. codemap verify resolves every from/to in #calls / #called-by and the meta entry; a dangling one = exit 1. Cross-stack tables are lenient: the #id end must resolve, the file:line end may lie outside the map. | §5 | Settled |
| 11 | Rendering: the generated documents are pure data and contain no diagram block; a renderer that recognizes a codemap document gives a layered method-flow view (roots = meta entry, depth = graph-depth); to embed the graph elsewhere write diagram {format=geml-code-graph src=…}, with src as its only attribute. | §6 · GEP-0003 | Settled |
| 12 | Versioning and trust: build --history commits each changed document into its own .gemlhistory; revert doc '#method' --rev -1 rolls back one method. resolution-default says where the edges came from; the confidence column and candidate rows are where the resolver refused to guess for you; #unresolved is a blind spot, not "no calls". | §7 · §8 | Settled |
| 13 | CLI: geml codemap build | verify | render | serve | refresh | find, dir defaults to ./.geml-code-graph, codegraph / code-graph are aliases. All 35 playground documents pass verify; find needs _index/name-lookup.json, which the playground does not ship. | geml codemap --help | Observed |
Left, the layout from profile §1; right, the real head of the playground's index.geml.
$ geml codemap verify playground/codemap verify: 35/35 documents pass geml check; profile references: all resolve $ geml codemap find playground/codemap renderChart no name-lookup at …\_index\name-lookup.json — build the codemap first
=== meta profile = "geml-codemap/v1" repo = geml commit = fa40d89 container = file entry = geml-viewer--content.js.geml#main resolution-default = cpg === # Code map — geml === table {#modules format=csv} module, doc, methods, entries, tests geml-parser/geml.ts, geml-parser--geml.ts.geml, 72, 23, 0 geml-parser/cli.ts, geml-parser--cli.ts.geml, 63, 0, 0 geml-parser/render.ts, geml-parser--render.ts.geml, 50, 6, 0 … %% 27 rows, one container document each ===
geml-parser/chart.ts → geml-parser--chart.ts.geml. The display path algorithm is §2 module: strip the build's source root (src/main/java, a bare src), then the longest common segment prefix within the module; test code folds into a top-level test/.foldings.geml and style.geml are files you edit, not build products: seeded on the first build, never rewritten after. style.geml is a geml-style/v1 sheet; missing or unreadable, the renderer falls back to its built-in defaults, exactly the behaviour before the sheet existed.geml-parser--chart.ts.geml, generated by the builder and not edited. Two methods, one outgoing table, one incoming table.
=== meta profile = "geml-codemap/v1" module = geml-parser/chart.ts %% display path src = geml-parser/src/chart.ts %% real path, used to locate the source entry = #buildChart %% called from outside the container; verify checks it resolution-default = cpg === # geml-parser/chart.ts === code {#str .leaf src=geml-parser/src/chart.ts#L51-53 anchor="scip-typescript npm @geml/geml 1.9.1 src/`chart.ts`/str()."} === %% empty body: the source is one hop away via src= === code {#buildChart src=geml-parser/src/chart.ts#L55-140 anchor="scip-typescript npm @geml/geml 1.9.1 src/`chart.ts`/buildChart()."} === === table {#calls format=csv} from, to, kind, confidence #buildChart, #str, call, %% empty confidence = high … === === table {#called-by format=csv} from, to, kind, site #buildChart, #str, call, geml-parser/src/chart.ts:61 geml-parser--geml.ts.geml#resolveCharts, #buildChart, call, geml-parser/src/geml.ts:1797 === %% cross-document reference: a method in another container document === table {#unresolved format=csv hidden} %% the blind-spot table, hidden
| Part | Rule | Source |
|---|---|---|
| meta | exactly one; entry is the only fact written in the meta rather than on a block | §2 · §3 |
| code {#id …} | empty body; id is the sanitized short name; src= is an ordinary routing attribute; anchor= is the engine identity, an admitted key | §3 |
| .leaf | zero outgoing edges and called; renderers dim it. .accessor hidden by default, .test filterable | §3 |
| #calls | outgoing edges; kind is call or candidate (a virtual-dispatch candidate, right after its primary call row); empty confidence = high | §4 |
| #called-by | incoming edges, aggregated by the generator across the whole graph; site is plain-text file:line | §4 |
| #unresolved | blind spots, hidden; to is plain text, verbatim, unchecked | §4 |
| doc.geml#id | cross-document reference as in §5.2; verify resolves it cell by cell | §4 · §5 |
geml check looks only at structure, ids and native references; #buildChart inside a CSV cell is text to the standard, and the standard grows no codemap-shaped hole. codemap verify is what resolves every from/to and the meta entry, exit 1 on a dangling one. Red means the map is stale or partially updated: rebuild before trusting navigation.to carry no commas or newlines (the generator substitutes spaces) and swap brackets for parentheses, because table cells parse as inline content and f[i](&x) would read as a link.The §8 cheat-sheet, plus cross-stack links and the trust semantics.
$ node -e "console.log(JSON.stringify(require('./.geml-code-graph/_index/name-lookup.json')['buildChart']))" {"anchor":"…","doc":"geml-parser--chart.ts.geml","id":"buildChart"} name → document + id $ geml get .geml-code-graph/geml-parser--chart.ts.geml '#buildChart' the method block; src= is one hop to source $ geml get .geml-code-graph/geml-parser--chart.ts.geml '#calls' outgoing; follow doc.geml#id downwards $ geml get .geml-code-graph/geml-parser--chart.ts.geml '#called-by' who calls me, with site $ head -8 .geml-code-graph/geml-parser--chart.ts.geml meta: the entry surface at a glance
| You see | It means |
|---|---|
| resolution-default = cpg | edges come from compiler-grade precise resolution; heuristic is syntax-level |
| confidence empty | high. A value marks where the resolver would not guess for you |
| kind = candidate | virtual dispatch / multiple implementations, right after the primary call row, inheriting its confidence |
| rows in #unresolved | a blind spot, not "no calls" |
| empty #called-by under heuristic | does not mean nobody calls it |
| #api-calls · #api-served-by | cross-stack http edges, matched, never mixed into #calls; method-mismatch flags verb disagreement |
http edges by METHOD + normalized path. Heuristic, so separate tables with a match confidence per row; the endpoint is a label on the edge rather than a node; framework knowledge lives only in per-language detectors. _index/cross-stack.json lists endpoints, verb mismatches (a contract-drift signal), routes nobody calls, and frontend calls that match no route.build --history puts each changed document into its own .gemlhistory, geml history get shows how the graph evolved, geml revert doc '#method' --rev -1 rolls back one method. See page 8.diagram {format=geml-code-graph src=index.geml}, src only. See page 4.Run against the current in-repo build, 1.9.2. Example files come from playground/codemap/, generated by geml codemap build.
| Command / file | Result | Maps to |
|---|---|---|
| geml codemap verify playground/codemap | 35/35 pass profile references: all resolve | board 10, 13 |
| geml codemap find playground/codemap renderChart | no name-lookup: the playground does not ship _index/name-lookup.json | board 13 |
| index.geml · geml-parser--chart.ts.geml | meta keys, empty-bodied code, #calls / #called-by / #unresolved match the profile | layout, document |
| profiles.ts registration | geml-codemap/v1 admits anchor / name / entry-via on code | board 1 |