From bd24605410a21c2593b07ae74246c595ef008550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20K=C3=B6nig?= Date: Thu, 16 Apr 2026 08:23:07 +0200 Subject: [PATCH 1/5] feat: update code and docs --- src/cli/check.ts | 35 +++++++++----- tests/cases.test.ts | 47 ++++++++++++++++++- .../lat.md/docs.md | 5 ++ .../src/components/.gitkeep | 0 .../lat.md/docs.md | 7 +++ .../source-ref-folder-valid/lat.md/docs.md | 3 ++ .../src/components/.gitkeep | 0 .../src/pages/.gitkeep | 0 .../lat.md/docs.md | 3 ++ .../schema.sql | 1 + .../lat.md/docs.md | 3 ++ .../src/schema.sql | 1 + 12 files changed, 93 insertions(+), 12 deletions(-) create mode 100644 tests/cases/error-source-ref-bad-folder/lat.md/docs.md create mode 100644 tests/cases/error-source-ref-bad-folder/src/components/.gitkeep create mode 100644 tests/cases/error-source-ref-unsupported-ext-missing/lat.md/docs.md create mode 100644 tests/cases/source-ref-folder-valid/lat.md/docs.md create mode 100644 tests/cases/source-ref-folder-valid/src/components/.gitkeep create mode 100644 tests/cases/source-ref-folder-valid/src/pages/.gitkeep create mode 100644 tests/cases/source-ref-unsupported-ext-root-valid/lat.md/docs.md create mode 100644 tests/cases/source-ref-unsupported-ext-root-valid/schema.sql create mode 100644 tests/cases/source-ref-unsupported-ext-valid/lat.md/docs.md create mode 100644 tests/cases/source-ref-unsupported-ext-valid/src/schema.sql diff --git a/src/cli/check.ts b/src/cli/check.ts index e825f06..d920531 100644 --- a/src/cli/check.ts +++ b/src/cli/check.ts @@ -1,22 +1,21 @@ -import { readFile } from 'node:fs/promises'; import { existsSync } from 'node:fs'; +import { readFile } from 'node:fs/promises'; import { basename, dirname, extname, join, relative } from 'node:path'; +import { scanCodeRefs } from '../code-refs.js'; +import type { CmdContext, CmdResult, Styler } from '../context.js'; +import { INIT_VERSION, readInitVersion } from '../init-version.js'; import { - listLatticeFiles, - loadAllSections, + buildFileIndex, extractRefs, flattenSections, + listLatticeFiles, + loadAllSections, parseFrontmatter, parseSections, - buildFileIndex, resolveRef, - type Section, } from '../lattice.js'; -import { scanCodeRefs } from '../code-refs.js'; import { SOURCE_EXTENSIONS, clearSymbolCache } from '../source-parser.js'; import { walkEntries } from '../walk.js'; -import type { CmdContext, CmdResult, Styler } from '../context.js'; -import { INIT_VERSION, readInitVersion } from '../init-version.js'; export type CheckError = { file: string; @@ -92,14 +91,28 @@ async function tryResolveSourceRef( projectRoot: string, ): Promise { if (!isSourcePath(target)) { - // Check if it looks like a file path with an unsupported extension const hashIdx = target.indexOf('#'); const filePart = hashIdx === -1 ? target : target.slice(0, hashIdx); const ext = extname(filePart); - if (ext && hashIdx !== -1) { + + const targetHasHash = hashIdx !== -1; + + // Unsupported extension with # — can't validate symbols + if (ext && targetHasHash) { const supported = [...SOURCE_EXTENSIONS].sort().join(', '); - return `broken link [[${target}]] — unsupported file extension "${ext}". Supported: ${supported}`; + return `broken link [[${target}]] — unsupported file extension "${ext}". Symbol references (#) only supported for: ${supported}`; } + + // File or folder without # — validate existence + if (!targetHasHash) { + const absPath = join(projectRoot, filePart); + if (existsSync(absPath)) { + return null; + } + + return `broken link [[${target}]] — file or folder "${filePart}" not found`; + } + return `broken link [[${target}]] — no matching section found`; } diff --git a/tests/cases.test.ts b/tests/cases.test.ts index b9e0bb8..0de1428 100644 --- a/tests/cases.test.ts +++ b/tests/cases.test.ts @@ -951,13 +951,58 @@ describe('error-source-ref-unsupported-ext', () => { expect(errors).toHaveLength(1); expect(errors[0].target).toBe('src/app.blah#spam'); expect(errors[0].message).toContain('unsupported file extension ".blah"'); - expect(errors[0].message).toContain('Supported:'); + expect(errors[0].message).toContain('Symbol references (#) only supported for:'); expect(errors[0].message).toContain('.ts'); expect(errors[0].message).toContain('.rs'); expect(errors[0].message).toContain('.go'); }); }); +describe('source-ref-folder-valid', () => { + it('check md accepts wiki link to existing folder', async () => { + const { errors } = await checkMd(latDir('source-ref-folder-valid')); + expect(errors).toHaveLength(0); + }); +}); + +describe('error-source-ref-bad-folder', () => { + it('check md reports broken link for nonexistent folder and folder with symbol ref', async () => { + const { errors } = await checkMd(latDir('error-source-ref-bad-folder')); + expect(errors).toHaveLength(2); + const byTarget = new Map(errors.map((e) => [e.target, e])); + expect(byTarget.get('src/nonexistent')!.message).toContain('file or folder "src/nonexistent" not found'); + expect(byTarget.get('src/components#something')!.message).toContain('no matching section found'); + }); +}); + +describe('source-ref-unsupported-ext-valid', () => { + it('check md accepts wiki link to existing file with unsupported extension', async () => { + const { errors } = await checkMd(latDir('source-ref-unsupported-ext-valid')); + expect(errors).toHaveLength(0); + }); +}); + +describe('source-ref-unsupported-ext-root-valid', () => { + it('check md accepts wiki link to root-level file with unsupported extension', async () => { + const { errors } = await checkMd(latDir('source-ref-unsupported-ext-root-valid')); + expect(errors).toHaveLength(0); + }); +}); + +describe('error-source-ref-unsupported-ext-missing', () => { + it('check md reports broken link for missing unsupported-ext files and folders', async () => { + const { errors } = await checkMd(latDir('error-source-ref-unsupported-ext-missing')); + expect(errors).toHaveLength(3); + const targets = errors.map((e) => e.target); + expect(targets).toContain('nope.sql'); + expect(targets).toContain('src/missing.sql'); + expect(targets).toContain('src/missing/'); + for (const e of errors) { + expect(e.message).toContain('not found'); + } + }); +}); + // --- source file refs --- describe('source-file-refs', () => { diff --git a/tests/cases/error-source-ref-bad-folder/lat.md/docs.md b/tests/cases/error-source-ref-bad-folder/lat.md/docs.md new file mode 100644 index 0000000..cf1dec0 --- /dev/null +++ b/tests/cases/error-source-ref-bad-folder/lat.md/docs.md @@ -0,0 +1,5 @@ +# Docs + +Links to a nonexistent folder: [[src/nonexistent]]. + +Folder with symbol ref: [[src/components#something]]. diff --git a/tests/cases/error-source-ref-bad-folder/src/components/.gitkeep b/tests/cases/error-source-ref-bad-folder/src/components/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/cases/error-source-ref-unsupported-ext-missing/lat.md/docs.md b/tests/cases/error-source-ref-unsupported-ext-missing/lat.md/docs.md new file mode 100644 index 0000000..d512bd3 --- /dev/null +++ b/tests/cases/error-source-ref-unsupported-ext-missing/lat.md/docs.md @@ -0,0 +1,7 @@ +# Docs + +Missing root file: [[nope.sql]]. + +Missing pathed file: [[src/missing.sql]]. + +Missing pathed folder: [[src/missing/]]. diff --git a/tests/cases/source-ref-folder-valid/lat.md/docs.md b/tests/cases/source-ref-folder-valid/lat.md/docs.md new file mode 100644 index 0000000..fd23b4b --- /dev/null +++ b/tests/cases/source-ref-folder-valid/lat.md/docs.md @@ -0,0 +1,3 @@ +# Docs + +Links to a folder: [[src/components]] and [[src/pages/]]. diff --git a/tests/cases/source-ref-folder-valid/src/components/.gitkeep b/tests/cases/source-ref-folder-valid/src/components/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/cases/source-ref-folder-valid/src/pages/.gitkeep b/tests/cases/source-ref-folder-valid/src/pages/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/cases/source-ref-unsupported-ext-root-valid/lat.md/docs.md b/tests/cases/source-ref-unsupported-ext-root-valid/lat.md/docs.md new file mode 100644 index 0000000..c278b4b --- /dev/null +++ b/tests/cases/source-ref-unsupported-ext-root-valid/lat.md/docs.md @@ -0,0 +1,3 @@ +# Docs + +Links to a root-level SQL file: [[schema.sql]]. diff --git a/tests/cases/source-ref-unsupported-ext-root-valid/schema.sql b/tests/cases/source-ref-unsupported-ext-root-valid/schema.sql new file mode 100644 index 0000000..4e1b8dc --- /dev/null +++ b/tests/cases/source-ref-unsupported-ext-root-valid/schema.sql @@ -0,0 +1 @@ +CREATE TABLE users (id INTEGER PRIMARY KEY); diff --git a/tests/cases/source-ref-unsupported-ext-valid/lat.md/docs.md b/tests/cases/source-ref-unsupported-ext-valid/lat.md/docs.md new file mode 100644 index 0000000..395eff9 --- /dev/null +++ b/tests/cases/source-ref-unsupported-ext-valid/lat.md/docs.md @@ -0,0 +1,3 @@ +# Docs + +Links to a SQL file: [[src/schema.sql]]. diff --git a/tests/cases/source-ref-unsupported-ext-valid/src/schema.sql b/tests/cases/source-ref-unsupported-ext-valid/src/schema.sql new file mode 100644 index 0000000..4e1b8dc --- /dev/null +++ b/tests/cases/source-ref-unsupported-ext-valid/src/schema.sql @@ -0,0 +1 @@ +CREATE TABLE users (id INTEGER PRIMARY KEY); From 09c394c5332702a13a0bb561d0f0cc2ad80fa95a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20K=C3=B6nig?= Date: Thu, 16 Apr 2026 08:23:18 +0200 Subject: [PATCH 2/5] docs: update template --- templates/AGENTS.md | 2 +- templates/cursor-rules.md | 2 +- templates/skill/SKILL.md | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/templates/AGENTS.md b/templates/AGENTS.md index c544150..a161906 100644 --- a/templates/AGENTS.md +++ b/templates/AGENTS.md @@ -35,7 +35,7 @@ If `lat search` fails because no API key is configured, explain to the user that - **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`). - **Wiki links**: `[[target]]` or `[[target|alias]]` — cross-references between sections. Can also reference source code: `[[src/foo.ts#myFunction]]`. -- **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. +- **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). Can also link to folders (`[[src/components]]`) or files with any extension (`[[schema.sql]]`) — these are validated to exist. Symbol references (`#`) only work for supported extensions. `lat check` validates these exist. - **Code refs**: `// @lat: [[section-id]]` (JS/TS/Rust/Go/C) or `# @lat: [[section-id]]` (Python) — ties source code to concepts # Test specs diff --git a/templates/cursor-rules.md b/templates/cursor-rules.md index 7bab9a1..c60247f 100644 --- a/templates/cursor-rules.md +++ b/templates/cursor-rules.md @@ -33,7 +33,7 @@ If `lat_search` fails because `LAT_LLM_KEY` is not set, explain to the user that - **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`). - **Wiki links**: `[[target]]` or `[[target|alias]]` — cross-references between sections. Can also reference source code: `[[src/foo.ts#myFunction]]`. -- **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. +- **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). Can also link to folders (`[[src/components]]`) or files with any extension (`[[schema.sql]]`) — these are validated to exist. Symbol references (`#`) only work for supported extensions. `lat check` validates these exist. - **Code refs**: `// @lat: [[section-id]]` (JS/TS/Rust/Go/C) or `# @lat: [[section-id]]` (Python) — ties source code to concepts # Test specs diff --git a/templates/skill/SKILL.md b/templates/skill/SKILL.md index 4208385..8a96620 100644 --- a/templates/skill/SKILL.md +++ b/templates/skill/SKILL.md @@ -85,9 +85,11 @@ Reference functions, classes, constants, and methods in source files: [[src/lib.rs#Greeter#greet]] — Rust impl method [[src/app.go#Greeter#Greet]] — Go method [[src/app.h#Greeter]] — C struct +[[src/components]] — folder (existence check) +[[schema.sql]] — any file extension (existence check) ``` -`lat check` validates that all targets exist. +Symbol references (`#`) only work for supported extensions. File-only and folder links work with any path. `lat check` validates that all targets exist. ## Code refs From b5ebd7e255e5e58fc6bc1b7a1315d17eb6b89f9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20K=C3=B6nig?= Date: Thu, 16 Apr 2026 08:23:33 +0200 Subject: [PATCH 3/5] docs: update lat and AGENTS --- AGENTS.md | 2 +- CLAUDE.md | 2 +- lat.md/markdown.md | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 9c015aa..adbb855 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -36,7 +36,7 @@ If `lat search` fails because no API key is configured, explain to the user that - **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`). - **Wiki links**: `[[target]]` or `[[target|alias]]` — cross-references between sections. Can also reference source code: `[[src/foo.ts#myFunction]]`. -- **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. +- **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). Can also link to folders (`[[src/components]]`) or files with any extension (`[[schema.sql]]`) — these are validated to exist. Symbol references (`#`) only work for supported extensions. `lat check` validates these exist. - **Code refs**: `// @lat: [[section-id]]` (JS/TS/Rust/Go/C) or `# @lat: [[section-id]]` (Python) — ties source code to concepts # Test specs diff --git a/CLAUDE.md b/CLAUDE.md index 9c015aa..adbb855 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -36,7 +36,7 @@ If `lat search` fails because no API key is configured, explain to the user that - **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`). - **Wiki links**: `[[target]]` or `[[target|alias]]` — cross-references between sections. Can also reference source code: `[[src/foo.ts#myFunction]]`. -- **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. +- **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). Can also link to folders (`[[src/components]]`) or files with any extension (`[[schema.sql]]`) — these are validated to exist. Symbol references (`#`) only work for supported extensions. `lat check` validates these exist. - **Code refs**: `// @lat: [[section-id]]` (JS/TS/Rust/Go/C) or `# @lat: [[section-id]]` (Python) — ties source code to concepts # Test specs diff --git a/lat.md/markdown.md b/lat.md/markdown.md index bdb21b1..f1ab74f 100644 --- a/lat.md/markdown.md +++ b/lat.md/markdown.md @@ -41,8 +41,10 @@ Wiki links can reference symbols in TypeScript, JavaScript, Python, Rust, Go, an - **`[[src/app.h#Greeter]]`** — the `Greeter` struct in a C header - **`[[src/app.h#Greeter#prefix]]`** — the `prefix` field of struct `Greeter` in C - **`[[src/config.ts]]`** — link to the file itself (no symbol) +- **`[[src/components]]`** — link to a folder (validated to exist) +- **`[[src/schema.sql]]`** — link to a file with any extension (validated to exist) -Supported extensions: `.ts`, `.tsx`, `.js`, `.jsx`, `.py`, `.rs`, `.go`, `.c`, `.h`. +Symbol references (`#`) require a supported extension: `.ts`, `.tsx`, `.js`, `.jsx`, `.py`, `.rs`, `.go`, `.c`, `.h`. File-only and folder links work with any path. Python symbols: functions, classes, methods, module-level variables. Decorated definitions (`@decorator`) are unwrapped transparently — `[[file.py#my_func]]` resolves whether or not `my_func` has decorators, and `# @lat:` comments placed between decorators and the `def`/`class` line are scanned normally. From d4f1cff71f34cf5a3691debd5087cf4e75fde2fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20K=C3=B6nig?= Date: Thu, 16 Apr 2026 09:18:18 +0200 Subject: [PATCH 4/5] fix: tests --- tests/cases.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cases.test.ts b/tests/cases.test.ts index 0de1428..f0ad543 100644 --- a/tests/cases.test.ts +++ b/tests/cases.test.ts @@ -658,7 +658,7 @@ describe('error-bare-heading-ref', () => { const { errors } = await checkMd(lat); const bare = errors.find((e) => e.target === 'Installation'); expect(bare).toBeDefined(); - expect(bare!.message).toContain('no matching section found'); + expect(bare!.message).toContain('not found'); }); // @lat: [[ref-resolution#Local section syntax in md is error]] @@ -666,7 +666,7 @@ describe('error-bare-heading-ref', () => { const { errors } = await checkMd(lat); const local = errors.find((e) => e.target === '#Configuration'); expect(local).toBeDefined(); - expect(local!.message).toContain('no matching section found'); + expect(local!.message).toContain('broken link'); }); // @lat: [[ref-resolution#Nonexistent file ref in md is error]] From 2b5d279fc8b9e24c0389adfdaec2d50ca0e3746b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20K=C3=B6nig?= Date: Mon, 20 Apr 2026 17:33:18 +0200 Subject: [PATCH 5/5] [all_file-and-folder-support] clarify new lat capabilities --- lat.md/markdown.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/lat.md/markdown.md b/lat.md/markdown.md index f1ab74f..2f87740 100644 --- a/lat.md/markdown.md +++ b/lat.md/markdown.md @@ -32,19 +32,25 @@ Resolution is handled by [[src/lattice.ts#resolveRef]]. See [[parser#Short Ref R ### Source Code Links -Wiki links can reference symbols in TypeScript, JavaScript, Python, Rust, Go, and C source files: +Wiki links can point to any file or folder in the project, and — for supported languages — to individual symbols within a source file. + +**Symbol targets** (use `#` to select a symbol inside a file): - **`[[src/config.ts#getConfigDir]]`** — the `getConfigDir` function in `src/config.ts` -- **`[[src/server.ts#App#listen]]`** — the `listen` method on class `App` in `src/server.ts` +- **`[[src/server.ts#App#listen]]`** — the `listen` method on class `App` - **`[[src/lib.rs#Greeter#greet]]`** — the `greet` method on struct `Greeter` in Rust - **`[[src/app.go#Greeter#Greet]]`** — the `Greet` method on type `Greeter` in Go - **`[[src/app.h#Greeter]]`** — the `Greeter` struct in a C header - **`[[src/app.h#Greeter#prefix]]`** — the `prefix` field of struct `Greeter` in C -- **`[[src/config.ts]]`** — link to the file itself (no symbol) -- **`[[src/components]]`** — link to a folder (validated to exist) -- **`[[src/schema.sql]]`** — link to a file with any extension (validated to exist) -Symbol references (`#`) require a supported extension: `.ts`, `.tsx`, `.js`, `.jsx`, `.py`, `.rs`, `.go`, `.c`, `.h`. File-only and folder links work with any path. +**Path targets** (no `#` — any file or folder in the project): + +- **`[[src/config.ts]]`** — a source file, linked without picking a symbol +- **`[[src/schema.sql]]`** — a file with any extension +- **`[[docs/CHANGELOG]]`** — a file with no extension +- **`[[src/components]]`** — a folder + +`lat check` verifies path targets exist on disk and symbol targets resolve to a real definition. Symbol targets (`#`) are only supported for these extensions: `.ts`, `.tsx`, `.js`, `.jsx`, `.py`, `.rs`, `.go`, `.c`, `.h`. Using `#` with any other extension (e.g. `[[schema.sql#foo]]`) is an error. Python symbols: functions, classes, methods, module-level variables. Decorated definitions (`@decorator`) are unwrapped transparently — `[[file.py#my_func]]` resolves whether or not `my_func` has decorators, and `# @lat:` comments placed between decorators and the `def`/`class` line are scanned normally.