Skip to content

Guided Stories

Chapter 8 gave you a curated projection: the right nodes, grouped and styled for one audience. A projection is still a picture, and a picture answers “what is there” — not “how do I read this”. The person who drew it fills that gap by talking over it, and when they leave, the gap comes back.

A story closes it in the model. It is an ordered walk over what the view already draws — the construct that makes an architecture explainable rather than merely correct.

view PaymentsStory {
show @@team:"payments"
story {
chapter "Order comes in" {
"A customer hits the storefront; an order is created."
Web, Checkout, Orders
}
chapter "Money moves" {
"Payments charges the card, then Ledger records it."
Payments, Bank, Ledger
}
}
}

That is the whole authored surface. Titles, an optional note, and an ordered list of nodes — deliberately nothing else.

Read that heading literally. A story clause does not restyle the board, does not reorder it, does not filter it. Open PaymentsStory normally and you get exactly the board show @@team:"payments" describes, as though the clause were not there.

The story is inert until the viewer is asked to present it, with ?present=1 on the URL (?play=1 autoplays and implies it). This is the point of the design: a story is a reading of a view, so declaring one never costs the ordinary reader anything. See Present mode below.

The five-chapter cap is a hard grammar rule, not a style guideline. A story is a walk a reader holds in their head, and the entire claim of the construct is that the authored part stays small enough to be worth reviewing. A sixth chapter raises a diagnostic and is dropped.

The note is the chapter’s leading string

Section titled “The note is the chapter’s leading string”
chapter "Money moves" {
"Payments charges the card, then Ledger records it."
Payments, Bank, Ledger
}

It is optional, and it obeys the same law module and view descriptions do (Chapter 10): the string comes first, before anything else in the body. A string written after the nodes is a diagnostic rather than a silent append — it reads like a per-node caption, and a chapter has no slot for one.

Nodes are separated by commas or newlines, and any node selector works (Chapter 31) — not just a bare name:

chapter "Everything the gateway fronts" {
PaymentGateway, @@zone:"dmz", nodes of (PaymentGateway > *)
}

Order is the meaning. Consecutive nodes are what a beat is derived from, so the written order is the narration’s order. Within one selector that resolves to several nodes, order is the deterministic ascending key. A node named twice in one chapter appears once, where it was first introduced.

Everything that isn’t in the list above. You never write a beat, a transition sentence, or a camera move:

DerivedFrom
beatseach consecutive pair of nodes
the relation each beat crossescalls / called by / mutual / contains / contained in / reaches-in-N-hops / unrelated — most specific first, so a direct call is never reported as a 1-hop reach
the sentence per beatthe relation plus the interfaces it goes through
the camera’s follow windowthe node just left, the node in hand, the node coming up (≤3)
the chapter handoffa stay / enter / leave set diff against the previous chapter

This is why a story survives a refactor. Move a call from Payments to a new Settlements module and the beat’s sentence changes with the model, because the sentence was never text you typed.

Narration deliberately does not claim whether a call is sync or async. That is not a property of the edge — it’s a stdlib widget-field convention on the target interface’s type chain (Chapter 11) — so stating it would be a guess.

The story rides on the view’s selection; it never widens it. A chapter that selects something outside show keeps the rest of its nodes, and a chapter left with nothing at all is dropped with a diagnostic.

The practical consequence: when a chapter needs an anchor from another domain, show it explicitly.

view PaymentJourney {
"How money actually moves through the system."
show @@domain:"Payments" or @@domain:"Orders"
// The gateway and the ledger anchor the first and last chapters but live
// in other domains — a chapter can only walk what the view DRAWS.
show APIGateway or Ledger
story {
chapter "An order arrives" {
"Traffic lands on the gateway and becomes an order."
APIGateway, Orders
}
chapter "Money moves" {
"The order asks Payments to charge; the gateway routes it out."
Orders, Payments, PaymentGateway
}
chapter "The outside world" {
"Only the gateway talks to the processors — everything else is internal."
PaymentGateway, Stripe
}
chapter "And it is written down" {
"Every movement lands in the ledger, which nothing else calls."
Payments, Ledger
}
}
}

A view carries at most one representation clause — table, matrix, grid, flow — and the board is the absence of one (Chapter 8). A story does not compete for that slot. It rides on whatever the view already is, so it composes with any of them.

Two constraints do apply:

  • Not with focus. A standing focus and a story both claim the emphasis channel, and composition intersects — a chapter intersected with a focus collapses to a near-empty board. Nothing stops you writing both; the result is simply a story not worth presenting, so pick one.
  • One per view. A view instance (Chapter 8) may not add a second story on top of its parent’s. The instance’s own wins, with a diagnostic.

?present=1 is a link you hand to someone — that is the whole shape of the feature:

  • The reader’s position lives in the URL fragment as #beat=<chapter>.<stop>, so any stop is a link a review comment can point at.
  • ?play=1 autoplays and implies ?present=1.
  • While a story runs it takes the emphasis channel outright: the chapter’s nodes are the figure, everything else is ground.
  • Present mode shows the view you are already on when that view has a story, and otherwise opens the first view that declares one — a presentation link has to work for someone who has never opened the workspace, and present mode hides the navigation they would otherwise use to find it. It steers once: stepping to another tab mid-talk leaves you there.

The parameters go on whatever surface is hosting the viewer — an embedded <archlang-viewer> (Chapter 23), a archlang serve session, or an exported single-file HTML bundle (Chapter 21).

  • Onboarding. The walk a senior engineer gives a new hire at a whiteboard, written down once and kept true by the compiler.
  • Review and design docs. A #beat= link is a citation: “this is the hop I’m objecting to”, pinned to a stop rather than a screenshot.
  • The talk you give twice. If you have explained the same diagram in the same order more than once, that order is a story and belongs in the model.

Do not reach for one to work around a busy board. If the picture needs a story to be legible at all, the fix is a narrower show — a story explains a readable view, it does not rescue an unreadable one.