Skip to content
Fermium

Links between documents

Aliases, wiki links in markdown, the /x/ URL form, how a reference resolves on the shared host and on a custom domain, broken links and backlinks.

Documents are ordinary web pages, so they can link to each other with ordinary URLs, and the stable slug keeps such a link working across every update of the target. A URL is not a name, though. Fermium adds aliases: one human name per document that people and agents can write without knowing a slug, and that can move to a newer document so every existing link follows.

Aliases

An alias is a lowercase slug such as q3-roadmap: letters, digits and dashes, 1 to 64 characters, no leading or trailing dash. Spaces and underscores you type are folded to dashes, so "Q3 Roadmap" is stored as q3-roadmap; anything else is rejected with a message. An alias may not look like a document id.

  • One alias per document. Setting a new one replaces the old.
  • Unique within the owner's workspace. Two workspaces may both have a handbook.
  • Only the document's owner can set or clear it.

Set it with set_alias(doc_id, alias) from an agent or PUT /api/docs/{id}/alias. Clear it with clear_alias(doc_id) or DELETE /api/docs/{id}/alias. The /d/<slug>/ URL is unaffected either way.

Re-pointing

If another live document in the workspace already holds the alias, set_alias is refused with a 409 that names the current holder. Pass force: true to move it: the old holder loses the alias, and every existing [[q3-roadmap]] and /x/q3-roadmap link now lands on the new document. This is how "the current proposal" stays current when you publish next quarter's version.

Prefer moving an alias over clearing it. A cleared alias leaves every link that used it visibly broken.

In a markdown document, write references in double brackets. They render as real links at publish time; source.md keeps exactly what you wrote.

[[q3-roadmap]]                    the document with that alias
[[q3-roadmap|the roadmap]]        the same, with your own link text
[[q3-roadmap/img/chart.png]]      a file inside that document
[[q3-roadmap/source.md#L12-L20]]  lines 12 to 20 of a file inside that document
[[q3-roadmap#L7]]                 line 7 of the document's primary file
[[#customer-facing]]              the tag view in the app
[[doc:01J7ZK3N9QW0X4B2C6D8E0F1G2]] a document by id, which never changes
[[@acme/q3-roadmap]]              an alias in a named workspace

References inside inline code and fenced code blocks are left alone. A target with a space in it, or an empty one, renders as literal text.

Document references become relative /x/... links. Tag references point at the tag view in the app on fermium.app.

In the browser editor, typing [[ offers your documents by alias and title, and [[# offers your tags, so you rarely type a reference by hand.

Line ranges

A reference can end in #L<from>-L<to> (or #L<line> for one line) to cite specific lines of a text file. The fragment stays on the rendered link, /x/q3-roadmap/source.md#L12-L20, and is recorded with the link, so list_links reports the path as source.md#L12-L20. Agents use this to cite the exact lines a statement came from.

On wiki pages

When a markdown document is shown inside the wiki, a [[link]] whose target is also in the wiki points at the target's wiki page (/w/<alias> on your domain, /w/@<workspace>/<alias> on the shared host), so readers stay in the wiki chrome. References to documents outside the wiki keep the /x/ form and resolve as usual. Agent members can also point at an alias rather than a document id; when the alias moves, the member follows.

A reference to an alias that no live document in your workspace holds still renders, as a muted link with a dashed underline, labelled [[ref]], with a tooltip that says there is no document with this alias yet. It is never dropped silently. Because the link already points at /x/<alias>, it starts working the moment a document takes the alias; republish the source and it renders as a normal link.

The URL form

For HTML documents and anything outside markdown, use the resolver URL directly:

/x/<ref>
/x/<ref>/<path>

<ref> is an alias, doc:<id>, a bare document id, or @<workspace-slug>/<alias>. The resolver answers with a 302 to the canonical /d/<slug>/<path> on the same host, so the target's visibility applies exactly as if the reader had opened it directly: a password document prompts, a Restricted document asks the reader to sign in. A reference that does not resolve gets the same neutral not-found page as a missing document, so /x/ reveals nothing a slug would not.

Because the link is relative, the same rendered HTML works on the shared content host and on a custom domain.

On the shared host and on custom domains

An alias is unique inside a workspace, so the resolver has to know which workspace you mean.

  • On a custom domain, the workspace is implied by the hostname. https://docs.acme.com/x/handbook resolves inside Acme's workspace, and only Acme's documents exist there.
  • On the shared content host, there is no implied workspace. A bare alias resolves only when exactly one live document anywhere holds it. If two workspaces both have a handbook, https://fermiumusercontent.app/x/handbook is not found.
  • @<workspace-slug>/<alias> works on either host. Use it, or doc:<id>, when a link may travel outside the workspace or the alias is a common word.

While a markdown document renders, and when resolve_link checks a reference, bare aliases are resolved in the writer's own workspace.

Each time a markdown document is written, its outbound references are recorded. That gives two views of any document:

  • Outbound: every [[ref]] in it, with the resolved target where there is one and resolved: false where there is not.
  • Inbound: every live document that links here.

Read them with list_links(doc_id) or GET /api/docs/{id}/links. Check inbound links before you re-point an alias, rewrite a document, or delete it. Links from a deleted document leave the index; links that pointed at a purged document go back to unresolved rather than dangling.

Only markdown documents contribute outbound links. A /x/ URL in an HTML page works when a reader follows it but is not indexed.

Tools and endpoints

Agent tool REST Does
set_alias(doc_id, alias, force) PUT /api/docs/{id}/alias set or move an alias
clear_alias(doc_id) DELETE /api/docs/{id}/alias remove it
resolve_link(ref) GET /api/resolve?ref= check what a reference points at
list_links(doc_id) GET /api/docs/{id}/links outbound links and backlinks

resolve_link accepts a bare reference, [[ref]], or /x/ref, and returns found: false with a hint when nothing matches. Agents are told to check before they cite a document, and to publish or alias the target rather than leave a broken reference. Parameters and responses are in the MCP reference and the REST reference.

Prompts that work:

  • "Give the roadmap the alias q3-roadmap so I can link to it."
  • "Link to the Acme proposal from this postmortem." The agent calls resolve_link, then writes [[acme-proposal]].
  • "Publish the new proposal and make acme-proposal point at it." The agent calls set_alias with force: true.
  • "What links to this document?" The agent calls list_links and reads inbound.

In the app

The inspector shows the document's Alias with its /x/ link and a copy button; the owner can set, move (the dialog explains the move when another document holds the alias) or clear it there. The Links tab lists links out, with broken references marked, and links in. The wiki shows the same inbound links as Linked from under each page, limited to documents that are themselves in the wiki.