llmnav 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/CHANGELOG.md +113 -0
  2. package/LICENSE +21 -0
  3. package/README.md +294 -0
  4. package/ROADMAP.md +71 -0
  5. package/bin/llmnav.js +16 -0
  6. package/docs/agent-integration.md +114 -0
  7. package/docs/api.md +290 -0
  8. package/docs/architecture.md +286 -0
  9. package/docs/benchmarking.md +164 -0
  10. package/docs/ci.md +196 -0
  11. package/docs/cli.md +233 -0
  12. package/docs/configuration.md +117 -0
  13. package/docs/editor-integration.md +29 -0
  14. package/docs/faq.md +59 -0
  15. package/docs/graph.md +92 -0
  16. package/docs/language-examples.md +130 -0
  17. package/docs/migration.md +130 -0
  18. package/docs/performance-v0.2.md +42 -0
  19. package/docs/provider-neutral-integration.md +66 -0
  20. package/docs/publishing.md +86 -0
  21. package/docs/quickstart.md +139 -0
  22. package/docs/research.md +31 -0
  23. package/docs/spec.md +424 -0
  24. package/examples/provider-neutral-host.d.mts +17 -0
  25. package/examples/provider-neutral-host.mjs +40 -0
  26. package/package.json +79 -0
  27. package/schema/config.schema.json +296 -0
  28. package/src/agent-protocol.js +117 -0
  29. package/src/agent-tools.js +61 -0
  30. package/src/agents.js +127 -0
  31. package/src/boundaries.js +50 -0
  32. package/src/changes.js +168 -0
  33. package/src/cli.js +459 -0
  34. package/src/config.js +305 -0
  35. package/src/contracts.js +70 -0
  36. package/src/declaration.js +334 -0
  37. package/src/doctor.js +124 -0
  38. package/src/editor.js +107 -0
  39. package/src/evaluation.js +67 -0
  40. package/src/files.js +81 -0
  41. package/src/formatter.js +23 -0
  42. package/src/generator.js +528 -0
  43. package/src/graph-input.js +157 -0
  44. package/src/graph.js +403 -0
  45. package/src/incremental.js +262 -0
  46. package/src/index.d.ts +673 -0
  47. package/src/index.js +115 -0
  48. package/src/initializer.js +137 -0
  49. package/src/inverted-index.js +350 -0
  50. package/src/parser.js +449 -0
  51. package/src/project.js +65 -0
  52. package/src/prompt-bundle.js +108 -0
  53. package/src/registry.js +107 -0
  54. package/src/sarif.js +70 -0
  55. package/src/search-shards.js +75 -0
  56. package/src/search.js +636 -0
  57. package/src/spec.d.ts +27 -0
  58. package/src/spec.js +237 -0
  59. package/src/tokenizer.js +37 -0
  60. package/src/transaction.js +557 -0
  61. package/src/util.js +256 -0
  62. package/src/validator.js +635 -0
  63. package/templates/file-card.txt +8 -0
  64. package/templates/lexicon.json +7 -0
  65. package/templates/line-card.txt +9 -0
  66. package/templates/module-card.txt +9 -0
  67. package/templates/queries.jsonl +1 -0
  68. package/templates/symbol-card.txt +10 -0
