# Linking — mechanics

(Core carries the MUST: link noun-phrases with standard markdown links, every link resolves, read `brokenLinks` on each write/edit. This file carries the full rule set.)

- **Every noun-phrase that names another document should be linked** using standard markdown link syntax. Two forms are valid: **relative** (`[text](./sibling.md)`, `[text](../folder/doc.md)`) — the recommended default, native in GitHub / Obsidian / VS Code and what published sites expect — and **root-absolute** (`[text](/folder/doc.md)`, leading slash = content root), handy for a cross-folder link.
- **Never glue `./` onto a content-root path.** `./wiki/modules/tasks`, written from a doc already inside `wiki/`, resolves to the doubled garbage `wiki/wiki/modules/tasks` — correct resolution of a malformed path, i.e. a silently broken link. Pick ONE form: a relative path from your doc (`./tasks.md`, `../modules/tasks.md`), or a `/`-rooted absolute path (`/wiki/modules/tasks.md`). The `./` prefix and a content-root path never combine.
- **External web sources are NOT inline body links.** Per the Grounding rule, web URLs live in the `source_url:` frontmatter of an ingested doc under `external-sources/` (or the project's equivalent raw-sources folder); the body cites the local path: `[source name](./external-sources/source-slug.md)`. A raw `[source](https://...)` inline in the body is a TODO, not a citation — see Grounding for the closed-loop contract.
- **Internal cross-refs between OK docs** → `[text](./other-doc.md)` — link liberally to aid navigation.
- **Every link must resolve to a doc that exists by the time you're done.** Within a single multi-doc authoring pass, linking a page you'll create later in the same pass is fine — `brokenLinks` reports it as `no-such-doc` until the target lands, an expected transient forward-reference rather than a wrong-path error. What's not acceptable is *leaving* a dead link behind: create the target in the same pass, or record it as a tracked task (`TaskCreate`, or your host's task tool — if the host has none, tell the user) and leave the mention as plain prose.
- **Never wrap a link in backticks.** `` `[text](./foo.md)` `` is a bug — the backticks make it render as literal code rather than a link.
- **Never use HTML anchors** (`<a href="...">`). Markdown link syntax only.
- **`brokenLinks` on the write/edit response is your primary check — read it before walking away.** Every `write`/`edit` returns `brokenLinks` in the SAME payload: `[]` means every outbound link resolves; a populated list names each broken `href` with its `resolvedTo` + `reason` (`no-such-doc` = resolved to a doc that doesn't exist; `no-such-file` = resolved to a linked asset / source file that isn't on disk at that path; `unresolvable` = the path escapes the content root, usually one `../` too many). This validates **every** local link, not just doc links: a wrong-depth `[src](../../foo.py)` to a source file is caught too. It is report-only — the write landed regardless; fix or remove every one in a follow-up `edit`.
- **`links({ kind: "dead" })` is the authoritative end-state audit.** For a corpus-wide sweep across many docs: `links({ kind: "dead", sourceDocuments: ["your/doc"] })`. Companion `links` kinds: `backlinks` (incoming), `forward` (outgoing), `orphans` (no incoming), `hubs` (high-incoming), `suggest` (untextualized mentions worth linking).
- **The editor's red-underline visual lies.** Its dead-link detection tolerates slug-fallback (e.g., `foo` may appear resolved because `foo.md` exists at root). `links({ kind: "dead" })` is strict-exact — trust the tool, not the visual.

**Note on wiki-link syntax (`[[Page]]`):** the parser still handles it for legacy content, but it's NO LONGER the recommended default. Write new content with standard markdown links per above. Seed-pack templates (`ok seed --pack <name>`) may still emit `[[Page]]` placeholders inside template body text — those are legacy. When you instantiate a seed-pack template, replace the legacy placeholders with standard markdown links during the `{shape}`-fill pass.
