Skip to content

10a. Markdown Documents

A description (Chapter 10) is flavored markdown attached to a declaration. An .md file is the same flavored markdown standing on its own — a native architecture document, not an opaque attachment. It renders with the same dialect: the [[…]] cross-references, aspect references, section references, foreign value getters, and backlinks you already know from descriptions, over the same core resolver. A design doc, a runbook, an onboarding guide, an ADR — write it in .md, drop it in the workspace, and it links straight into the model.

# Payments Platform
The [[Payments]] service authorizes and captures card payments. It runs in
[[@@security-zone:pci]] and publishes events consumed by [[Orders]] and
[[Notifications]]. On-call rotation is owned by [[#pay001]]@@team.
See [[Payments#compliance]] for the PCI scope.

Every [[…]] here is a live link into the canonical model: [[Payments]] resolves to the module, [[@@security-zone:pci]] to the aspect overlay, [[#pay001]]@@team reads the team aspect off the referenced node, and [[Payments#compliance]] jumps to a section.

The hard constraint: .md cannot create model

Section titled “The hard constraint: .md cannot create model”

Rule. A markdown document references and renders existing model; it never defines it. The .arch files remain the single source of truth.

This is the line that keeps documentation from quietly becoming a second, conflicting source of architecture. An .md can point at [[Payments]], embed a snippet, quote an aspect — but it cannot bring a Payments module into existence, set a field on it, or wire an edge. If it isn’t in an .arch file, it isn’t canonical. Markdown is a lens on the model, never the model.

Bidirectional linking. A document references model elements with [[…]], and an .arch element (or its description) can link back out to a document — and to a #section inside it:

service Payments {
docs.design: "platform-overview.md"
"Full design rationale in [[platform-overview]]; PCI details in
[[platform-overview#compliance]]."
}

The backlink index (“mentioned in”, below) spans both surfaces, so you can navigate .arch.md and .md.arch from either side.

Inline self-contained snippets. A fenced ```arch block holds a throwaway draft diagram — its own independent, self-contained model that is not part of the workspace’s canonical model:

Here's the shape we're proposing:
```arch
service Gateway {
> Payments
> Orders
}
```

That snippet renders live — a real diagram, not a screenshot — but defines nothing canonical, so the hard constraint still holds. It’s perfect for an RFC or a design doc where you want to sketch an idea without touching the real workspace. (Embedding a live view of the real model in a document is not available yet — it depends on view maturity. A self-contained snippet, being independent of the canonical model, is the supported inline form.)

.md files use the exact dialect from Chapter 10 — the same CommonMark subset plus the archlang [[…]] extensions:

FormLinks to
[[#id]] / [[Name]]a declaration (by stable ID or name)
[[@@key]] / [[@@key:value]]an aspect plane, or a specific aspect on it
[[Doc#section]]a #-header inside an .md document
[[ref]]@@aspectPathan aspect value read off the referenced node

One form behaves differently in a document than in a description:

Rule. Bare @@aspectPath interpolation is description-only. A standalone .md has no owning node, so a bare @@ in a document is an error. To read an aspect inside a document, use the explicit [[ref]]@@aspectPath form, which supplies its own context — it’s the only interpolation available in .md.

So a description on Payments can write @@team, but platform-overview.md must write [[Payments]]@@team. The composed form (a cross-reference plus the value getter) is one mechanism built from two pieces you already have, not new syntax — and it works everywhere, including back in descriptions.

Every element maintains an automatic reverse index of all [[…]] references pointing at it, across both descriptions and .md documents. Open Payments and tooling shows everywhere it’s discussed — the design doc, the runbook, another service’s description — so you navigate from a declaration to its whole conversation without grepping.

A document’s bare names ([[Payments]]) resolve against a package/space, the same as any reference. The scope is taken from the .md frontmatter when present, falling back to the file’s location in the workspace tree. Stable-ID references ([[#id]]) resolve regardless of scope.

  • .md files are a first-class archspace surface, rendered with the same flavored markdown as descriptions.
  • A document references and renders model — it can never create canonical model; .arch stays the source of truth.
  • It participates two ways: bidirectional [[…]] linking (.arch.md, including #section) and inline self-contained ```arch snippets (throwaway, non-canonical, rendered live).
  • Bare @@aspectPath is description-only; in a document use the explicit [[ref]]@@aspectPath getter.
  • Backlinks span both surfaces, so “mentioned in” reaches descriptions and documents alike.

Chapter 11: The Standard Library → — from bare types to service, command, event, and the rest of the stdlib vocabulary.