@@ -0,0 +1,86 @@
1
+ # Publishing `llmnav` to npm
2
+
3
+ The repository is release-ready except for owner-specific metadata and npm account configuration.
4
+
5
+ ## 1. Claim the names
6
+
7
+ Create the GitHub repository named `llmnav`, then check the npm registry immediately before the first release:
8
+
9
+ ```sh
10
+ npm view llmnav
11
+ ```
12
+
13
+ An `E404` means no public package is visible through the registry you queried at that moment. It is not a reservation. The name remains claimable by someone else until publication succeeds.
14
+
15
+ ## 2. Replace release metadata
16
+
17
+ Update only the owner-specific URLs in `package.json` and `.github/ISSUE_TEMPLATE/config.yml`.
18
+ Do not run a repository-wide replacement: the release checker and doctor intentionally keep the literal `OWNER` sentinel in source code.
19
+
20
+ ```sh
21
+ npm pkg set repository.url="git+https://github.com/YOUR_GITHUB_OWNER/llmnav.git"
22
+ npm pkg set bugs.url="https://github.com/YOUR_GITHUB_OWNER/llmnav/issues"
23
+ npm pkg set homepage="https://github.com/YOUR_GITHUB_OWNER/llmnav#readme"
24
+ ```
25
+
26
+ Then replace `OWNER` only in `.github/ISSUE_TEMPLATE/config.yml` and run:
27
+
28
+ ```sh
29
+ npm run release:check
30
+ ```
31
+
32
+ ## 3. Configure npm authentication
33
+
34
+ The supplied release workflow uses npm provenance and GitHub's OIDC token. In npm package settings, configure the GitHub repository and `.github/workflows/release.yml` as a trusted publisher.
35
+
36
+ The workflow references a GitHub environment named `npm`. Create that environment for release protection, or remove the `environment` line when no environment gate is desired.
37
+
38
+ A classic or granular access token can be used for a manual first publication. Do not commit `.npmrc` credentials or an npm token.
39
+
40
+ ## 4. Validate the exact package payload
41
+
42
+ ```sh
43
+ npm ci
44
+ npm run check
45
+ npm run release:check
46
+ npm run smoke:pack
47
+ npm pack --dry-run
48
+ ```
49
+
50
+ Inspect the tarball list. The package intentionally includes the CLI, source API, type declarations, schema, templates, documentation, the typed provider-neutral host example, README, changelog, roadmap, and license. Tests, benchmark harnesses, and development scripts remain in GitHub but are not installed into consumer projects. `npm run smoke:pack` verifies the exact tarball and example export in a clean temporary project.
51
+
52
+ ## 5. Publish the first release
53
+
54
+ Manual publication:
55
+
56
+ ```sh
57
+ npm login
58
+ npm publish --provenance --access public
59
+ ```
60
+
61
+ Automated publication:
62
+
63
+ ```sh
64
+ git tag v0.5.1
65
+ git push origin v0.5.1
66
+ ```
67
+
68
+ The release workflow rejects a tag that does not match `package.json`.
69
+
70
+ ## 6. Verify from a clean directory
71
+
72
+ ```sh
73
+ mkdir llmnav-smoke
74
+ cd llmnav-smoke
75
+ npm init -y
76
+ npm install --save-dev llmnav
77
+ npx llmnav --version
78
+ npx llmnav init --agents all --package-scripts
79
+ npx llmnav doctor
80
+ ```
81
+
82
+ ## Versioning policy
83
+
84
+ The npm package follows semantic versioning. The comment protocol is versioned separately in the header.
85
+
86
+ A CLI or API breaking change increments the npm major version. A breaking source syntax change creates a new header such as `llmnav/2`; existing `llmnav/1` parsing should remain available through an explicit migration window.
@@ -0,0 +1,139 @@
1
+ # Quick start
2
+
3
+ ## Install and initialize
4
+
5
+ ```sh
6
+ npm install --save-dev llmnav
7
+ npx llmnav init --agents all --package-scripts
8
+ ```
9
+
10
+ This creates the `.llmnav` control directory, a JSON schema, the semantic ID registry, the stable order lock, deterministic generated indexes and catalogs, volatile state ignore rules, and managed instruction files for coding agents.
11
+
12
+ Review `.llmnav/config.json` before annotating code. The default scans the repository root while excluding build outputs, dependency directories, generated bundles, and common caches.
13
+
14
+ Source roots and evaluation files must remain inside the repository. The generated cache directory must remain below `.llmnav/`; parent traversal and symbolic-link control directories are rejected.
15
+
16
+ ## Annotate a module boundary
17
+
18
+ Choose a boundary that an agent is likely to search for by behavior rather than by current symbol name.
19
+
20
+ ```ts
21
+ /* llmnav/1 module
22
+ id=auth.session
23
+ role=Own refresh-token issuance, rotation, replay detection, and revocation.
24
+ owns=refresh-token family|session revocation
25
+ excludes=access-token signing|user profile storage
26
+ search=session lifecycle|token family|session revocation
27
+ invariant=One token family has at most one live refresh token.
28
+ stability=architecture
29
+ */
30
+ ```
31
+
32
+ Do not begin by annotating every function. One clear module card is more valuable than dozens of generic helper cards.
33
+
34
+ ## Annotate a behavioral boundary
35
+
36
+ ```ts
37
+ /* llmnav/1 symbol
38
+ id=auth.session.rotate
39
+ role=Rotate one refresh-token family atomically and reject replayed tokens.
40
+ search=refresh token|token rotation|token family|replay detection
41
+ invariant=At most one live refresh token exists per family.
42
+ invariant=Replay revokes the entire token family.
43
+ effect=db.write(session_tokens)|event.emit(auth.session.revoked)
44
+ risk=auth|concurrency
45
+ rel=policy>auth.session.lifecycle
46
+ rel=test>auth.session.rotate.contract
47
+ stability=contract
48
+ */
49
+ export async function rotateSession() {}
50
+ ```
51
+
52
+ The referenced policy and test IDs must exist as source cards or registry records.
53
+
54
+ ## Format and validate
55
+
56
+ ```sh
57
+ npx llmnav format
58
+ npx llmnav check
59
+ ```
60
+
61
+ `check` exits with status 1 for errors. Warnings do not fail the command.
62
+
63
+ GitHub annotation output is available for CI:
64
+
65
+ ```sh
66
+ npx llmnav check --format github
67
+ ```
68
+
69
+ ## Generate deterministic indexes and catalogs
70
+
71
+ ```sh
72
+ npx llmnav generate
73
+ ```
74
+
75
+ The first run parses every source file and builds `index.json`, `search-index.json`, `file-state.json`, semantic catalogs, and a manifest. Later runs reuse unchanged file parses and card search documents.
76
+
77
+ Commit `.llmnav/cache`, `.llmnav/ids.jsonl`, and `.llmnav/order.lock`. Do not commit `.llmnav/state` or transaction work files.
78
+
79
+ Inspect machine-readable impact data when integrating with CI or an agent:
80
+
81
+ ```sh
82
+ npx llmnav generate --json
83
+ ```
84
+
85
+ `changedCards` distinguishes semantic, structure, and body changes. `affectedCatalogs` identifies only repository, module, and agent-context catalogs whose bytes changed.
86
+
87
+ CI should run:
88
+
89
+ ```sh
90
+ npx llmnav generate --full --check
91
+ ```
92
+
93
+ That command fails when generated files, the registry, or the stable order lock differ from current source. It does not replace the live cache. Normal generation stages and verifies a complete replacement before committing it.
94
+
95
+ ## Search before opening source
96
+
97
+ ```sh
98
+ npx llmnav query "where do replayed refresh tokens revoke their family" --top 5
99
+ npx llmnav show auth.session.rotate
100
+ npx llmnav context auth.session.rotate --depth 1 --budget 2500
101
+ ```
102
+
103
+ Queries use the persistent inverted index and do not retokenize every card. If a previous generation was interrupted, the query command restores the last committed cache before reading it.
104
+
105
+ The expected agent workflow is:
106
+
107
+ 1. Query from the task language.
108
+ 2. Inspect a few cards and generated signatures.
109
+ 3. Open the selected declarations.
110
+ 4. Expand one semantic hop only when policy, test, fallback, or workflow context is needed.
111
+ 5. Use broad grep only after LLMNav fails to return a credible candidate.
112
+
113
+ ## Add task-language aliases
114
+
115
+ ```json
116
+ {
117
+ "version": 1,
118
+ "aliases": {
119
+ "session renewal": "auth.session.rotate",
120
+ "token replay attack": "auth.session.rotate",
121
+ "credit reservation": "billing.credit.reserve"
122
+ }
123
+ }
124
+ ```
125
+
126
+ Aliases are evaluated before lexical ranking and receive a large deterministic score boost.
127
+
128
+ ## Add search regression cases
129
+
130
+ ```jsonl
131
+ {"query":"revoke every session in the family when a refresh token is replayed","expected":["auth.session.rotate","auth.session.revoke-family"]}
132
+ {"query":"reserve credits before starting an external generation job","expected":["billing.credit.reserve"]}
133
+ ```
134
+
135
+ ```sh
136
+ npx llmnav eval
137
+ ```
138
+
139
+ Do not lower the gates simply because a new card displaced an old result. Fix ambiguous roles, overloaded search phrases, aliases, or missing semantic relations first.
@@ -0,0 +1,31 @@
1
+ # Research basis
2
+
3
+ LLMNav is an engineering proposal built from a recurring result in repository-level code intelligence: retrieval quality depends more on selecting the right structure and context than on sending more source text to a model.
4
+
5
+ ## Repository-level retrieval
6
+
7
+ [RepoCoder](https://arxiv.org/abs/2303.12570) uses an iterative retrieval and generation loop instead of treating repository context as one static prompt. That supports LLMNav's `query → show → context → source` workflow.
8
+
9
+ [Repoformer](https://arxiv.org/abs/2403.10059) studies selective retrieval and reports that retrieval can be unnecessary or harmful for some completions. LLMNav therefore keeps the first result set small and does not force a repository dump into every request.
10
+
11
+ [GraphCoder](https://arxiv.org/abs/2406.07003) combines code context with graph structure. [CodexGraph](https://arxiv.org/abs/2408.03910) exposes repository graphs to agents. These works support the separation between hand-written semantic cards and generated structural edges.
12
+
13
+ [Aider's repository map](https://aider.chat/docs/repomap.html) is a practical example of presenting selected declarations and signatures under a token budget rather than copying every file.
14
+
15
+ ## What the research does not prove
16
+
17
+ None of these projects validates the exact `llmnav/1` syntax, field weights, byte limits, or CI thresholds in this repository. Those are testable design choices, not established constants.
18
+
19
+ LLMNav also makes no universal claim that comments increase model accuracy. Unbounded comments can add stale facts, duplicate code, and distort lexical retrieval. The protocol deliberately limits cards to scarce semantic facts and measures retrieval with repository-specific queries.
20
+
21
+ ## Falsifiable claims
22
+
23
+ A useful LLMNav installation should demonstrate all of the following against its own baseline:
24
+
25
+ 1. The correct semantic ID appears more often in the first five results.
26
+ 2. Agents open fewer irrelevant files before reaching the target declaration.
27
+ 3. Uncached input tokens decrease when stable catalogs are reused.
28
+ 4. Final task success does not regress.
29
+ 5. Stale source metadata remains at zero because volatile structure is generated.
30
+
31
+ Use [benchmarking.md](benchmarking.md) to measure those claims. Do not advertise token or latency reductions measured on another repository as expected results for yours.
package/docs/spec.md ADDED
@@ -0,0 +1,424 @@
1
+ # LLMNav/1 specification
2
+
3
+ Status: experimental normative specification
4
+
5
+ Package implementation: `llmnav` 0.2.x
6
+
7
+ ## Purpose
8
+
9
+ LLMNav/1 defines a compact semantic card embedded next to selected code boundaries. A conforming implementation extracts cards, validates stable meaning, generates volatile structure, and exposes the result to coding agents without requiring broad repository reads.
10
+
11
+ The source card is not a complete documentation record. It contains only information that is expensive to infer from code and expected to remain valid across ordinary implementation changes.
12
+
13
+ The terms MUST, MUST NOT, SHOULD, SHOULD NOT, and MAY are normative.
14
+
15
+ ## Encoding and line model
16
+
17
+ A card MUST be UTF-8 text.
18
+
19
+ Each metadata line MUST contain one `key=value` pair. The first `=` separates the key and value. Multiline values are not supported.
20
+
21
+ Tabs are not meaningful. A formatter MUST emit spaces and deterministic line endings matching the containing source file.
22
+
23
+ Unknown keys are errors. Implementations MUST NOT silently index them, and formatters MUST NOT silently delete them.
24
+
25
+ ## Headers and scopes
26
+
27
+ Every card starts with:
28
+
29
+ ```text
30
+ llmnav/1 <scope>
31
+ ```
32
+
33
+ The valid scopes are `file`, `module`, and `symbol`.
34
+
35
+ A `file` card describes the responsibility of one source file. It SHOULD appear before imports after any shebang, license notice, or language-required package declaration.
36
+
37
+ A `module` card describes a domain, package, namespace, or architectural boundary. It SHOULD be used when one responsibility spans multiple declarations or files.
38
+
39
+ A `symbol` card attaches to the next declaration after whitespace, ordinary documentation comments, decorators, or attributes. A conforming checker MUST report a card that cannot be attached to a declaration.
40
+
41
+ ## Comment encodings
42
+
43
+ ### Block comments
44
+
45
+ ```text
46
+ /* llmnav/1 symbol
47
+ id=domain.capability.action
48
+ role=Produce one observable result.
49
+ stability=contract
50
+ */
51
+ ```
52
+
53
+ ### HTML comments
54
+
55
+ ```text
56
+ <!-- llmnav/1 file
57
+ id=ui.checkout.page
58
+ role=Render the checkout workflow and submit one payment confirmation.
59
+ stability=contract
60
+ -->
61
+ ```
62
+
63
+ ### Line comments
64
+
65
+ Line-comment cards MUST use one prefix consistently and MUST end with an explicit `/llmnav` line.
66
+
67
+ ```text
68
+ # llmnav/1 symbol
69
+ # id=domain.capability.action
70
+ # role=Produce one observable result.
71
+ # stability=contract
72
+ # /llmnav
73
+ ```
74
+
75
+ The supported prefixes in the reference implementation are `//`, `#`, and `--`.
76
+
77
+ ## Canonical key order
78
+
79
+ A formatter MUST emit keys in this order:
80
+
81
+ ```text
82
+ id
83
+ role
84
+ owns
85
+ excludes
86
+ search
87
+ invariant
88
+ effect
89
+ risk
90
+ rel
91
+ stability
92
+ ```
93
+
94
+ Stable key order is part of the format. It makes generated catalogs deterministic and avoids semantically meaningless prompt-prefix changes.
95
+
96
+ ## Field cardinality
97
+
98
+ | Key | Cardinality | Value form |
99
+ | --- | --- | --- |
100
+ | `id` | exactly one | scalar |
101
+ | `role` | exactly one | scalar sentence |
102
+ | `owns` | zero or one line | pipe-separated list |
103
+ | `excludes` | zero or one line | pipe-separated list |
104
+ | `search` | zero or one line | pipe-separated list |
105
+ | `invariant` | repeated, zero to four | one assertion per line |
106
+ | `effect` | zero or one line | pipe-separated controlled values |
107
+ | `risk` | zero or one line | pipe-separated controlled values |
108
+ | `rel` | repeated, zero to six | one relation per line |
109
+ | `stability` | exactly one | controlled scalar |
110
+
111
+ Empty values are invalid in every field. Empty items inside a pipe-separated list are invalid. Optional fields MUST be omitted when they have no value. Duplicate values in list or repeatable fields are invalid after Unicode normalization and case folding.
112
+
113
+ ## `id`
114
+
115
+ `id` is a durable semantic identity. It MUST describe a capability, contract, policy, or workflow rather than a current file or symbol name.
116
+
117
+ The grammar is:
118
+
119
+ ```text
120
+ id = segment "." segment *("." segment)
121
+ segment = lowercase-letter *(lowercase-letter / digit / "-")
122
+ ```
123
+
124
+ The reference validation expression is:
125
+
126
+ ```regex
127
+ ^[a-z][a-z0-9]*(?:\.[a-z][a-z0-9-]*){1,5}$
128
+ ```
129
+
130
+ Examples:
131
+
132
+ ```text
133
+ auth.session.rotate
134
+ billing.credit.reserve
135
+ privacy.export.prepare
136
+ game.arena.collapse-sequence
137
+ ```
138
+
139
+ An ID MUST remain unchanged when a file moves, a declaration is renamed, or an implementation is replaced without changing the semantic capability.
140
+
141
+ Deleted IDs MUST NOT be reused. `.llmnav/ids.jsonl` records active, redirected, replaced, or retired identities.
142
+
143
+ ```jsonl
144
+ {"id":"auth.session.rotate","state":"active"}
145
+ {"id":"auth.session.renew","state":"redirect","to":"auth.session.rotate"}
146
+ {"id":"billing.credit.charge","state":"replaced","by":["billing.credit.reserve","billing.credit.capture"]}
147
+ ```
148
+
149
+ ## `role`
150
+
151
+ `role` states the observable result produced by the file, module, or symbol.
152
+
153
+ It MUST NOT merely restate a name or use an empty abstraction such as “handle data”, “manage sessions”, “service utility”, or “process logic”.
154
+
155
+ It MUST be no longer than 180 characters in the reference profile.
156
+
157
+ Good:
158
+
159
+ ```text
160
+ role=Reserve user credits before an external generation job starts.
161
+ ```
162
+
163
+ Bad:
164
+
165
+ ```text
166
+ role=Handle billing data.
167
+ ```
168
+
169
+ ## `owns` and `excludes`
170
+
171
+ `owns` lists responsibilities for which the card is authoritative.
172
+
173
+ `excludes` names adjacent responsibilities that appear related but belong elsewhere. It reduces false-positive routing in repositories with dense domain vocabulary.
174
+
175
+ ```text
176
+ owns=refresh-token family|session revocation
177
+ excludes=access-token signing|user profile storage
178
+ ```
179
+
180
+ These fields SHOULD appear primarily on `file` and `module` cards.
181
+
182
+ ## `search`
183
+
184
+ `search` bridges task language and code language. It contains phrases that a developer or product owner is likely to use but that may not appear in current identifiers.
185
+
186
+ When present, the reference profile requires two to six phrases.
187
+
188
+ ```text
189
+ search=refresh token|token rotation|token family|replay detection
190
+ ```
191
+
192
+ Generic phrases such as `service`, `manager`, `handler`, `helper`, `utility`, `data`, `process`, and `logic` are forbidden by default.
193
+
194
+ A repository SHOULD use one source-card language. Translations, abbreviations, product terminology, and historical names SHOULD be stored in `.llmnav/lexicon.json` rather than duplicated across source comments.
195
+
196
+ ## `invariant`
197
+
198
+ Each `invariant` is a condition whose violation represents a bug, security failure, accounting failure, or broken contract.
199
+
200
+ ```text
201
+ invariant=At most one live refresh token exists per family.
202
+ invariant=Replay revokes the entire token family.
203
+ ```
204
+
205
+ Descriptions, goals, implementation notes, and temporary assumptions MUST NOT be presented as invariants.
206
+
207
+ The reference profile permits at most four invariants per card. More usually indicates that the annotated boundary is too broad or that policy belongs in a separate card.
208
+
209
+ ## `effect`
210
+
211
+ `effect` uses a controlled vocabulary for externally observable or nondeterministic behavior.
212
+
213
+ The base vocabulary is:
214
+
215
+ ```text
216
+ db.read(name)
217
+ db.write(name)
218
+ cache.read(name)
219
+ cache.write(name)
220
+ event.emit(name)
221
+ event.consume(name)
222
+ net.call(name)
223
+ fs.read
224
+ fs.write
225
+ process.spawn
226
+ clock.read
227
+ random.read
228
+ lock.acquire(name)
229
+ cookie.write(name)
230
+ auth.check(name)
231
+ ```
232
+
233
+ The base vocabulary has fixed argument arity. `db.*`, `cache.*`, `event.*`, `net.call`, `lock.acquire`, `cookie.write`, and `auth.check` require one stable target argument. `fs.read`, `fs.write`, `process.spawn`, `clock.read`, and `random.read` accept no argument. Resource arguments identify a semantic resource rather than a path, host, timestamp, or current implementation detail.
234
+
235
+ A repository MAY extend the vocabulary in `.llmnav/config.json`. An extension declares only a lower-case effect kind such as `queue.publish`; the reference implementation accepts that custom kind with or without one target argument. Extensions MUST remain machine-parseable and SHOULD use a stable namespace.
236
+
237
+ Effects do not replace static analysis. They express semantic importance and provide retrieval signals while future enrichers compare declarations against actual sinks.
238
+
239
+ ## `risk`
240
+
241
+ The base risk vocabulary is:
242
+
243
+ ```text
244
+ auth
245
+ money
246
+ privacy
247
+ concurrency
248
+ migration
249
+ availability
250
+ performance
251
+ ```
252
+
253
+ Cards containing `auth`, `money`, or `privacy` MUST contain at least one invariant and at least one `test>` relation under the reference profile.
254
+
255
+ A repository MAY add controlled risk values in configuration.
256
+
257
+ ## `rel`
258
+
259
+ `rel` records a semantic relation that cannot be reliably derived from imports or call syntax.
260
+
261
+ The grammar is:
262
+
263
+ ```text
264
+ rel=<type>><target-id>
265
+ ```
266
+
267
+ The base relation types are:
268
+
269
+ ```text
270
+ policy
271
+ workflow
272
+ fallback
273
+ mirror
274
+ migration
275
+ test
276
+ replaces
277
+ deprecated-by
278
+ cross-repo
279
+ ```
280
+
281
+ Examples:
282
+
283
+ ```text
284
+ rel=policy>auth.session.lifecycle
285
+ rel=workflow>auth.session.revoke-family
286
+ rel=fallback>auth.session.reauthenticate
287
+ rel=test>auth.session.rotate.contract
288
+ rel=cross-repo>zdp-core-auth/auth.session.rotate
289
+ ```
290
+
291
+ The following structural relations MUST NOT be maintained by hand:
292
+
293
+ ```text
294
+ calls
295
+ imports
296
+ references
297
+ implements
298
+ exports
299
+ overrides
300
+ ```
301
+
302
+ They belong in generated structure indexes because source changes can invalidate them immediately.
303
+
304
+ A non-cross-repository target MUST resolve to a source card or an ID registry record.
305
+
306
+ ## `stability`
307
+
308
+ `stability` controls catalog placement and cache strategy.
309
+
310
+ `architecture` describes ownership, boundaries, and responsibilities that normally survive file moves and implementation changes. Architecture cards enter the repository core catalog by default.
311
+
312
+ `contract` describes externally relevant behavior, invariants, effects, and semantic workflow links. Contract cards enter module catalogs by default.
313
+
314
+ `implementation` describes a current algorithm or optimization that may change frequently. Implementation cards remain searchable but are excluded from shared stable catalogs by default.
315
+
316
+ ## Forbidden volatile data
317
+
318
+ Source cards MUST NOT contain fields for:
319
+
320
+ ```text
321
+ path
322
+ line
323
+ span
324
+ commit
325
+ updated_at
326
+ owner
327
+ callers
328
+ callees
329
+ imports
330
+ references
331
+ implementation_count
332
+ test_status
333
+ current_signature
334
+ ```
335
+
336
+ Equivalent path, line, commit, and timestamp data hidden inside `role`, `search`, or `invariant` values is also invalid.
337
+
338
+ Current locations, signatures, imports, hashes, and future call-graph edges belong in generated files.
339
+
340
+ ## Size profile
341
+
342
+ The reference implementation applies these default byte limits:
343
+
344
+ | Scope | Maximum bytes |
345
+ | --- | ---: |
346
+ | `file` | 400 |
347
+ | `module` | 1,200 |
348
+ | `symbol` | 900 |
349
+
350
+ For repositories with at least 50,000 scanned source bytes, LLMNav comments SHOULD remain below 1.5% of source bytes. The checker reports a warning when the configured ratio is exceeded.
351
+
352
+ These are anti-bloat limits, not targets.
353
+
354
+ ## Canonicalization
355
+
356
+ A canonical formatter MUST refuse to erase malformed lines, unknown fields, overlapping blocks, or duplicate scalar values. Unsafe cards remain unchanged until the checker-reported issue is fixed.
357
+
358
+ For valid cards, a canonical formatter MUST:
359
+
360
+ * emit the standard header and terminator for the original comment style
361
+ * emit keys in canonical order
362
+ * emit list fields once with `|` separators
363
+ * emit one line per `invariant` and `rel`
364
+ * remove empty optional fields
365
+ * preserve the containing file's newline convention
366
+ * preserve source indentation
367
+
368
+ A checker MAY reject non-canonical formatting. The reference implementation does so by default.
369
+
370
+ ## Generated index
371
+
372
+ The reference implementation emits `.llmnav/cache/index.json` with:
373
+
374
+ * stable card fields
375
+ * generated path and source line
376
+ * attached declaration name, kind, line, and signature when recognized
377
+ * generated import strings
378
+ * separate semantic, structure, and body SHA-256 hashes
379
+
380
+ `semantic` hashes change only when card meaning changes.
381
+
382
+ `structure` hashes change when path, declaration, signature, or import structure changes.
383
+
384
+ `body` hashes change when the containing source file changes.
385
+
386
+ Generated files MUST be deterministic. Wall-clock timestamps, absolute paths, platform-specific separators, random transaction IDs, and filesystem stat values MUST NOT be embedded in deterministic catalogs.
387
+
388
+ The reference implementation preserves `index.json` schemaVersion 1 for v0.1 consumers and emits additive generated accelerators:
389
+
390
+ * `search-index.json` contains a versioned deterministic token dictionary, normalized phrase documents, and compact posting lists
391
+ * `file-state.json` contains versioned deterministic parsed-file state
392
+ * `manifest.json` hashes every deterministic cache artifact except itself
393
+
394
+ An implementation MAY use volatile filesystem stat hints to avoid reading unchanged files, but those hints MUST remain outside deterministic cache output and MUST NOT affect generated bytes.
395
+
396
+ Incremental generation MUST produce the same deterministic artifacts as a full generation for identical source, configuration, registry, aliases, and stable order.
397
+
398
+ A generated search index MUST be treated as an accelerator rather than source truth. Implementations MUST be able to reject an incompatible accelerator and rebuild it from the primary card index.
399
+
400
+ Transactional work directories and recovery journals are not deterministic artifacts. They MUST NOT be copied into source comments or committed as semantic metadata.
401
+
402
+ ## Stable order
403
+
404
+ `.llmnav/order.lock` records semantic IDs in append-only catalog order. Implementations SHOULD preserve existing lines and append new active IDs.
405
+
406
+ A deleted ID MAY remain in the lock. Removing or globally reordering entries is an explicit cache-epoch operation, not routine formatting.
407
+
408
+ ## Conformance
409
+
410
+ A source parser conforms to LLMNav/1 when it recognizes all required comment encodings, field syntax, and canonical keys.
411
+
412
+ A checker conforms when it enforces required fields, controlled values, ID syntax, forbidden volatile data, relation resolution, registry state validity, and declaration attachment.
413
+
414
+ An indexer conforms when it keeps source semantics separate from generated location and emits deterministic output for identical input.
415
+
416
+ A coding-agent integration conforms when it directs the agent to query compact cards before broad repository exploration and does not treat generated paths as stable source metadata.
417
+
418
+ ## Versioning
419
+
420
+ The npm package version and source specification version are independent.
421
+
422
+ Backward-compatible parser, CLI, ranking, or diagnostic improvements use normal semantic package versioning.
423
+
424
+ A breaking source grammar change requires a new header such as `llmnav/2`. Implementations MUST NOT reinterpret a `llmnav/1` card under incompatible rules.
@@ -0,0 +1,17 @@
1
+ import type {
2
+ AgentOperationResult,
3
+ AgentToolDefinition,
4
+ PromptPrefixBundle,
5
+ PromptPrefixPartition,
6
+ } from "llmnav";
7
+
8
+ export interface LlmnavHost {
9
+ toolDefinitions: AgentToolDefinition[];
10
+ basePromptPartitions: PromptPrefixPartition[];
11
+ selectPromptPartitions(moduleIds?: string[]): PromptPrefixPartition[];
12
+ execute(call: { name: string; input?: Record<string, unknown> }): Promise<AgentOperationResult>;
13
+ refresh(): Promise<LlmnavHost>;
14
+ }
15
+
16
+ export function createLlmnavHost(root: string): Promise<LlmnavHost>;
17
+ export function selectPromptPartitions(bundle: PromptPrefixBundle, moduleIds?: string[]): PromptPrefixPartition[];