@plebeiantech/lat.md 0.12.3-fork.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 (144) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +97 -0
  3. package/dist/src/cli/check-frontmatter.d.ts +12 -0
  4. package/dist/src/cli/check-frontmatter.js +44 -0
  5. package/dist/src/cli/check-mode.d.ts +6 -0
  6. package/dist/src/cli/check-mode.js +303 -0
  7. package/dist/src/cli/check-status.d.ts +74 -0
  8. package/dist/src/cli/check-status.js +217 -0
  9. package/dist/src/cli/check.d.ts +45 -0
  10. package/dist/src/cli/check.js +777 -0
  11. package/dist/src/cli/checklist-menu.d.ts +12 -0
  12. package/dist/src/cli/checklist-menu.js +111 -0
  13. package/dist/src/cli/comment-guard.d.ts +16 -0
  14. package/dist/src/cli/comment-guard.js +111 -0
  15. package/dist/src/cli/comment-reminder.d.ts +62 -0
  16. package/dist/src/cli/comment-reminder.js +210 -0
  17. package/dist/src/cli/context.d.ts +11 -0
  18. package/dist/src/cli/context.js +58 -0
  19. package/dist/src/cli/expand.d.ts +8 -0
  20. package/dist/src/cli/expand.js +94 -0
  21. package/dist/src/cli/gen-index.d.ts +45 -0
  22. package/dist/src/cli/gen-index.js +235 -0
  23. package/dist/src/cli/gen.d.ts +6 -0
  24. package/dist/src/cli/gen.js +42 -0
  25. package/dist/src/cli/graph.d.ts +7 -0
  26. package/dist/src/cli/graph.js +47 -0
  27. package/dist/src/cli/hook.d.ts +1 -0
  28. package/dist/src/cli/hook.js +432 -0
  29. package/dist/src/cli/index.d.ts +2 -0
  30. package/dist/src/cli/index.js +307 -0
  31. package/dist/src/cli/init.d.ts +9 -0
  32. package/dist/src/cli/init.js +1031 -0
  33. package/dist/src/cli/link-scheme.d.ts +54 -0
  34. package/dist/src/cli/link-scheme.js +101 -0
  35. package/dist/src/cli/locate.d.ts +2 -0
  36. package/dist/src/cli/locate.js +17 -0
  37. package/dist/src/cli/refs.d.ts +22 -0
  38. package/dist/src/cli/refs.js +229 -0
  39. package/dist/src/cli/reindex.d.ts +13 -0
  40. package/dist/src/cli/reindex.js +136 -0
  41. package/dist/src/cli/search.d.ts +36 -0
  42. package/dist/src/cli/search.js +217 -0
  43. package/dist/src/cli/section.d.ts +43 -0
  44. package/dist/src/cli/section.js +252 -0
  45. package/dist/src/cli/select-menu.d.ts +13 -0
  46. package/dist/src/cli/select-menu.js +100 -0
  47. package/dist/src/cli/templates.d.ts +1 -0
  48. package/dist/src/cli/templates.js +15 -0
  49. package/dist/src/cli/ui.d.ts +11 -0
  50. package/dist/src/cli/ui.js +34 -0
  51. package/dist/src/code-refs.d.ts +17 -0
  52. package/dist/src/code-refs.js +277 -0
  53. package/dist/src/config.d.ts +29 -0
  54. package/dist/src/config.js +83 -0
  55. package/dist/src/context.d.ts +23 -0
  56. package/dist/src/context.js +11 -0
  57. package/dist/src/extensions/wiki-link/from-markdown.d.ts +5 -0
  58. package/dist/src/extensions/wiki-link/from-markdown.js +34 -0
  59. package/dist/src/extensions/wiki-link/index.d.ts +4 -0
  60. package/dist/src/extensions/wiki-link/index.js +3 -0
  61. package/dist/src/extensions/wiki-link/syntax.d.ts +14 -0
  62. package/dist/src/extensions/wiki-link/syntax.js +121 -0
  63. package/dist/src/extensions/wiki-link/to-markdown.d.ts +5 -0
  64. package/dist/src/extensions/wiki-link/to-markdown.js +28 -0
  65. package/dist/src/extensions/wiki-link/types.d.ts +34 -0
  66. package/dist/src/extensions/wiki-link/types.js +1 -0
  67. package/dist/src/format.d.ts +8 -0
  68. package/dist/src/format.js +43 -0
  69. package/dist/src/graph-export.d.ts +60 -0
  70. package/dist/src/graph-export.js +309 -0
  71. package/dist/src/init-version.d.ts +10 -0
  72. package/dist/src/init-version.js +49 -0
  73. package/dist/src/knowledge/bd.d.ts +2 -0
  74. package/dist/src/knowledge/bd.js +107 -0
  75. package/dist/src/knowledge/claude-memory.d.ts +13 -0
  76. package/dist/src/knowledge/claude-memory.js +204 -0
  77. package/dist/src/knowledge/cq.d.ts +2 -0
  78. package/dist/src/knowledge/cq.js +74 -0
  79. package/dist/src/knowledge/index.d.ts +49 -0
  80. package/dist/src/knowledge/index.js +271 -0
  81. package/dist/src/knowledge/ranking.d.ts +17 -0
  82. package/dist/src/knowledge/ranking.js +62 -0
  83. package/dist/src/knowledge/session.d.ts +46 -0
  84. package/dist/src/knowledge/session.js +203 -0
  85. package/dist/src/knowledge/types.d.ts +47 -0
  86. package/dist/src/knowledge/types.js +10 -0
  87. package/dist/src/lattice.d.ts +108 -0
  88. package/dist/src/lattice.js +816 -0
  89. package/dist/src/mcp/server.d.ts +1 -0
  90. package/dist/src/mcp/server.js +58 -0
  91. package/dist/src/parser.d.ts +3 -0
  92. package/dist/src/parser.js +18 -0
  93. package/dist/src/search/db.d.ts +16 -0
  94. package/dist/src/search/db.js +54 -0
  95. package/dist/src/search/embedder.d.ts +25 -0
  96. package/dist/src/search/embedder.js +58 -0
  97. package/dist/src/search/index.d.ts +9 -0
  98. package/dist/src/search/index.js +66 -0
  99. package/dist/src/search/search.d.ts +9 -0
  100. package/dist/src/search/search.js +16 -0
  101. package/dist/src/source-parser.d.ts +27 -0
  102. package/dist/src/source-parser.js +916 -0
  103. package/dist/src/untrusted.d.ts +24 -0
  104. package/dist/src/untrusted.js +97 -0
  105. package/dist/src/version.d.ts +7 -0
  106. package/dist/src/version.js +39 -0
  107. package/dist/src/view/client/assets/index-B0n0u03y.css +1 -0
  108. package/dist/src/view/client/assets/index-xm2_px4q.js +23 -0
  109. package/dist/src/view/client/index.html +14 -0
  110. package/dist/src/view/diagnostics.d.ts +5 -0
  111. package/dist/src/view/diagnostics.js +171 -0
  112. package/dist/src/view/git-diff.d.ts +3 -0
  113. package/dist/src/view/git-diff.js +255 -0
  114. package/dist/src/view/git.d.ts +22 -0
  115. package/dist/src/view/git.js +193 -0
  116. package/dist/src/view/highlight.d.ts +2 -0
  117. package/dist/src/view/highlight.js +3767 -0
  118. package/dist/src/view/markdown.d.ts +22 -0
  119. package/dist/src/view/markdown.js +322 -0
  120. package/dist/src/view/protocol.d.ts +89 -0
  121. package/dist/src/view/protocol.js +1 -0
  122. package/dist/src/view/references.d.ts +62 -0
  123. package/dist/src/view/references.js +345 -0
  124. package/dist/src/view/repository.d.ts +12 -0
  125. package/dist/src/view/repository.js +167 -0
  126. package/dist/src/view/search.d.ts +14 -0
  127. package/dist/src/view/search.js +64 -0
  128. package/dist/src/view/server.d.ts +20 -0
  129. package/dist/src/view/server.js +233 -0
  130. package/dist/src/view/store.d.ts +57 -0
  131. package/dist/src/view/store.js +404 -0
  132. package/dist/src/walk.d.ts +18 -0
  133. package/dist/src/walk.js +27 -0
  134. package/package.json +85 -0
  135. package/templates/AGENTS.md +118 -0
  136. package/templates/README +1 -0
  137. package/templates/cursor-rules.md +77 -0
  138. package/templates/init/lat.md +1 -0
  139. package/templates/logo-dark.svg +182 -0
  140. package/templates/logo-light.svg +182 -0
  141. package/templates/logo.txt +7 -0
  142. package/templates/opencode-plugin.ts +180 -0
  143. package/templates/pi-extension.ts +364 -0
  144. package/templates/skill/SKILL.md +189 -0
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Walk a directory tree respecting .gitignore rules. Returns relative paths
3
+ * of all non-ignored files, excluding .git/ and dotfiles (e.g. .gitignore).
4
+ *
5
+ * This is the single entry point for all directory walking in lat.md — both
6
+ * code-ref scanning and lat.md/ index validation use it so .gitignore rules
7
+ * are consistently honored.
8
+ */
9
+ export declare function walkEntries(dir: string): Promise<string[]>;
10
+ /**
11
+ * Normalize a filesystem path to forward-slash (POSIX) form. Node's
12
+ * `path.relative()` emits the native separator (`\` on Windows), but section
13
+ * ids, wiki-link targets, and the code-ref data model are all forward-slash
14
+ * based. Normalizing every OS-relative path through here at construction keeps
15
+ * a single invariant — stored paths are always POSIX — so downstream lookups
16
+ * (e.g. `buildFileIndex`, ref resolution) work identically on every platform.
17
+ */
18
+ export declare function toPosix(p: string): string;
@@ -0,0 +1,27 @@
1
+ // @ts-expect-error -- no type declarations
2
+ import walk from 'ignore-walk';
3
+ /**
4
+ * Walk a directory tree respecting .gitignore rules. Returns relative paths
5
+ * of all non-ignored files, excluding .git/ and dotfiles (e.g. .gitignore).
6
+ *
7
+ * This is the single entry point for all directory walking in lat.md — both
8
+ * code-ref scanning and lat.md/ index validation use it so .gitignore rules
9
+ * are consistently honored.
10
+ */
11
+ export function walkEntries(dir) {
12
+ return walk({
13
+ path: dir,
14
+ ignoreFiles: ['.gitignore'],
15
+ }).then((entries) => entries.filter((e) => !e.startsWith('.git/') && !e.startsWith('.')));
16
+ }
17
+ /**
18
+ * Normalize a filesystem path to forward-slash (POSIX) form. Node's
19
+ * `path.relative()` emits the native separator (`\` on Windows), but section
20
+ * ids, wiki-link targets, and the code-ref data model are all forward-slash
21
+ * based. Normalizing every OS-relative path through here at construction keeps
22
+ * a single invariant — stored paths are always POSIX — so downstream lookups
23
+ * (e.g. `buildFileIndex`, ref resolution) work identically on every platform.
24
+ */
25
+ export function toPosix(p) {
26
+ return p.replace(/\\/g, '/');
27
+ }
package/package.json ADDED
@@ -0,0 +1,85 @@
1
+ {
2
+ "name": "@plebeiantech/lat.md",
3
+ "version": "0.12.3-fork.1",
4
+ "description": "A knowledge graph for your codebase, written in markdown",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Yury Selivanov",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/1st1/lat.md.git"
11
+ },
12
+ "homepage": "https://github.com/1st1/lat.md",
13
+ "keywords": [
14
+ "markdown",
15
+ "knowledge-graph",
16
+ "documentation",
17
+ "agents",
18
+ "cli",
19
+ "wiki-links",
20
+ "codebase"
21
+ ],
22
+ "bin": {
23
+ "lat": "./dist/src/cli/index.js"
24
+ },
25
+ "files": [
26
+ "dist/src",
27
+ "templates"
28
+ ],
29
+ "devDependencies": {
30
+ "@types/react": "^19.0.0",
31
+ "@types/react-dom": "^19.0.0",
32
+ "@vitejs/plugin-react": "^5.0.0",
33
+ "@types/mdast": "^4.0.4",
34
+ "@types/node": "^25.3.0",
35
+ "highlight.js": "^11.12.0",
36
+ "mdast-util-from-markdown": "^2.0.3",
37
+ "micromark-util-types": "^2.0.2",
38
+ "prettier": "^3.8.1",
39
+ "react": "^19.0.0",
40
+ "react-dom": "^19.0.0",
41
+ "tsx": "^4.21.0",
42
+ "typescript": "^5.7.0",
43
+ "vite": "^7.0.0",
44
+ "vitest": "^3.0.0"
45
+ },
46
+ "dependencies": {
47
+ "@folder/xdg": "^4.0.1",
48
+ "@libsql/client": "^0.17.0",
49
+ "@modelcontextprotocol/sdk": "^1.27.1",
50
+ "@repomix/tree-sitter-wasms": "^0.1.16",
51
+ "commander": "^14.0.3",
52
+ "github-slugger": "^2.0.0",
53
+ "ignore-walk": "^8.0.0",
54
+ "mdast-util-to-markdown": "^2.1.0",
55
+ "remark-frontmatter": "^5.0.0",
56
+ "remark-parse": "^11.0.0",
57
+ "remark-rehype": "^11.1.2",
58
+ "remark-stringify": "^11.0.0",
59
+ "rehype-sanitize": "^6.0.0",
60
+ "rehype-slug": "^6.0.0",
61
+ "rehype-stringify": "^10.0.1",
62
+ "unified": "^11.0.0",
63
+ "unist-util-visit": "^5.0.0",
64
+ "web-tree-sitter": "^0.26.6",
65
+ "yaml": "^2.8.2",
66
+ "zod": "^4.3.6",
67
+ "@lat.md/embed-minilm-fp16": "0.1.0",
68
+ "@lat.md/embed": "0.2.0"
69
+ },
70
+ "scripts": {
71
+ "build": "tsc && pnpm build:view",
72
+ "build:view": "vite build --config view/vite.config.ts && vite build --config view/highlight.vite.config.ts",
73
+ "buildall": "pnpm build:packages && pnpm build",
74
+ "setup:rust": "pnpm --filter @lat.md/embed setup:rust",
75
+ "build:wasm": "pnpm --filter @lat.md/embed build:wasm",
76
+ "build:weights": "pnpm --filter @lat.md/embed-minilm-fp16 build:weights",
77
+ "build:packages": "pnpm --filter @lat.md/embed build && pnpm --filter @lat.md/embed-minilm-fp16 build",
78
+ "test": "vitest run",
79
+ "test:watch": "vitest",
80
+ "typecheck": "tsc --noEmit && tsc --noEmit -p view/tsconfig.json",
81
+ "format": "prettier --write \"src/**/*.ts\" \"view/**/*.{ts,tsx,css,html}\"",
82
+ "format:check": "prettier --check \"src/**/*.ts\" \"view/**/*.{ts,tsx,css,html}\"",
83
+ "cook-test-rag": "tsx scripts/cook-test-rag.ts"
84
+ }
85
+ }
@@ -0,0 +1,118 @@
1
+ # Before starting work
2
+
3
+ - Run `lat search` to find sections relevant to your task. Read them to understand the design intent before writing code.
4
+ - Run `lat expand` on user prompts to expand any `[[refs]]` — this resolves section names to file locations and provides context.
5
+
6
+ # Post-task checklist (REQUIRED — do not skip)
7
+
8
+ After EVERY task, before responding to the user:
9
+
10
+ - [ ] Update `lat.md/` if you added or changed meaningful functionality, architecture, tests, behavior, or planned work. Keep it a focused snapshot of current/planned state, not a journal/changelog.
11
+ - [ ] Run `lat check` — all validations must pass
12
+ - [ ] Do not skip these steps. Do not consider your task done until both are complete.
13
+
14
+ ---
15
+
16
+ # What is lat.md?
17
+
18
+ This project uses [lat.md](https://www.npmjs.com/package/lat.md) to maintain a structured knowledge graph of its architecture, design decisions, and test specs in the `lat.md/` directory. It is a set of cross-linked markdown files that describe **what** this project does and **why** — the domain concepts, key design decisions, business logic, and test specifications. Use it to ground your work in the actual architecture rather than guessing. Do not treat `lat.md/` as a journal or changelog; it should be a focused snapshot of current or planned state, and should not grow just to note insignificant details.
19
+
20
+ # Commands
21
+
22
+ ```bash
23
+ lat locate "Section Name" # find a section by name (exact, fuzzy)
24
+ lat refs "file#Section" # find what references a section
25
+ lat search "natural language" # semantic search across all sections
26
+ lat expand "user prompt text" # expand [[refs]] to resolved locations
27
+ lat check # run full graph and documentation validation
28
+ ```
29
+
30
+ Run `lat --help` when in doubt about available commands or options.
31
+
32
+ If `lat search` fails because no API key is configured, explain to the user that semantic search requires a key provided via `LAT_LLM_KEY` (direct value), `LAT_LLM_KEY_FILE` (path to key file), or `LAT_LLM_KEY_HELPER` (command that prints the key). Supported key prefixes: `sk-...` (OpenAI) or `vck_...` (Vercel). If the user doesn't want to set it up, use `lat locate` for direct lookups instead.
33
+
34
+ # Syntax primer
35
+
36
+ - **Section ids**: `lat.md/path/to/file#Heading#SubHeading` — full form uses project-root-relative path (e.g. `lat.md/tests/search#RAG Replay Tests`). Short form uses bare file name when unique (e.g. `search#RAG Replay Tests`, `cli#search#Indexing`).
37
+ - **Wiki links**: `[[target]]` or `[[target|alias]]` — cross-references between sections. Can also reference source code: `[[src/foo.ts#myFunction]]`.
38
+ - **Source code links**: Wiki links in `lat.md/` files can reference functions, classes, constants, and methods in TypeScript/JavaScript/Python/Rust/Go/C files. Use the full path: `[[src/config.ts#getConfigDir]]`, `[[src/server.ts#App#listen]]` (class method), `[[lib/utils.py#parse_args]]`, `[[src/lib.rs#Greeter#greet]]` (Rust impl method), `[[src/app.go#Greeter#Greet]]` (Go method), `[[src/app.h#Greeter]]` (C struct). `lat check` validates these exist.
39
+ - **Code refs**: `// @lat: [[section-id]]` (JS/TS/Rust/Go/C) or `# @lat: [[section-id]]` (Python) — ties source code to concepts
40
+
41
+ # Test specs
42
+
43
+ Key tests can be described as sections in `lat.md/` files (e.g. `tests.md`). Add frontmatter to require that every leaf section is referenced by a `// @lat:` or `# @lat:` comment in test code:
44
+
45
+ ```markdown
46
+ ---
47
+ lat:
48
+ require-code-mention: true
49
+ ---
50
+ # Tests
51
+
52
+ Authentication and authorization test specifications.
53
+
54
+ ## User login
55
+
56
+ Verify credential validation and error handling for the login endpoint.
57
+
58
+ ### Rejects expired tokens
59
+ Tokens past their expiry timestamp are rejected with 401, even if otherwise valid.
60
+
61
+ ### Handles missing password
62
+ Login request without a password field returns 400 with a descriptive error.
63
+ ```
64
+
65
+ Every section MUST have a description — at least one sentence explaining what the test verifies and why. Empty sections with just a heading are not acceptable. (This is a specific case of the general leading paragraph rule below.)
66
+
67
+ Each test in code should reference its spec with exactly one comment placed next to the relevant test — not at the top of the file:
68
+
69
+ ```python
70
+ # @lat: [[tests#User login#Rejects expired tokens]]
71
+ def test_rejects_expired_tokens():
72
+ ...
73
+
74
+ # @lat: [[tests#User login#Handles missing password]]
75
+ def test_handles_missing_password():
76
+ ...
77
+ ```
78
+
79
+ Do not duplicate refs. One `@lat:` comment per spec section, placed at the test that covers it. `lat check` will flag any spec section not covered by a code reference, and any code reference pointing to a nonexistent section.
80
+
81
+ # Section structure
82
+
83
+ Every section in `lat.md/` **must** have a leading paragraph — at least one sentence immediately after the heading, before any child headings or other block content. The first paragraph must be ≤250 characters (excluding `[[wiki link]]` content). This paragraph serves as the section's overview and is used in search results, command output, and RAG context — keeping it concise guarantees the section's essence is always captured.
84
+
85
+ ```markdown
86
+ # Good Section
87
+
88
+ Brief overview of what this section documents and why it matters.
89
+
90
+ More detail can go in subsequent paragraphs, code blocks, or lists.
91
+
92
+ ## Child heading
93
+
94
+ Details about this child topic.
95
+ ```
96
+
97
+ ```markdown
98
+ # Bad Section
99
+
100
+ ## Child heading
101
+
102
+ Details about this child topic.
103
+ ```
104
+
105
+ The second example is invalid because `Bad Section` has no leading paragraph. `lat check` validates this rule and reports errors for missing or overly long leading paragraphs.
106
+
107
+ # Diátaxis modes
108
+
109
+ Documents under `lat.md/tutorials/`, `lat.md/how-to/`, `lat.md/reference/`, and `lat.md/explanation/` are checked against their Diátaxis mode. Declare it explicitly with nested frontmatter, or rely on the directory:
110
+
111
+ ```markdown
112
+ ---
113
+ lat:
114
+ mode: reference
115
+ ---
116
+ ```
117
+
118
+ If a document is in one of the four mode directories, the declared mode must match that directory. Each mode enforces one shape rule: tutorials need an ordered list of steps and a stated outcome; how-to guides need an ordered list of steps; reference docs must not contain narrative prose (no second paragraph under a heading); explanations must not give imperative commands. Run `lat check mode` to validate.
@@ -0,0 +1 @@
1
+ This directory is used as source of templates for commands like `lat init`.
@@ -0,0 +1,77 @@
1
+ # Before starting work
2
+
3
+ - Use the `lat_search` tool to find sections relevant to your task. Read them to understand the design intent before writing code.
4
+ - Use the `lat_expand` tool on user prompts to expand any `[[refs]]` — this resolves section names to file locations and provides context.
5
+
6
+ # Post-task checklist (REQUIRED — do not skip)
7
+
8
+ After EVERY task, before responding to the user:
9
+
10
+ - [ ] Update `lat.md/` if you added or changed meaningful functionality, architecture, tests, behavior, or planned work. Keep it a focused snapshot of current/planned state, not a journal/changelog.
11
+ - [ ] Use the `lat_check` tool — all validations must pass
12
+ - [ ] Do not skip these steps. Do not consider your task done until both are complete.
13
+
14
+ ---
15
+
16
+ # What is lat.md?
17
+
18
+ This project uses [lat.md](https://www.npmjs.com/package/lat.md) to maintain a structured knowledge graph of its architecture, design decisions, and test specs in the `lat.md/` directory. It is a set of cross-linked markdown files that describe **what** this project does and **why** — the domain concepts, key design decisions, business logic, and test specifications. Use it to ground your work in the actual architecture rather than guessing. Do not treat `lat.md/` as a journal or changelog; it should be a focused snapshot of current or planned state, and should not grow just to note insignificant details.
19
+
20
+ # Tools
21
+
22
+ You have access to the following MCP tools from the `lat` server:
23
+
24
+ - **lat_locate** — find a section by name (exact, fuzzy)
25
+ - **lat_search** — semantic search across all sections
26
+ - **lat_expand** — expand `[[refs]]` in text to resolved locations
27
+ - **lat_check** — run full graph and documentation validation
28
+ - **lat_refs** — find what references a section
29
+
30
+ If `lat_search` fails because `LAT_LLM_KEY` is not set, explain to the user that semantic search requires an API key (`export LAT_LLM_KEY=sk-...` for OpenAI or `export LAT_LLM_KEY=vck_...` for Vercel). If the user doesn't want to set it up, use `lat_locate` for direct lookups instead.
31
+
32
+ # Syntax primer
33
+
34
+ - **Section ids**: `lat.md/path/to/file#Heading#SubHeading` — full form uses project-root-relative path (e.g. `lat.md/tests/search#RAG Replay Tests`). Short form uses bare file name when unique (e.g. `search#RAG Replay Tests`, `cli#search#Indexing`).
35
+ - **Wiki links**: `[[target]]` or `[[target|alias]]` — cross-references between sections. Can also reference source code: `[[src/foo.ts#myFunction]]`.
36
+ - **Source code links**: Wiki links in `lat.md/` files can reference functions, classes, constants, and methods in TypeScript/JavaScript/Python/Rust/Go/C files. Use the full path: `[[src/config.ts#getConfigDir]]`, `[[src/server.ts#App#listen]]` (class method), `[[lib/utils.py#parse_args]]`, `[[src/lib.rs#Greeter#greet]]` (Rust impl method), `[[src/app.go#Greeter#Greet]]` (Go method), `[[src/app.h#Greeter]]` (C struct). `lat check` validates these exist.
37
+ - **Code refs**: `// @lat: [[section-id]]` (JS/TS/Rust/Go/C) or `# @lat: [[section-id]]` (Python) — ties source code to concepts
38
+
39
+ # Test specs
40
+
41
+ Key tests can be described as sections in `lat.md/` files (e.g. `tests.md`). Add frontmatter to require that every leaf section is referenced by a `// @lat:` or `# @lat:` comment in test code:
42
+
43
+ ```markdown
44
+ ---
45
+ lat:
46
+ require-code-mention: true
47
+ ---
48
+ # Tests
49
+
50
+ Authentication and authorization test specifications.
51
+
52
+ ## User login
53
+
54
+ Verify credential validation and error handling for the login endpoint.
55
+
56
+ ### Rejects expired tokens
57
+ Tokens past their expiry timestamp are rejected with 401, even if otherwise valid.
58
+
59
+ ### Handles missing password
60
+ Login request without a password field returns 400 with a descriptive error.
61
+ ```
62
+
63
+ Every section MUST have a description — at least one sentence explaining what the test verifies and why. Empty sections with just a heading are not acceptable.
64
+
65
+ Each test in code should reference its spec with exactly one comment placed next to the relevant test — not at the top of the file:
66
+
67
+ ```python
68
+ # @lat: [[tests#User login#Rejects expired tokens]]
69
+ def test_rejects_expired_tokens():
70
+ ...
71
+
72
+ # @lat: [[tests#User login#Handles missing password]]
73
+ def test_handles_missing_password():
74
+ ...
75
+ ```
76
+
77
+ Do not duplicate refs. One `@lat:` comment per spec section, placed at the test that covers it. `lat check` will flag any spec section not covered by a code reference, and any code reference pointing to a nonexistent section.
@@ -0,0 +1 @@
1
+ This directory defines the high-level concepts, business logic, and architecture of this project using markdown. It is managed by [lat.md](https://www.npmjs.com/package/lat.md) — a tool that anchors source code to these definitions. Install the `lat` command with `npm i -g lat.md` and run `lat --help`.
@@ -0,0 +1,182 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 73224 16688" fill="#444">
2
+ <defs>
3
+ <path id="g2591" d="M934 -512V-251H1094V-512ZM298 -512V-251H457V-512ZM616 -147V114H775V-147ZM-20 -147V114H138V-147ZM934 219V480H1094V219ZM298 219V480H457V219ZM616 584V845H775V584ZM-20 584V845H138V584ZM934 950V1211H1094V950ZM298 950V1211H457V950ZM616 1315V1576H775V1315ZM-20 1315V1576H138V1315Z"/>
4
+ <path id="g2588" d="M-20 -512V1576H1253V-512Z"/>
5
+ </defs>
6
+ <use href="#g2591" transform="translate(0,0) scale(1,-1) translate(0,-1901)"/>
7
+ <use href="#g2588" transform="translate(1356,0) scale(1,-1) translate(0,-1901)"/>
8
+ <use href="#g2588" transform="translate(2712,0) scale(1,-1) translate(0,-1901)"/>
9
+ <use href="#g2591" transform="translate(21696,0) scale(1,-1) translate(0,-1901)"/>
10
+ <use href="#g2588" transform="translate(23052,0) scale(1,-1) translate(0,-1901)"/>
11
+ <use href="#g2588" transform="translate(24408,0) scale(1,-1) translate(0,-1901)"/>
12
+ <use href="#g2591" transform="translate(69156,0) scale(1,-1) translate(0,-1901)"/>
13
+ <use href="#g2588" transform="translate(70512,0) scale(1,-1) translate(0,-1901)"/>
14
+ <use href="#g2588" transform="translate(71868,0) scale(1,-1) translate(0,-1901)"/>
15
+ <use href="#g2591" transform="translate(0,2384) scale(1,-1) translate(0,-1901)"/>
16
+ <use href="#g2588" transform="translate(1356,2384) scale(1,-1) translate(0,-1901)"/>
17
+ <use href="#g2588" transform="translate(2712,2384) scale(1,-1) translate(0,-1901)"/>
18
+ <use href="#g2591" transform="translate(21696,2384) scale(1,-1) translate(0,-1901)"/>
19
+ <use href="#g2588" transform="translate(23052,2384) scale(1,-1) translate(0,-1901)"/>
20
+ <use href="#g2588" transform="translate(24408,2384) scale(1,-1) translate(0,-1901)"/>
21
+ <use href="#g2591" transform="translate(69156,2384) scale(1,-1) translate(0,-1901)"/>
22
+ <use href="#g2588" transform="translate(70512,2384) scale(1,-1) translate(0,-1901)"/>
23
+ <use href="#g2588" transform="translate(71868,2384) scale(1,-1) translate(0,-1901)"/>
24
+ <use href="#g2591" transform="translate(0,4768) scale(1,-1) translate(0,-1901)"/>
25
+ <use href="#g2588" transform="translate(1356,4768) scale(1,-1) translate(0,-1901)"/>
26
+ <use href="#g2588" transform="translate(2712,4768) scale(1,-1) translate(0,-1901)"/>
27
+ <use href="#g2591" transform="translate(6780,4768) scale(1,-1) translate(0,-1901)"/>
28
+ <use href="#g2588" transform="translate(8136,4768) scale(1,-1) translate(0,-1901)"/>
29
+ <use href="#g2588" transform="translate(9492,4768) scale(1,-1) translate(0,-1901)"/>
30
+ <use href="#g2588" transform="translate(10848,4768) scale(1,-1) translate(0,-1901)"/>
31
+ <use href="#g2588" transform="translate(12204,4768) scale(1,-1) translate(0,-1901)"/>
32
+ <use href="#g2588" transform="translate(13560,4768) scale(1,-1) translate(0,-1901)"/>
33
+ <use href="#g2588" transform="translate(14916,4768) scale(1,-1) translate(0,-1901)"/>
34
+ <use href="#g2591" transform="translate(18984,4768) scale(1,-1) translate(0,-1901)"/>
35
+ <use href="#g2588" transform="translate(20340,4768) scale(1,-1) translate(0,-1901)"/>
36
+ <use href="#g2588" transform="translate(21696,4768) scale(1,-1) translate(0,-1901)"/>
37
+ <use href="#g2588" transform="translate(23052,4768) scale(1,-1) translate(0,-1901)"/>
38
+ <use href="#g2588" transform="translate(24408,4768) scale(1,-1) translate(0,-1901)"/>
39
+ <use href="#g2588" transform="translate(25764,4768) scale(1,-1) translate(0,-1901)"/>
40
+ <use href="#g2588" transform="translate(27120,4768) scale(1,-1) translate(0,-1901)"/>
41
+ <use href="#g2591" transform="translate(37968,4768) scale(1,-1) translate(0,-1901)"/>
42
+ <use href="#g2588" transform="translate(39324,4768) scale(1,-1) translate(0,-1901)"/>
43
+ <use href="#g2588" transform="translate(40680,4768) scale(1,-1) translate(0,-1901)"/>
44
+ <use href="#g2588" transform="translate(42036,4768) scale(1,-1) translate(0,-1901)"/>
45
+ <use href="#g2588" transform="translate(43392,4768) scale(1,-1) translate(0,-1901)"/>
46
+ <use href="#g2588" transform="translate(44748,4768) scale(1,-1) translate(0,-1901)"/>
47
+ <use href="#g2588" transform="translate(46104,4768) scale(1,-1) translate(0,-1901)"/>
48
+ <use href="#g2588" transform="translate(47460,4768) scale(1,-1) translate(0,-1901)"/>
49
+ <use href="#g2588" transform="translate(48816,4768) scale(1,-1) translate(0,-1901)"/>
50
+ <use href="#g2588" transform="translate(50172,4768) scale(1,-1) translate(0,-1901)"/>
51
+ <use href="#g2588" transform="translate(51528,4768) scale(1,-1) translate(0,-1901)"/>
52
+ <use href="#g2588" transform="translate(52884,4768) scale(1,-1) translate(0,-1901)"/>
53
+ <use href="#g2588" transform="translate(54240,4768) scale(1,-1) translate(0,-1901)"/>
54
+ <use href="#g2588" transform="translate(55596,4768) scale(1,-1) translate(0,-1901)"/>
55
+ <use href="#g2591" transform="translate(61020,4768) scale(1,-1) translate(0,-1901)"/>
56
+ <use href="#g2588" transform="translate(62376,4768) scale(1,-1) translate(0,-1901)"/>
57
+ <use href="#g2588" transform="translate(63732,4768) scale(1,-1) translate(0,-1901)"/>
58
+ <use href="#g2588" transform="translate(65088,4768) scale(1,-1) translate(0,-1901)"/>
59
+ <use href="#g2588" transform="translate(66444,4768) scale(1,-1) translate(0,-1901)"/>
60
+ <use href="#g2588" transform="translate(67800,4768) scale(1,-1) translate(0,-1901)"/>
61
+ <use href="#g2588" transform="translate(69156,4768) scale(1,-1) translate(0,-1901)"/>
62
+ <use href="#g2588" transform="translate(70512,4768) scale(1,-1) translate(0,-1901)"/>
63
+ <use href="#g2588" transform="translate(71868,4768) scale(1,-1) translate(0,-1901)"/>
64
+ <use href="#g2591" transform="translate(0,7152) scale(1,-1) translate(0,-1901)"/>
65
+ <use href="#g2588" transform="translate(1356,7152) scale(1,-1) translate(0,-1901)"/>
66
+ <use href="#g2588" transform="translate(2712,7152) scale(1,-1) translate(0,-1901)"/>
67
+ <use href="#g2591" transform="translate(13560,7152) scale(1,-1) translate(0,-1901)"/>
68
+ <use href="#g2588" transform="translate(14916,7152) scale(1,-1) translate(0,-1901)"/>
69
+ <use href="#g2588" transform="translate(16272,7152) scale(1,-1) translate(0,-1901)"/>
70
+ <use href="#g2591" transform="translate(21696,7152) scale(1,-1) translate(0,-1901)"/>
71
+ <use href="#g2588" transform="translate(23052,7152) scale(1,-1) translate(0,-1901)"/>
72
+ <use href="#g2588" transform="translate(24408,7152) scale(1,-1) translate(0,-1901)"/>
73
+ <use href="#g2591" transform="translate(37968,7152) scale(1,-1) translate(0,-1901)"/>
74
+ <use href="#g2588" transform="translate(39324,7152) scale(1,-1) translate(0,-1901)"/>
75
+ <use href="#g2588" transform="translate(40680,7152) scale(1,-1) translate(0,-1901)"/>
76
+ <use href="#g2591" transform="translate(46104,7152) scale(1,-1) translate(0,-1901)"/>
77
+ <use href="#g2588" transform="translate(47460,7152) scale(1,-1) translate(0,-1901)"/>
78
+ <use href="#g2588" transform="translate(48816,7152) scale(1,-1) translate(0,-1901)"/>
79
+ <use href="#g2591" transform="translate(54240,7152) scale(1,-1) translate(0,-1901)"/>
80
+ <use href="#g2588" transform="translate(55596,7152) scale(1,-1) translate(0,-1901)"/>
81
+ <use href="#g2588" transform="translate(56952,7152) scale(1,-1) translate(0,-1901)"/>
82
+ <use href="#g2591" transform="translate(59664,7152) scale(1,-1) translate(0,-1901)"/>
83
+ <use href="#g2588" transform="translate(61020,7152) scale(1,-1) translate(0,-1901)"/>
84
+ <use href="#g2588" transform="translate(62376,7152) scale(1,-1) translate(0,-1901)"/>
85
+ <use href="#g2591" transform="translate(69156,7152) scale(1,-1) translate(0,-1901)"/>
86
+ <use href="#g2588" transform="translate(70512,7152) scale(1,-1) translate(0,-1901)"/>
87
+ <use href="#g2588" transform="translate(71868,7152) scale(1,-1) translate(0,-1901)"/>
88
+ <use href="#g2591" transform="translate(0,9536) scale(1,-1) translate(0,-1901)"/>
89
+ <use href="#g2588" transform="translate(1356,9536) scale(1,-1) translate(0,-1901)"/>
90
+ <use href="#g2588" transform="translate(2712,9536) scale(1,-1) translate(0,-1901)"/>
91
+ <use href="#g2591" transform="translate(6780,9536) scale(1,-1) translate(0,-1901)"/>
92
+ <use href="#g2588" transform="translate(8136,9536) scale(1,-1) translate(0,-1901)"/>
93
+ <use href="#g2588" transform="translate(9492,9536) scale(1,-1) translate(0,-1901)"/>
94
+ <use href="#g2588" transform="translate(10848,9536) scale(1,-1) translate(0,-1901)"/>
95
+ <use href="#g2588" transform="translate(12204,9536) scale(1,-1) translate(0,-1901)"/>
96
+ <use href="#g2588" transform="translate(13560,9536) scale(1,-1) translate(0,-1901)"/>
97
+ <use href="#g2588" transform="translate(14916,9536) scale(1,-1) translate(0,-1901)"/>
98
+ <use href="#g2588" transform="translate(16272,9536) scale(1,-1) translate(0,-1901)"/>
99
+ <use href="#g2591" transform="translate(21696,9536) scale(1,-1) translate(0,-1901)"/>
100
+ <use href="#g2588" transform="translate(23052,9536) scale(1,-1) translate(0,-1901)"/>
101
+ <use href="#g2588" transform="translate(24408,9536) scale(1,-1) translate(0,-1901)"/>
102
+ <use href="#g2591" transform="translate(37968,9536) scale(1,-1) translate(0,-1901)"/>
103
+ <use href="#g2588" transform="translate(39324,9536) scale(1,-1) translate(0,-1901)"/>
104
+ <use href="#g2588" transform="translate(40680,9536) scale(1,-1) translate(0,-1901)"/>
105
+ <use href="#g2591" transform="translate(46104,9536) scale(1,-1) translate(0,-1901)"/>
106
+ <use href="#g2588" transform="translate(47460,9536) scale(1,-1) translate(0,-1901)"/>
107
+ <use href="#g2588" transform="translate(48816,9536) scale(1,-1) translate(0,-1901)"/>
108
+ <use href="#g2591" transform="translate(54240,9536) scale(1,-1) translate(0,-1901)"/>
109
+ <use href="#g2588" transform="translate(55596,9536) scale(1,-1) translate(0,-1901)"/>
110
+ <use href="#g2588" transform="translate(56952,9536) scale(1,-1) translate(0,-1901)"/>
111
+ <use href="#g2591" transform="translate(59664,9536) scale(1,-1) translate(0,-1901)"/>
112
+ <use href="#g2588" transform="translate(61020,9536) scale(1,-1) translate(0,-1901)"/>
113
+ <use href="#g2588" transform="translate(62376,9536) scale(1,-1) translate(0,-1901)"/>
114
+ <use href="#g2591" transform="translate(69156,9536) scale(1,-1) translate(0,-1901)"/>
115
+ <use href="#g2588" transform="translate(70512,9536) scale(1,-1) translate(0,-1901)"/>
116
+ <use href="#g2588" transform="translate(71868,9536) scale(1,-1) translate(0,-1901)"/>
117
+ <use href="#g2591" transform="translate(0,11920) scale(1,-1) translate(0,-1901)"/>
118
+ <use href="#g2588" transform="translate(1356,11920) scale(1,-1) translate(0,-1901)"/>
119
+ <use href="#g2588" transform="translate(2712,11920) scale(1,-1) translate(0,-1901)"/>
120
+ <use href="#g2591" transform="translate(5424,11920) scale(1,-1) translate(0,-1901)"/>
121
+ <use href="#g2588" transform="translate(6780,11920) scale(1,-1) translate(0,-1901)"/>
122
+ <use href="#g2588" transform="translate(8136,11920) scale(1,-1) translate(0,-1901)"/>
123
+ <use href="#g2591" transform="translate(13560,11920) scale(1,-1) translate(0,-1901)"/>
124
+ <use href="#g2588" transform="translate(14916,11920) scale(1,-1) translate(0,-1901)"/>
125
+ <use href="#g2588" transform="translate(16272,11920) scale(1,-1) translate(0,-1901)"/>
126
+ <use href="#g2591" transform="translate(21696,11920) scale(1,-1) translate(0,-1901)"/>
127
+ <use href="#g2588" transform="translate(23052,11920) scale(1,-1) translate(0,-1901)"/>
128
+ <use href="#g2588" transform="translate(24408,11920) scale(1,-1) translate(0,-1901)"/>
129
+ <use href="#g2591" transform="translate(37968,11920) scale(1,-1) translate(0,-1901)"/>
130
+ <use href="#g2588" transform="translate(39324,11920) scale(1,-1) translate(0,-1901)"/>
131
+ <use href="#g2588" transform="translate(40680,11920) scale(1,-1) translate(0,-1901)"/>
132
+ <use href="#g2591" transform="translate(46104,11920) scale(1,-1) translate(0,-1901)"/>
133
+ <use href="#g2588" transform="translate(47460,11920) scale(1,-1) translate(0,-1901)"/>
134
+ <use href="#g2588" transform="translate(48816,11920) scale(1,-1) translate(0,-1901)"/>
135
+ <use href="#g2591" transform="translate(54240,11920) scale(1,-1) translate(0,-1901)"/>
136
+ <use href="#g2588" transform="translate(55596,11920) scale(1,-1) translate(0,-1901)"/>
137
+ <use href="#g2588" transform="translate(56952,11920) scale(1,-1) translate(0,-1901)"/>
138
+ <use href="#g2591" transform="translate(59664,11920) scale(1,-1) translate(0,-1901)"/>
139
+ <use href="#g2588" transform="translate(61020,11920) scale(1,-1) translate(0,-1901)"/>
140
+ <use href="#g2588" transform="translate(62376,11920) scale(1,-1) translate(0,-1901)"/>
141
+ <use href="#g2591" transform="translate(67800,11920) scale(1,-1) translate(0,-1901)"/>
142
+ <use href="#g2588" transform="translate(69156,11920) scale(1,-1) translate(0,-1901)"/>
143
+ <use href="#g2588" transform="translate(70512,11920) scale(1,-1) translate(0,-1901)"/>
144
+ <use href="#g2588" transform="translate(71868,11920) scale(1,-1) translate(0,-1901)"/>
145
+ <use href="#g2591" transform="translate(0,14304) scale(1,-1) translate(0,-1901)"/>
146
+ <use href="#g2588" transform="translate(1356,14304) scale(1,-1) translate(0,-1901)"/>
147
+ <use href="#g2588" transform="translate(2712,14304) scale(1,-1) translate(0,-1901)"/>
148
+ <use href="#g2591" transform="translate(6780,14304) scale(1,-1) translate(0,-1901)"/>
149
+ <use href="#g2588" transform="translate(8136,14304) scale(1,-1) translate(0,-1901)"/>
150
+ <use href="#g2588" transform="translate(9492,14304) scale(1,-1) translate(0,-1901)"/>
151
+ <use href="#g2588" transform="translate(10848,14304) scale(1,-1) translate(0,-1901)"/>
152
+ <use href="#g2588" transform="translate(12204,14304) scale(1,-1) translate(0,-1901)"/>
153
+ <use href="#g2588" transform="translate(13560,14304) scale(1,-1) translate(0,-1901)"/>
154
+ <use href="#g2591" transform="translate(14916,14304) scale(1,-1) translate(0,-1901)"/>
155
+ <use href="#g2588" transform="translate(16272,14304) scale(1,-1) translate(0,-1901)"/>
156
+ <use href="#g2588" transform="translate(17628,14304) scale(1,-1) translate(0,-1901)"/>
157
+ <use href="#g2591" transform="translate(23052,14304) scale(1,-1) translate(0,-1901)"/>
158
+ <use href="#g2588" transform="translate(24408,14304) scale(1,-1) translate(0,-1901)"/>
159
+ <use href="#g2588" transform="translate(25764,14304) scale(1,-1) translate(0,-1901)"/>
160
+ <use href="#g2588" transform="translate(27120,14304) scale(1,-1) translate(0,-1901)"/>
161
+ <use href="#g2591" transform="translate(31188,14304) scale(1,-1) translate(0,-1901)"/>
162
+ <use href="#g2588" transform="translate(32544,14304) scale(1,-1) translate(0,-1901)"/>
163
+ <use href="#g2588" transform="translate(33900,14304) scale(1,-1) translate(0,-1901)"/>
164
+ <use href="#g2591" transform="translate(37968,14304) scale(1,-1) translate(0,-1901)"/>
165
+ <use href="#g2588" transform="translate(39324,14304) scale(1,-1) translate(0,-1901)"/>
166
+ <use href="#g2588" transform="translate(40680,14304) scale(1,-1) translate(0,-1901)"/>
167
+ <use href="#g2591" transform="translate(46104,14304) scale(1,-1) translate(0,-1901)"/>
168
+ <use href="#g2588" transform="translate(47460,14304) scale(1,-1) translate(0,-1901)"/>
169
+ <use href="#g2588" transform="translate(48816,14304) scale(1,-1) translate(0,-1901)"/>
170
+ <use href="#g2591" transform="translate(54240,14304) scale(1,-1) translate(0,-1901)"/>
171
+ <use href="#g2588" transform="translate(55596,14304) scale(1,-1) translate(0,-1901)"/>
172
+ <use href="#g2588" transform="translate(56952,14304) scale(1,-1) translate(0,-1901)"/>
173
+ <use href="#g2591" transform="translate(61020,14304) scale(1,-1) translate(0,-1901)"/>
174
+ <use href="#g2588" transform="translate(62376,14304) scale(1,-1) translate(0,-1901)"/>
175
+ <use href="#g2588" transform="translate(63732,14304) scale(1,-1) translate(0,-1901)"/>
176
+ <use href="#g2588" transform="translate(65088,14304) scale(1,-1) translate(0,-1901)"/>
177
+ <use href="#g2588" transform="translate(66444,14304) scale(1,-1) translate(0,-1901)"/>
178
+ <use href="#g2588" transform="translate(67800,14304) scale(1,-1) translate(0,-1901)"/>
179
+ <use href="#g2591" transform="translate(69156,14304) scale(1,-1) translate(0,-1901)"/>
180
+ <use href="#g2588" transform="translate(70512,14304) scale(1,-1) translate(0,-1901)"/>
181
+ <use href="#g2588" transform="translate(71868,14304) scale(1,-1) translate(0,-1901)"/>
182
+ </svg>