CLI Tour
The CLI is independent of the web viewer. Use lnk start, lnk query, lnk brief, lnk session-end, lnk health, and maintenance commands even when lnk serve is not running. Agents that support lazy-loaded instructions can also use the official Link skills instead of MCP setup.
Use lnk try when you want the shortest proof loop: demo creation, readiness, query proof, brief proof, viewer command, and first agent prompts in one command.
Use lnk demo [dir] to create a sample workspace with a few memories, raw sources and wiki pages, so you can try recall, the viewer and the graph without touching your own memory. It refuses to overwrite a directory that is not an earlier demo; --force replaces an earlier demo.
Use lnk proof when you want to prove the cross-agent memory loop directly: one clean local workspace, one reviewed memory, and one bounded recall packet shared by CLI, skills, and MCP.
Use lnk setup for install day and every upgrade after it: it detects every agent installed on your machine and wires them all — workspace, MCP provisioning, session hooks, and a refresh of any stale Link-owned agent instruction files (a steering file from an older Link can name MCP tools the configured server no longer exposes, sending the agent back to file greps) — in one idempotent command. Use lnk onboard when you want the guided single-agent flow: safe repair, health check, optional first memory, optional project seed, first prompts, and optional agent MCP wiring. If the local viewer is running, /onboard mirrors that flow with copy buttons.
Use lnk seed . ~/link from a project directory when you want Link to create a source-backed project page from existing repo context before the first real recall. It scans allowlisted docs/rule files, blocks secret-looking values, and does not create durable memories silently.
Daily Loop
lnk serve
lnk setup # every detected agent, wired in one command
lnk onboard
lnk onboard --seed-project .
lnk seed . ~/link
lnk proof
lnk welcome
lnk next
lnk start ~/link --task "working on Link release"
lnk session-end session-notes.md ~/link --limit 3
lnk health
lnk ingest-status
# Supported structured exports: plan first, then apply
lnk ingest raw/chezmoi-docs/export.jsonl ~/link --adapter chezmoi-docs-graph-v1
lnk ingest raw/chezmoi-docs/export.jsonl ~/link --adapter chezmoi-docs-graph-v1 --apply
lnk remember "User prefers feature branches for Link work." --type preference --scope project --project link --visibility project --review-after 2026-08-01
lnk remember "Temporary launch branch is release/one-off." --type project --project link --expires-at 2026-09-01
lnk remember "1. Bump version 2. Run tests 3. Tag and publish" --type procedure --trigger "cutting a release"
lnk remember "Deploy acme only via blue-green" --applies-when "project:acme, task:deploying"
lnk remember "Releases ship daily from main" --supersedes weekly-releases
lnk recall "how often do releases ship" --as-of 2026-03-01
lnk share "Prefer local memory"
lnk snapshot ~/link --output link-snapshot
lnk brief "working on Link release" --project link
lnk query "what should I know before changing the MCP tools?" --budget small --project link
lnk validate
Memory Commands
One rule for the memory knobs. Finding it → --trigger (a phrase that helps task-shaped recall find a recipe). Fencing it → --applies-when (conditions that demote or hide a memory outside its context). Owning it → --scope/--project/--visibility (whose memory it is and who may see it). Replacing it → --supersedes (archive the old claim with lineage; accepts the memory name or its title). Aging it → --review-after/--expires-at. When in doubt, save with none of them — every knob can be added later through review.
lnk remember
Save a local agent memory. Strong duplicates and likely conflicts are refused unless explicitly allowed.
lnk recall
Search local memories with recall readiness, project-aware filtering, type filters, and --as-of temporal recall.
lnk recipes
List saved procedure memories with their triggers and first steps.
lnk explain-memory
Show provenance, lifecycle, graph links, review issues, and recall readiness.
lnk update-memory
Merge new text into an existing memory and reset review state.
lnk archive-memory
Reversibly hide a stale or wrong memory from default recall.
lnk forget-memory
Permanently delete a memory after explicit confirmation.
Capture Workflow
Use lnk session-end at the end of a work session when an agent has notes or a transcript and should propose memory without saving it silently. Use lower-level captures for saved review inbox workflows.
lnk session-end session-notes.md ~/link --project link --limit 3
cat transcript.md | lnk session-end - ~/link --project link
lnk capture-session session-notes.md --project link
lnk capture-inbox --project link
lnk accept-capture raw/memory-captures/<capture>.md --index 1
lnk redact-capture raw/memory-captures/<capture>.md
lnk delete-capture raw/memory-captures/<capture>.md --confirm
lnk dedup-captures # collapse inbox captures that offer nothing new (--confirm applies)
Proactive Guard
On Claude Code, Link checks each prompt against your constraint-shaped memories (never / always / only / do not) and interrupts exactly once when one strongly applies: "let's deploy payments on Friday" surfaces your deploys-on-Tuesdays memory before the agent acts. Silence is the normal output - unrelated and weak-overlap prompts pass untouched - and each firing is recorded locally as a guard event. Installed automatically with session hooks.
Session Handoff
The most universal pain of multi-agent work: a rate limit hits mid-task, you switch tools, and the first ten minutes go to re-explaining. lnk handoff writes a standalone packet - task, state, next steps - and the next session on any connected agent opens with it: session-start hooks and the MCP first response both carry it, so delivery never depends on the agent thinking to ask. Handoffs expire on their own (48h), are secret-redacted at write time, and never become durable memory unless you promote them through normal review.
lnk handoff "Auth refactor: token validation moved, refresh test failing" --task "Auth refactor" --next "Fix refresh test"
lnk handoffs # list pending
lnk handoffs --clear FILE # after the next session picks it up
Import Your Scattered Memory
Your memory already exists — in ~/.claude/CLAUDE.md and Claude Code's auto-memory, Cursor rules, a hand-tended AGENTS.md, or memories copied out of ChatGPT. lnk import reads those surfaces and turns each deliberate line into a reviewable proposal in the capture inbox — through the same dedup, secret-scanning, and injection-labeling gates as any capture. Nothing is ever auto-accepted, Link's own instruction sections are excluded, and re-running an import is a no-op for anything already pending, dismissed, or saved.
lnk import claude-code # CLAUDE.md + auto-memory
lnk import cursor # rules files
lnk import codex # AGENTS.md (minus Link's own section)
lnk import file --file chatgpt-memories.txt # anything pasted to a file
Review at bulk speed when a capture is trustworthy: lnk accept-capture FILE --all accepts every proposal (duplicates and conflicts are skipped and reported, never forced), and lnk delete-capture TARGET --all --confirm clears the whole inbox with dismissals recorded.
Weekly Digest
lnk digest is the reflection ritual: what you taught Link this week, what is aging out of its trust window, which memories are drifting into saying the same thing, and what is still waiting for review. Read-only and deterministic — it reuses the lifecycle, consolidation, and inbox engines rather than computing new truth. A quiet week says so.
lnk digest # the last 7 days
lnk digest --days 30 # a monthly look back
lnk digest --json # for dashboards and agents
Temporal Recall
Ask what you believed then, in plain language. Link resolves everyday time phrases ("last quarter", "in March", "2 months ago", "back then") to an exact date and reconstructs what was active on it from the dated files themselves — archived memories, supersede lineage, and expiry all participate. No model, no clock magic. --as-of YYYY-MM-DD still pins the moment explicitly.
lnk recall "where does local data live" # today's truth
lnk recall "where does local data live in March" # what was true then
lnk recall "what did we decide last quarter"
lnk recall "deploy process" --as-of 2026-03-31
Sync Between Machines
lnk sync moves reviewed memory between your machines through a git remote you control (a private repo, a homelab bare repo) — no server, no service. Every outgoing file is scanned for secrets before anything is pushed, not only wiki pages; conflicting memory edits are kept as both versions and surfaced by lnk consolidate for review (git conflict markers never touch wiki files); the tamper-evident log merges with a declared re-anchor. raw/ captures, ingest staging, operation snapshots, backups, caches and the runtime never sync: they are ignored, and if an older setup tracked them, sync reports it and prints the commands to untrack them, and never does it for you: the untracking commit would delete those files on a machine still running an older Link. lnk sync --init refuses to re-point a workspace that already has a different origin.
lnk sync --init --remote git@github.com:you/link-memory.git
lnk sync # daily: commit, pull, resolve, gate secrets, push
lnk sync --status
Compile Memory into Agent Files
lnk compile ~/link --repo .
lnk compile ~/link --repo . --dry-run
lnk compile ~/link --repo . --check
lnk compile ~/link --repo . --targets all
lnk compile writes your reviewed memories into the files each coding agent already reads, so they reach agents with no MCP connection or hooks. By default it writes AGENTS.md plus the agents the repository already has files for; --targets all or a comma-separated list chooses others.
| Memory | Written to |
|---|---|
| Preferences, decisions, facts, project context | A Link block in AGENTS.md, CLAUDE.md, GEMINI.md and .github/copilot-instructions.md; .windsurf/rules/link-memory.md and .kiro/steering/link-memory.md |
| Anchored to code in this repository | One rule per memory, loaded when the agent works on those files: .cursor/rules/link-*.mdc (globs), .claude/rules/link-*.md (paths), .github/instructions/link-*.instructions.md (applyTo), Windsurf (trigger: glob) and Kiro (inclusion: fileMatch). AGENTS.md and GEMINI.md, which have no path rules, list them with their files. |
| Procedures | Agent Skills: .claude/skills/<name>/SKILL.md |
What it will and will not write:
- Only reviewed, active memories. Unreviewed ones, unreviewed team imports, and anything with a secret-shaped value or an injection-shaped instruction are left out and listed.
- Private memories stay out of files a repository commits unless you pass
--include-private. A memory fenced to a task stays in recall; one fenced to another project or directory is not written here. - In shared files only the block between the Link markers changes; everything else is kept byte for byte, including line endings. Link-owned files carry a generated-by line; a file without it is never overwritten and is reported instead. Stale Link-owned files are removed. Symlinked targets are refused.
- Each file stays within what its agent reads: 32 KiB for AGENTS.md (Codex), 200 lines for CLAUDE.md, 12,000 characters per Windsurf rule, 500 lines per Cursor rule. When memories do not fit, notes go first, then facts, then decisions and preferences, older before newer, and every memory left out is listed with the reason.
- Output is deterministic. Running it twice changes nothing, so
--checkcan fail CI when the files drift from the reviewed memories, and--dry-runshows the diff first.
Over MCP it is admin(action="compile", arguments="{"repo": "/path/to/repo"}"). It returns a preview with the diff; add "write": true after the user approves.
Check Instruction Files
lnk stale ~/link --repo . --instructions
lnk stale ~/link --repo . --instructions --json
lnk stale --instructions checks the repository's own agent instruction files the way lnk stale checks memories: every AGENTS.md, CLAUDE.md and GEMINI.md (nested ones too), .claude/rules, Cursor, Windsurf and Kiro rules, and Copilot's instruction files. It reports three things and changes none of them:
- Stale references. Paths, scripts, make and just targets, dependencies, variables, local endpoints, runtime versions and package managers the repository once had and no longer does, with the same history rule as memories. In an instruction file a bare filename counts only as a link (
[CLAUDE.md](CLAUDE.md)); “run main.ts” is an example. A nested file's links are resolved from its own folder. - Size limits. Text an agent never reads: Codex stops after 32 KiB of AGENTS.md, counted along the chain from the repository root to each nested file; Windsurf reads 12,000 characters of a rule; Claude Code skips a CLAUDE.md over 4 MiB. Each finding gives the limit and how far over. Longer-than-recommended files (CLAUDE.md over 200 lines, a Cursor rule over 500) are reported as warnings that do not fail the check.
- Contradictions. Rules in two instruction files, or a rule and a reviewed memory, that cannot both hold (“always use tabs” and “never use tabs”; “2 spaces” and “4 spaces”). Copies of the same rule in AGENTS.md and CLAUDE.md are not contradictions, and words inside code, links or names do not count. With the local contradiction model on disk (
lnk semantic --setup --nli) pairs the word rules miss are added.
Link's own compiled block and Link-owned files are skipped: their content comes from memories, which lnk stale checks. Exit codes are the same as lnk stale: 0 nothing found, 1 something to fix, 2 could not check.
Maintenance
lnk backup
lnk doctor --fix
lnk health
lnk status --validate
lnk memory-audit
lnk compliance-export --output link-audit.json
lnk team-sync ~/link
lnk snapshot ~/link --output link-snapshot
lnk operations
lnk benchmark "agent memory"
lnk rebuild-index
lnk rebuild-backlinks
lnk stale
lnk receipt
lnk validate
lnk verify-mcp
Use lnk backup before broad repair work. Use lnk benchmark when a wiki starts to feel slow or when you want to see how much broad wiki context the bounded packet avoided sending to an agent. lnk status --validate and lnk benchmark both show persistent-cache reuse so you can tell whether Link is rereading every page or reusing unchanged records.
Run lnk stale from inside a repository to list memories that describe things the repository no longer has. It checks file paths (with the new name when git recorded a rename), package scripts (npm run deploy:staging), make and just targets, dependencies, environment variables and URLs, and two direct contradictions with files the repository checks in: a runtime version the manifests no longer allow (“Python 3.10” when pyproject.toml requires >=3.12) and a package manager whose lockfile was replaced by another manager's. Each reference is only reported when the repository shows it once had the thing and no longer does, so prose that merely looks like a filename, a variable or a script stays quiet. On this repository's own documentation plus eight other real repositories, that rule produced no false flags across more than 600 references (exact figures in benchmarks/RESULTS.md). It also re-reads each memory's code anchors (path:line symbol, recorded when the memory was written inside a checkout) and reports symbols that were removed. A symbol that only moved within its file is not a finding, and anchors from another repository are never checked here. Claims framed as history (“we dropped Python 3.9”) or as a prohibition (“do not use npm”) are not read as current claims, monorepo workspace manifests count, and links to public documentation are left alone. History answers are cached per commit in the workspace's .link-cache/, so repeat runs on a large repository are fast. The command changes nothing: it tells you which memories to review. It exits like a linter, so CI and scripts can act on the result. 0 means nothing was flagged, 1 means at least one memory was flagged, and 2 means it could not check, for example because the folder is not a git repository. A folder git cannot read never gets a false all-clear.
Run lnk receipt to see what your agent was actually given, session by session. It lists which surface each session came through (session hook, MCP or CLI), each brief's size and whether anything was truncated, how many recalls there were, and every memory used, each with the commands to explain or forget it. --sessions N shows more history, and --json is for scripts and LinkBar. The receipt comes from a local ledger that never records what you asked; LINK_USAGE=off disables it.
Use lnk operations when health reports an interrupted write. If a marker has a rollback snapshot, run lnk operations ~/link --recover <marker> to preview the recovery and add --confirm only after reviewing the plan.
Use lnk team-sync to share memories through a team git remote. Before it is set up, it is a read-only plan: it checks Git state, verifies that raw/ is protected, and checks whether review or visibility: private memories would make sharing unsafe. After lnk team-sync --init --remote <git-url>, each run exports your active visibility: team memories, syncs the shared repo, and imports teammates' memories for your review: they arrive as review_status: pending with imported_from: team, because a teammate's review is not yours. Pages that are not visibility: team, not active, symlinks, or carrying a secret-shaped value or an injection-shaped instruction are rejected and reported, never written. Local versions win, and a team memory you forgot or archived is not re-imported.
Use lnk snapshot when you need a static, read-only HTML export for a teammate, maintainer, security reviewer, or demo. It excludes raw/, captures, local operation state, and memory pages by default. With --include-memories, it still excludes visibility: private memories unless --include-private-memories is explicitly passed.
Use lnk connect <agent> when an agent already has Link instructions but still needs MCP wiring. It previews the config before writing.
lnk connect codex ~/link
lnk connect codex ~/link --write
lnk connect kiro ~/link --write
lnk connect claude-code ~/link --hooks --write
lnk verify-mcp ~/link
Use lnk disconnect <agent> to take Link out of an agent: it previews, and with --write removes, Link's MCP server entry and its session hooks. Other servers, other hooks and comments in those files are left as they were, so it is safe on hand-edited VS Code and Zed settings. Run it before deleting a workspace, or new sessions keep trying to load it.
Add --hooks (Claude Code, Codex, Cursor) to also install session hooks: every new session then starts with a bounded Link memory brief injected automatically, and session end stores proposal-only notes with memory candidates for later review — no durable memory is written without approval. Codex has no session-end event, so it gets the session-start brief only. Sessions without memory-worthy content are skipped and duplicate end events are deduplicated, so the capture inbox does not fill with noise. The hooks run lnk hook session-start and lnk hook session-end, which you can also invoke directly to inspect what they inject or capture. Codex and Cursor hook support is new and follows those vendors' documented hook schemas — if a hook misbehaves there, please open an issue. If the workspace runtime predates session hooks, --write refreshes it automatically.
The hooks themselves are plain commands you can run by hand to see what they inject or decide: lnk hook session-start, session-end, prompt-check, pre-tool and post-tool, each reading the agent's event JSON on stdin; --emit cursor prints Cursor's envelope instead of plain text. lnk remember "..." --enforce "ask command: git push --force*" saves a memory with its rule in one step (repeatable; the rule acts after review).
Memory that holds at the moment of action. A memory can carry rules that are checked before the agent's tool calls: lnk enforce <name> --rule "ask command: git push --force*" (or deny write: migrations/**, ask read: .env*). A rule acts only after you review the memory, ask is the default (the tool call waits for your OK) and deny blocks it, and every decision names the memory it came from. When a saved constraint names a command in backticks, lnk remember suggests the rule for you to approve; Link never enables one on its own. With hooks installed (lnk connect claude-code --hooks --write), Claude Code checks rules before shell commands and file reads and writes, Cursor before shell commands. Claude Code also gets memories surfaced when the agent opens or edits a file they are anchored to (recorded when the memory was written inside the repository), once per session, and never for an anchor whose symbol is gone. Everything a hook injects carries a short (link:…) marker; at session end Link checks the transcript for it, and lnk receipt says whether the brief and each reminder arrived, arrived cut off, or never arrived. Proposals waiting for your OK, and rules waiting for review, are listed at the top of the next session with the exact command for each; the agent runs one only after you say yes. Proposals from a session that read web pages or another MCP server's output are marked, so you can check the words were yours.
Use lnk recipes to list saved procedure memories with their triggers, and lnk recall "<task>" --type procedure to recall only recipes. Consolidation plans also surface recurring themes across session captures — the review-gated way an agent learns your patterns: detection is automatic and deterministic, but turning a pattern into one durable memory is always proposed to you first. A scheduled idle-time agent session can run the plan as a "dream pass" and bring proposals to your next session.
Use lnk consolidate when the capture or review backlog builds up. It is read-only: it counts pending captures and memories needing review, groups duplicate captures, and prints paste-safe accept/discard/review commands to run with the user. When the backlog crosses a threshold, the injected session-start brief nudges the agent to offer a consolidation pass, and MCP agents can request the same plan through review(action="consolidate").
Use lnk semantic to inspect or enable optional hybrid recall. Lexical recall is always the default and the fallback; running lnk semantic --setup once (or python3 -m link_mcp --semantic-setup for MCP-only installs) adds a small local embedding model so paraphrased queries also find memories phrased differently — on Homebrew installs, where the runtime Python refuses direct pip installs, setup provisions the extras into ~/.link-mcp-venv automatically. Recall itself never touches the network — the model loads offline-only, embeddings live in plain JSON under .link-cache/, and semantic-only matches are labeled with capped confidence so agents verify before trusting them. Measured results and methodology live in benchmarks/RESULTS.md.
Contradiction flags are a separate opt-in. lnk semantic --setup --nli also downloads a small local natural-language-inference model (Xenova/nli-deberta-v3-xsmall, int8, about 87 MB), which needs the onnxruntime and tokenizers packages from the rerank extra.
- After that,
lnk rememberchecks a new memory against the few stored memories that share its subject. A likely contradiction adds a review note and apossible_contradictionslist to the result. - The save always goes through. The model is never used during recall and never contacts the network after setup.
lnk semantic --jsonreports the state undercontradiction_flags(enabled,reason,model,threshold).LINK_NLI=offdisables it.
From a source checkout, use the synthetic large-wiki smoke when you want local scale evidence without touching your real wiki. The script prints the exact lnk serve command and graph URL for the generated fixture.
python3 scripts/smoke_large_wiki.py --pages 10000
All Commands
lnk --version
lnk version
lnk init [dir]
lnk serve [dir] [--port 3000]
lnk onboard [dir] [--agent codex] [--write] [--hooks] [--first-memory "..."] [--seed-project .]
lnk seed [project-dir] [dir] [--project-name name] [--overwrite] [--dry-run]
lnk try [dir] [--force] [--serve] [--port 3000]
lnk demo [dir] [--force]
lnk proof [dir] [--force] [--serve] [--port 3000]
lnk welcome [dir] [--project slug]
lnk prompts [dir] [--project slug]
lnk next [dir] [--project slug]
lnk health [dir] [--json]
lnk status [--validate]
lnk operations [--limit 20] [--recover marker.json] [--confirm]
lnk backup [--label name] [--include-raw]
lnk compliance-export [dir] [--output audit.json] [--project slug]
lnk team-sync [dir] [--remote git-url]
lnk share <page-or-memory> [dir] [--port 3000]
lnk snapshot [dir] [--output link-snapshot] [--include-memories] [--include-private-memories] [--force]
lnk ingest <raw-source> [dir] --adapter chezmoi-docs-graph-v1 [--exclude "group"] [--apply] [--replace-unmanaged] [--prune]
lnk ingest-status
lnk import-obsidian <vault> [dir] [--dry-run] [--overwrite]
lnk remember "text" [--type note|preference|decision|project|fact|procedure] [--project slug] [--visibility private|project|team] [--review-after YYYY-MM-DD] [--expires-at YYYY-MM-DD] [--trigger "..."] [--applies-when "..."] [--supersedes name-or-title]
lnk propose-memories <file-or-text> [--project slug]
lnk session-end <file-or-text-or-> [dir] [--project slug] [--limit 3]
lnk capture-session <file-or-text> [--project slug]
lnk capture-inbox [--project slug]
lnk accept-capture <capture> [--index N] [--visibility private|project|team]
lnk redact-capture <capture>
lnk delete-capture <capture> --confirm
lnk query "task" [--budget micro|small|medium|large] [--project slug]
lnk graph-summary ["topic"] [--limit 40] [--depth 1]
lnk benchmark ["query"] [--budget micro|small|medium|large] [--project slug]
lnk start [dir] [--task "task"] [--project slug]
lnk brief "task" [--project slug]
lnk memory-audit [--project slug]
lnk consolidate [dir] [--project slug] [--limit N]
lnk semantic [dir] [--setup] [--rebuild] [--nli] [--json]
lnk recall "query" [--project slug] [--type TYPE] [--as-of YYYY-MM-DD] [--include-archived]
lnk recipes [dir] [--project slug]
lnk profile [--project slug]
lnk wins [--project slug]
lnk memory-inbox [--project slug]
lnk memory-log [--limit N]
lnk review-memory <name>
lnk explain-memory <name>
lnk update-memory <name> "text" [--project slug]
lnk set-memory-visibility <name> private|project|team
lnk enforce <name> [dir] --rule "ask command: git push --force*" [--clear] [--suggest] [--json]
lnk archive-memory <name>
lnk restore-memory <name>
lnk forget-memory <name> --confirm
lnk doctor
lnk doctor --fix
lnk migrate
lnk validate [--strict]
lnk rebuild-index
lnk rebuild-backlinks
lnk stale [dir] [--repo path] [--instructions] [--json]
lnk compile [dir] [--repo path] [--targets list|all] [--check] [--dry-run] [--include-private] [--project slug] [--json]
lnk receipt [dir] [--sessions N] [--json]
lnk verify-mcp [--json]
lnk connect <agent> [dir] [--write] [--config path] [--python python] [--hooks]
lnk disconnect <agent> [--write] [--config path] [--hooks-settings path]
lnk hook session-start|session-end|prompt-check|pre-tool|post-tool [dir] [--limit N] [--project slug]
lnk backup [--list] [--include-raw]
lnk restore-backup <backup.tar.gz> [--include-raw] --confirm
python3 link.py demo
python3 link.py query-link "task" [dir]
query-link is kept as an internal/backward-compatible alias. Prefer lnk query in user-facing docs.