Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ dist
.codex
.cursor/hooks.json
.cursor
opencode.json
39 changes: 36 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@

## The idea

Compress the knowledge about your program domain into a **graph** — a set of interconnected markdown files that live in a `lat.md/` directory at the root of your project. Sections link to each other with `[[wiki links]]`, markdown files link into the codebase (`[[src/auth.ts#validateToken]]`), source files link back with `// @lat: [[section-id]]` comments, and `lat check` ensures nothing drifts out of sync.
Compress the knowledge about your program domain into a **graph** — a set of interconnected markdown files that live in a `lat.md/` directory at the root of your project. Sections link to each other with `[[wiki links]]`, markdown files link into the codebase (`[[src/auth.ts#validateToken]]`) or pinned external sources (`[[architecture-docs:docs/system/request-flow.md#L123]]`), source files link back with `// @lat: [[section-id]]` comments, and `lat check` ensures nothing drifts out of sync.

- **Faster coding for agents** — instead of grepping through your codebase, agents search the knowledge graph to discover key design decisions, constraints, and domain context fast and consistently.

- **Faster workflow for humans** — your agents maintain lat files for you. When you review a diff, start with the semantic changes in `lat.md/` to understand *what* changed and *why*. Reviewing code becomes the secondary task.
- **Faster workflow for humans** — your agents maintain lat files for you. When you review a diff, start with the semantic changes in `lat.md/` to understand _what_ changed and _why_. Reviewing code becomes the secondary task.

- **Knowledge retention** — the context and reasoning behind your prompts is usually lost after a session ends. With lat, agents capture that knowledge into the graph as they work, so future sessions start with full context instead of rediscovering it from scratch.

Expand All @@ -43,7 +43,7 @@ Then run `lat init` in the repo you want to use lat in.

## How it works

Run `lat init` to scaffold a `lat.md/` directory, then write markdown files describing your architecture, business logic, test specs — whatever matters. Link between sections using `[[file#Section#Subsection]]` syntax. Link to source code symbols with `[[src/auth.ts#validateToken]]`. Annotate source code with `// @lat: [[section-id]]` (or `# @lat: [[section-id]]` in Python) comments to tie implementation back to concepts.
Run `lat init` to scaffold a `lat.md/` directory, then write markdown files describing your architecture, business logic, test specs — whatever matters. Link between sections using `[[file#Section#Subsection]]` syntax. Link to source code symbols with `[[src/auth.ts#validateToken]]`. You can also define external source handles in `lat.md/lat.md` frontmatter and link to them with `[[handle:path#fragment]]`. Annotate source code with `// @lat: [[section-id]]` (or `# @lat: [[section-id]]` in Python) comments to tie implementation back to concepts.

```
my-project/
Expand All @@ -65,6 +65,7 @@ lat check # validate all wiki links and code refs
lat locate "OAuth Flow" # find sections by name (exact, fuzzy)
lat section "auth#OAuth Flow" # show a section with its links and refs
lat refs "auth#OAuth Flow" # find what references a section
lat get-source architecture-docs # show repo URL or local checkout for a handle
lat search "how do we auth?" # semantic search via embeddings
lat expand "fix [[OAuth Flow]]" # expand [[refs]] in a prompt for agents
lat mcp # start MCP server for editor integration
Expand All @@ -79,6 +80,38 @@ Semantic search (`lat search`) requires an OpenAI (`sk-...`) or Vercel AI Gatewa
3. `LAT_LLM_KEY_HELPER` env var — shell command that prints the key (10s timeout)
4. Config file — saved by `lat init`. Run `lat config` to see its location.

External source handles are configured per project:

- Canonical handle definitions live in `lat.md/lat.md` frontmatter under `lat.external-sources`
- Machine-local checkout overrides live in `lat.md/config.local.json` under the same `lat.external-sources` key path, using `path`

Example:

```yaml
---
lat:
external-sources:
architecture-docs:
repo: https://example.com/architecture-docs.git
rev: v6.9
browse: https://example.com/architecture-docs/tree/{path}?h={rev}#{fragment}
---
```

```json
{
"lat": {
"external-sources": {
"architecture-docs": {
"path": "~/src/architecture-docs"
}
}
}
}
```

Local override `path` values may start with `~/`; `lat` expands that to the current user's home directory before validating or navigating the checkout.

## Development

Requires Node.js 22+ and pnpm.
Expand Down
1 change: 1 addition & 0 deletions lat.md/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.obsidian
.cache
*.canvas
config.local.json
37 changes: 31 additions & 6 deletions lat.md/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Output:

1. Section header with id and file location
2. Section content blockquoted (`>`) from `startLine` through the end of the last descendant subsection
3. **This section references** — all wiki link targets found within the section, including both lat.md section refs (with body descriptions) and source code refs (with file path and line range, e.g. `file.ts:10-25`, plus a 5-line snippet centered on the symbol)
3. **This section references** — all wiki link targets found within the section, including lat.md section refs (with body descriptions), source code refs (with file path and line range, e.g. `file.ts:10-25`, plus a 5-line snippet centered on the symbol), and external source refs (with the active local or canonical destination, plus resolved line ranges when a local checkout can map a line fragment or AsciiDoc heading fragment)
4. **Referenced by** — other sections in `lat.md/` that contain wiki links pointing to this section
5. **Referenced by code** — source files containing `@lat:` comments that reference this section, each shown with file path, line number, and a 5-line snippet centered on the reference
6. **Navigation hints** — same footer as [[cli#search]], suggesting `lat section` and `lat search` as next steps
Expand All @@ -41,12 +41,14 @@ Core logic in [[src/cli/section.ts#getSection]] (returns structured result), use

## refs

Find sections that reference a given target via [[parser#Wiki Links]]. The query can be a section id or a source file path.
Find sections that reference a given target via [[parser#Wiki Links]]. The query can be a section id, a source file path, or an exact external source target.

**Section queries** (e.g. `section-parsing#Heading`) are resolved via `findSections` when `resolveRef` doesn't produce an exact match, as long as the result is unambiguous (exact, stem-expanded, or section-name match). If no confident match exists, shows "Did you mean:" suggestions and exits.

**Source file queries** (e.g. `src/app.rs#greet`, `src/app.ts`) are detected when the file part has a recognized source extension and exists on disk. File-level queries (no `#`) match all wiki links targeting that file or any symbol in it. Symbol-level queries match exactly.

**External source queries** (e.g. `architecture-docs:docs/system/request-flow.md#L123`) are matched exactly against configured external targets from [[markdown#Frontmatter#external-sources]]. They return markdown sections that reference that exact handle/path/fragment.

Outputs a [[cli#Section Preview]] for each referring section.

Usage: `lat refs <query> [--scope=md|code|md+code]`
Expand All @@ -59,11 +61,21 @@ Usage: `lat refs <query> [--scope=md|code|md+code]`

Core logic in [[src/cli/refs.ts#findRefs]] (returns structured result), used by both the CLI command and [[cli#mcp]] `lat_refs` tool.

## get-source

Resolve a configured external source handle to its active location, preferring a valid local checkout path and otherwise falling back to the canonical repository URL.

Usage: `lat get-source <handle>`

This is for handle-level lookup, not file-level deep links. For example, `lat get-source architecture-docs` returns either the pinned local checkout root from `lat.md/config.local.json` or the canonical `repo` URL from `lat.md/lat.md` frontmatter.

Implementation: [[src/cli/get-source.ts#getSourceCommand]]

## check

Validation command group. Runs all checks when invoked without a subcommand.

Usage: `lat check [md|code-refs|index|sections]`
Usage: `lat check [md|code-refs|index|sections] [--ignore-local-overrides]`

Emits a stale-init warning before any errors so the user sees setup issues first. The init version check compares `INIT_VERSION` in [[src/init-version.ts]] against the version in `lat.md/.cache/lat_init.json` written by [[cli#init]]. Missing LLM key warning appears only when all checks pass. If the total check took longer than one second and ripgrep is not installed, shows a tip suggesting the user install it for faster scanning. The first output line ("Scanned ...") includes the total elapsed time (e.g. "in 250ms" or "in 1.2s").

Expand All @@ -73,13 +85,19 @@ Implementation: [[src/cli/check.ts]]

Validate that all [[parser#Wiki Links]] in `lat.md` markdown files point to existing sections.

Configured external refs in `[[handle:path#fragment]]` form are also accepted here. `check md` validates the handle definition, required canonical fields (`repo`, `rev`, `browse`), and any local override path from `lat.md/config.local.json`.

`--ignore-local-overrides` treats `lat.md/config.local.json` as absent for that check run. Use it when you want a portable check that validates only checked-in canonical config and ignores machine-specific local override errors.

### code-refs

Two validations:

1. Every `// @lat: [[...]]` or `# @lat: [[...]]` comment in source code must point to a real section in `lat.md/`
2. For files with [[markdown#Frontmatter#require-code-mention]], every leaf section must be referenced by at least one `// @lat:` comment in the codebase

Configured external refs in `[[handle:path#fragment]]` form are also accepted here. `check code-refs` treats them as valid when the handle exists in `lat.external-sources`.

### sections

Validate that every section has a well-formed leading paragraph. Two checks:
Expand All @@ -97,7 +115,7 @@ Each index file must contain a bullet list covering every visible file and subdi

Four checks:

1. **Non-markdown files** — any file without a `.md` extension is flagged as an error (only markdown belongs in `lat.md/`)
1. **Non-markdown files** — any file without a `.md` extension is flagged as an error (only markdown belongs in `lat.md/`), except for `lat.md/config.local.json`
2. **Missing index file** — errors with a ready-to-copy bullet list snippet
3. **Missing entries** — index file exists but doesn't list all visible entries
4. **Stale entries** — index file lists an entry that doesn't exist on disk
Expand All @@ -117,6 +135,8 @@ For each `[[ref]]` in the input, uses `findSections()` directly (no `resolveRef`
1. **Best match** — resolves to the top result from `findSections` (exact > file stem > subsection > subsequence > fuzzy)
2. **No match** — errors out, tells the agent to ask the user to correct the reference

Configured external refs are not rewritten inline. Instead, `lat expand` keeps `[[handle:path#fragment]]` as authored and appends context describing the external handle, pinned revision, and active local or canonical destination.

Output replaces `[[ref]]` with `[[resolved-id]]` inline and appends a `<lat-context>` block as a nested outliner. For exact matches: `is referring to:`. For non-exact: `might be referring to either of the following:` with all candidates, match reasons, locations, and body text.

Implementation: [[src/cli/expand.ts]]
Expand Down Expand Up @@ -147,7 +167,7 @@ Usage: `lat init [dir]`

Steps:

1. **lat.md/ directory** — if not present, asks whether to create it (via a one-off readline interface that is closed before step 2). Scaffolds from `templates/init/` (`.gitignore` and `README.md`). If it already exists, skips ahead.
1. **lat.md/ directory** — if not present, asks whether to create it (via a one-off readline interface that is closed before step 2). Scaffolds from `templates/init/` (`.gitignore` and `README.md`). If it already exists, skips ahead. Re-runs also ensure `lat.md/.gitignore` includes `config.local.json` for local external source overrides.
2. **Agent selection** — interactive checklist menu ([[src/cli/checklist-menu.ts#checklistMenu]]). All agents are shown at once with `[x]`/`[ ]` checkboxes; the cursor row is highlighted with `chalk.bgCyan`. Keys: up/down (j/k) to move, Space to toggle, Enter to confirm, Ctrl+C to abort. Returns an array of selected agent values. Non-TTY fallback returns `[]`. After confirmation, prints a summary line (e.g. "Selected: Claude Code, Cursor" or dim "None"). **Important:** the persistent readline interface is created _after_ this step — `checklistMenu` puts stdin into raw mode with its own `data` listener, which corrupts any co-existing readline interface.
3. **Command style** — if any selected agent needs a lat command reference (all except Codex), a `selectMenu` asks "How should agents run lat?" with three options: `lat` (global install, portable), the resolved local binary path, or `npx lat.md@latest` (slow but zero-install). The choice determines what command string is written into hooks, MCP configs, and Pi extensions. Non-interactive mode defaults to `local`. Choosing `global` or `npx` makes generated config files portable and safe to commit.
4. **AGENTS.md** — created if a non-Claude agent is selected (Cursor, Copilot, Codex). Shared instruction file. Uses marker-based append mode (see below).
Expand All @@ -168,6 +188,7 @@ Sets up `CLAUDE.md` and two agent hooks for the Claude Code coding agent.
- Hooks synced in `.claude/settings.json` — on every run, all existing lat-owned hook entries are removed, then fresh entries are added for both events. Detection uses three heuristics: `/\blat\b/` in the command string, `hook claude ` substring (catches any install path), or command starting with the current binary path. Non-lat hooks are preserved. Both hooks call [[cli#hook]]:
- `UserPromptSubmit` → `lat hook claude UserPromptSubmit` — injects lat.md workflow reminders, auto-resolves `[[refs]]` in the prompt
- `Stop` → `lat hook claude Stop` — reminds the agent to update `lat.md/` before finishing
- `.claude/settings.local.json` — if `lat.md/config.local.json` defines external source paths, `lat init` adds them to Claude's `additionalDirectories` list so the local checkout is readable without extra approval prompts
- `.claude/skills/lat-md/SKILL.md` — skill spec generated from `templates/skill/SKILL.md`. Teaches the agent how to author and maintain `lat.md/` files. Claude Code discovers it automatically from `.claude/skills/`.
- `.claude` directory added to `.gitignore` (settings contain local absolute paths in hook commands)
- [[cli#mcp]] server registered in `.mcp.json` at the project root (added to `.gitignore` since it contains absolute paths)
Expand Down Expand Up @@ -206,6 +227,7 @@ Sets up an OpenCode plugin that registers lat tools as native OpenCode tools and

- `AGENTS.md` — shared instruction file (created in the shared step)
- `.opencode/plugins/lat.ts` — TypeScript plugin generated from `templates/opencode-plugin.ts` with the lat invocation command injected. Uses `@opencode-ai/plugin` to register six tools (`lat_search`, `lat_section`, `lat_locate`, `lat_check`, `lat_expand`, `lat_refs`) that shell out to the `lat` CLI. Hooks into `session.idle` (runs `lat check` + diff analysis, logs a warning via `client.app.log` if something needs fixing).
- `opencode.json` — if `lat.md/config.local.json` defines external source paths, `lat init` can add `permission.external_directory` allow rules for those checkouts. When `opencode.json` does not yet exist, init first adds it to the root `.gitignore` before writing local-only permissions. If the file already exists and is not gitignored, init leaves it untouched.
- `.agents/skills/lat-md/SKILL.md` — skill spec for authoring `lat.md/` files, placed in the cross-agent standard skills directory
- `.opencode` directory added to `.gitignore` (plugin contains local absolute paths)

Expand Down Expand Up @@ -239,6 +261,8 @@ Currently supports one field:

- `llm_key` — embedding API key for semantic search, used when `LAT_LLM_KEY` env var is not set

Project-local external source overrides live separately in `lat.md/config.local.json`. Run `lat config` to see both the user config path and, when inside a project, the project-local config path.

Key resolution order: `LAT_LLM_KEY` > `LAT_LLM_KEY_FILE` > `LAT_LLM_KEY_HELPER` > config file `llm_key`. This applies everywhere: `lat search`, `lat check`, and the MCP `lat_search` tool.

Implementation: [[src/config.ts]]
Expand Down Expand Up @@ -285,14 +309,15 @@ Start the MCP (Model Context Protocol) server over stdio. Exposes lat.md tools t

Usage: `lat mcp`

Clients invoke this as `lat mcp`. The `lat init` wizard registers the MCP server using the absolute path to the current `lat` binary, so it works regardless of how `lat` was installed. The server exposes six tools:
Clients invoke this as `lat mcp`. The `lat init` wizard registers the MCP server using the absolute path to the current `lat` binary, so it works regardless of how `lat` was installed. The server exposes seven tools:

- **lat_locate** — find sections by name (wraps [[cli#locate]])
- **lat_section** — show section content with outgoing/incoming refs (wraps [[cli#section]])
- **lat_search** — semantic search across sections (wraps [[cli#search]])
- **lat_expand** — expand `[[refs]]` in text (wraps [[cli#expand]])
- **lat_check** — validate links and code refs (wraps [[cli#check]])
- **lat_refs** — find references to a section (wraps [[cli#refs]])
- **lat_get_source** — resolve an external source handle to its active location (wraps [[cli#get-source]])

Each MCP tool calls the same command function as the CLI (e.g. `locateCommand`, `refsCommand`, `searchCommand`), passing a `CmdContext` with `plainStyler` and `mode: 'mcp'`. The `toMcp()` helper converts `CmdResult` to MCP response format. Uses `@modelcontextprotocol/sdk` with stdio transport. Resolves `lat.md/` from cwd.

Expand Down
Loading