Topology DSL — Syntax Reference
The Topology DSL describes a Flight-Levels Work-System Local View: a focal Work System and the 1-hop ego-slice of Work Systems around it (the value chain that contributes up toward it, plus the Work Systems it contributes to). It is not a global org map — it is a scoped, focal slice.
The DSL is plain YAML. The fence language id for live-rendering viewers (the
dwsd-vscode extension preview, the website) is dwsd-topology:
```dwsd-topologymode: declaredwork-systems: - { name: "Squad Aurora" }```A viewer that recognizes the dwsd-topology id renders the block live; in plain
Markdown / GitHub the same example is also shown as a static SVG (see
Examples), so the reference reads correctly in either context.
Live example · Whole-company flight-level map — Voltfeld example →
The parser is tolerant: it never throws on author input. Unknown or
malformed fields produce a topology.* diagnostic (a warning or info) and the
offending value is clamped to a default or skipped — the rest of the document
still parses. The diagnostic codes are listed per field below.
Note on field names that do not exist. The Topology DSL has no
hostfield and nomember-offield. Membership and hosting are not part of the grammar — do not write them. The only relationship the DSL expresses between Work Systems iscontributes-to.
Design notes — YAML, humans, and machines
The Topology DSL is YAML by design. Every example in this reference is also
a valid YAML document — block style (work-systems: as an indented list) and
flow style ({ name: "...", flightlevel: 1 }) both parse — so any YAML-aware
editor, linter, or formatter can read and write it. The package ships its own
tolerant parser (src/topology/parser.ts) that accepts the same shape.
The syntax optimizes for readability and round-trippability, not brevity.
Field names are spelled out (flightlevel, contributes-to — not
abbreviations), values are explicit, and the parser never throws: unknown or
malformed input yields a topology.* diagnostic and a sensible default rather
than a hard error. That verbosity is deliberate — the format is meant to be
read and written by humans, but above all by machines.
Increasingly, that machine is an AI. The raw DSL is a good target for
generation and repair by coding agents: the YAML shape, the closed and
documented set of fields, and the per-field diagnostics give an agent
everything it needs to author or fix a topology without a UI. Expect authoring
to shift toward AI tooling over time — for example, a Claude Code plugin or
similar agent integration that emits and edits dwsd-topology blocks directly.
The live fence preview and the static-SVG variants then serve as the way a
person checks what the machine produced.
Modes
mode: selects how the Local View is assembled. Values: infer,
declared, mixed. The default (when mode: is absent) is infer.
| Mode | Meaning |
|---|---|
infer | Derive the Local View from the indexer — the focal Work System and its 1-hop neighbours are read from the surrounding DawnSeed vault. The author lists nothing explicitly. |
declared | The author lists the work-systems and contributes-to edges explicitly. Nothing is inferred from the indexer. |
mixed | The author’s declared entries overlay the inferred topology as a diff: an entry with a delta (add / change / remove) is applied on top of what the indexer found, an entry without one is drawn as it is. Inference needs an around: (in an embedded block, the containing work system); without it the declared entries are the whole picture. |
An unrecognized mode: value emits topology.unknown-mode (warning) and
falls back to infer.
Syntax reference
Every field below is implemented by the frozen parser
(src/topology/parser.ts) and validated by src/topology/validate.ts. The
Diagnostic column names the topology.* code an author hits on misuse.
Top-level fields
| Field | Values / shape | Default | Diagnostic on misuse |
|---|---|---|---|
mode | infer | declared | mixed | infer | topology.unknown-mode (warning; falls back to infer) |
title | string | (none — omitted when absent) | (none — a non-string or empty value is silently ignored) |
tags | string list (document-level descriptive chips; a scalar string is accepted as a one-element list) | (none) | tolerant — non-string entries dropped, empties trimmed |
around | self | [[Target]] | [[Target|Alias]] | (none) | topology.invalid-focus (warning, parse); topology.unresolved-focus (warning, validate — target is not a known Work System) |
radius | a number | inf | { up, down, lateral } | { up: 1, down: 1, lateral: 1 } | topology.unsupported-radius (unparseable value → defaults to 1; negative → clamped to 0; lateral > 1 flagged at validate) |
work-systems (alias work_systems) | list of Work-System objects | [] | topology.invalid-work-system (a non-object or name-less entry is skipped) |
contributes-to (alias contributes_to) | list of edge objects | [] | topology.invalid-edge (a non-object or from/to-less entry is skipped) |
title is an optional human-readable label for the topology as a whole. It
is data-only metadata — used for export filenames and other outside-the-image
uses — and is not rendered on the diagram. A non-string or empty value is
silently ignored; when the key is absent the field is omitted (never '').
tags are document-level descriptive chips. Note the two scopes: this
top-level tags: describes the topology document, while the tags: on a
work-systems entry (below) describes that Work System. Topology gained the
document-level one in Phase 27.
title: and tags: are the shared document header — the board and
flight-route DSLs use the same two keys with the same meaning and the same
missing-value convention. Topology did not change here; the other two converged
onto its spelling. See The document header.
around centers the view. self centers on the containing Work System (used
in embedded blocks); a [[wikilink]] (optionally [[Target|Alias]]) centers on a
named Work System. Anything else emits topology.invalid-focus and the center is
dropped. At validate time, a wikilink target that is not a known Work System
emits topology.unresolved-focus (the diagnostic codes keep their old spelling:
codes are stable identifiers). focus: is the retired spelling of around:: it still works and shows an INFO (topology.retired-focus) in the editor. With both keys, around: wins and the parser warns (topology.around-and-focus).
Focusing a mark in the preview is a different thing from around:: it is a
view-time highlight and changes nothing in the document.
radius bounds the ego-slice. A bare number applies uniformly to up,
down, and lateral. The string inf (case-insensitive) means unbounded
(transitive closure). The object form fills any missing key with 1. Negative
values are clamped to 0 with topology.unsupported-radius. Multi-hop up /
down (and inf) are honoured; lateral > 1 is not yet supported and
emits topology.unsupported-radius (info) at validate — lateral / relates-to
expansion is deferred.
Work-system fields (each entry of work-systems)
| Field | Values / shape | Default | Diagnostic on misuse |
|---|---|---|---|
name | string (required) | — | topology.invalid-work-system (entry skipped when name is missing or empty) |
flightlevel | 1 | 2 | 3 | (none) | topology.invalid-flightlevel (warning; the value is omitted) |
delta | add | change | remove | (none) | topology.unknown-delta (warning; the value is omitted) |
tags | string list (a scalar string is accepted as a one-element list) | (none) | tolerant — non-string entries are dropped, empties trimmed away |
anchors | map of typeKey → string list | (none) | topology.invalid-anchors (the value is ignored when it is not a map) |
name is the only required field. flightlevel places the Work System
in its band (1 = operational, 2 = coordination, 3 = strategy). delta is
the mixed-mode diff marker. tags render as one tags marker in the node’s
marker row: a tag icon with the number of tags. The tags themselves are listed
in the editor preview’s drawer. anchors declares type-keyed entities
attached to the Work System — the key is the entity type (e.g. agreement, meeting, individual,
unit, flight-route, interaction, or a visualization:board /
visualization:route composite) and the value is a list of entity names. In
the live indexer path these anchors come from the vault; the declared form is
for authoring and the static examples.
An agreement or an AI agent that names a work system only through a bare
agreement-of: or bound-to: wikilink lands on that work system’s node, and so
does a signal or insight with a bare observes: wikilink. A bare [[Name]]
matches the target file case-insensitively: [[bakery operations]] reaches
Bakery Operations.md. See the locator grammar for the
full grammar.
Edge fields (each entry of contributes-to)
| Field | Values / shape | Default | Diagnostic on misuse |
|---|---|---|---|
from | string (required) | — | topology.invalid-edge (entry skipped when missing) |
to | string (required) | — | topology.invalid-edge (entry skipped when missing) |
delta | add | change | remove | (none) | topology.unknown-delta (warning; the value is omitted) |
A contributes-to edge points from a contributor to the Work System it feeds.
The value chain flows upward: an edge should land on the same or a higher
flight level. An edge to a strictly lower flight level emits
topology.downward-contribution (warning) at validate. A repeated (from, to)
pair emits topology.duplicate-edge (info) and the second occurrence is ignored
at layout time.
How edges are drawn
There is nothing to configure here; these are the rules the layout follows. An edge leaves the top of its source and enters the bottom of its target, vertically at both ends. Between two boxes that sit on top of each other the edge is a straight line: one of the two boxes moves a few pixels to line up, and the focused box never moves. An edge that skips a row keeps a reserved corridor beside the boxes in between, and it bends into that corridor only when its straight route would cut through one of them; otherwise it is drawn like any other edge. Ports sit 20 px apart, centered on the box edge, incoming and outgoing alike — closer only when the box edge is too short for all of them — and a single edge meets its box in the middle.
The corridor exists so that no contributes-to edge is ever drawn through a box it
does not connect; the reasoning lives in the edge-aware placement decision record of
the dwsd-dsl package.
Markers, drawer and click model
A Work System node carries a marker row along its bottom edge: one small glyph
with a count per kind of entity attached to it. There are nine annotation
layers — Interactions · Agreements · AI Agents · Contributors (key roles) · Mandates · Change conversation ·
Organizational decision records · Notes · Tags — and the filter menu, the export and
the command line (--hide roles, …) treat all nine alike. (The filter menu row Boards,
key board-bindings and the first row of the menu, also hides the board, route, topology and flight-route
markers of a box; the row Contributors, key roles, hides the role, person and member-unit markers.
Both re-flow like every other layer.) The row holds at most
four markers and then shows an ellipsis. A meeting is an interaction: it is counted in the box’s
one interaction marker (an interaction and a meeting read 2) and listed in the drawer’s one
Interactions section, and hiding Interactions hides it. Hiding a layer re-flows the inside of the box (the boxes, edges and bands
never move): the remaining markers close up with no gap, a marker that did not fit before may come into
view, the ellipsis goes when everything visible fits, and a box with no visible marker loses its divider
line and centers its title like a box without markers. The change pill on a box (change-conversation pins and
decision records) gets narrower when part of it is hidden and is not painted when all of it is. With every
layer hidden the picture keeps the work systems, the edges and the bands. Roles are their own marker type: a
type: role file whose for-domain: names the work system puts a role marker
(a badge glyph and a count) on its node, and roles rank before people and teams /
units, so a crowded row keeps the role marker visible and the ellipsis hides the
last-ranked kinds. A role with several work systems in a list-form for-domain: marks
each of them.
Mandates are a marker type of their own (a key glyph and a count) and rank directly after roles: a
type: mandate file whose for-domain: names the work system, or a mandate that hangs at the work system
with mandate-of:, puts a mandate marker on its node, and the drawer lists the holders with the mandate
text. The layer is called Mandates (--hide mandates). See Mandates.
The change pill. A node with change entries carries ONE change pill straddling its top edge, 14 px from the box’s right edge and drawn over the box (and over the focal ring): a level indicator of four small dots (signal, insight, driver, proposal), filled in the marker grey up to the highest stage that has an entry and faint above it, the entry count, and the organizational decision records behind a thin divider (a sprout glyph and their count). It is a quiet 16 px capsule in the node box’s own paint (its Flight Level fill, its border color and stroke width, 3 px on the focal node) and has no type colors. Hovering it shows the card “Change story here · n entries”; a click opens the node drawer, where the change conversation is listed by stage and can be folded into a long pill. See Where the pins render.
A click anywhere on a node opens the drawer — the title area, the body, the marker
row — and a second click closes it. The drawer title is a link to the work
system’s file: it carries the link color and a trailing ”›” at rest, is underlined
only on hover and keyboard focus, and opens the file beside the preview; the drawer
stays open. A host that wants the earlier model — the marker row opens the drawer and a
click on the node navigates — passes openOn: 'marker-zone' (the default is
'box'), and titleAction ('navigate' by default, 'select', or 'none' for a
plain title with no control) chooses what the title does.
The drawer opens with the fact row: one line of small chips with no heading. The
flight level is always there, as a colored chip (Flight Level 1, 2, 3 in the
Flight Levels colors, because the chip means the flight level); the unit types follow
side by side, exactly as written, with work-system reading Work System. The unit
types come from the workspace — the work system’s unit file — or from the optional
lookupUnit host callback (which answers just { unitTypes }); the callback wins, and
without either the row shows the flight level alone. The bands follow in the order
Interactions · Agreements · AI Agents · Roles · Change conversation · Organizational
decision records · Notes · Tags; the change conversation reads Signal, Insight, Driver,
Proposal from top to bottom whatever order the pins arrive in, and the decision
records are their own section, Organizational Decision Records.
Center and radius
In the VS Code side preview, and in any host that offers it (the Dawn Seed App, for example), you can look at another part of the
topology without touching the fence. Click a work system: its drawer opens, and the header offers Center here, with “+N outside” when N
neighbors are not in view. Click it and the picture re-centers on that box with a short glide. The toolbar then shows Back and
Forward (a right click, a half-second press or Shift+Enter on Back lists every earlier center) and the center icon, which
returns to the picture the fence asks for. The radius button next to them opens a pop-out with an Up and a Down row (0,
1, 2, 3 or all); “Reset” returns to the fence’s radius:.
In a hand-declared topology, re-centering only moves the focus ring: every declared work system stays. Without a radius: in the fence nothing is cut, so the radius button reads ↑∞ ↓∞ with “default” under ∞; choosing a smaller radius trims the picture to what is within reach.
Center and radius are view state: the fence is not touched, and another fence or note starts at its own picture. A picture without
a focal (no around: or focus:, and no default focus from the entity that contains the fence) shows everything, so there is
nothing to center on: it offers neither “Center here” nor the radius button. A fence with only focus: counts as scoped and offers
both. The Markdown preview stays static; it draws the fence’s picture and has none of these controls. The radius offers Up and Down
only; there is no step along a relates-to link, so a third row would change nothing.
Examples
Each example below appears in both variants: the dynamic dwsd-topology
fence (the raw DSL a live viewer renders) and the generated static SVG (the
fallback for plain Markdown / GitHub). The examples escalate from the smallest
valid document to the full mixed-mode diff surface.
For a focused, source-⟷-rendered showcase of just the six examples (generated from the single source of truth), see the examples gallery.
1. Minimal
The smallest valid topology: a single declared work-system.
# minimal — the smallest valid topology: a single declared work-system. mode: declared work-systems: - { name: "Squad Aurora", flightlevel: 1 }
2. Flight Levels
The three Flight Level bands (1 operational, 2 coordination, 3 strategy) across three work-systems.
# flightlevels — the three Flight Level bands (1 operational, 2 coordination, 3 strategy). mode: declared work-systems: - { name: "Squad Aurora", flightlevel: 1 } - { name: "Reliability Mid", flightlevel: 2 } - { name: "Delivery Ops", flightlevel: 3 }
3. Contributes-To Network
A contributes-to network: work systems contribute upward to higher-level targets, and a mid-level system can feed more than one target — so the shape is a network, not a single-rooted tree. Edges point to the same or a higher flight level (the value chain flows upward).
# contributes-to-network — several sources contribute UP to higher-level targets; one system feeds TWO targets (a network, not a single-rooted tree). # Edges point same-or-higher flight level (the value chain flows upward). mode: declared work-systems: - { name: "Squad Aurora", flightlevel: 1 } - { name: "Squad Vega", flightlevel: 1 } - { name: "Reliability Mid", flightlevel: 2 } - { name: "Delivery Ops", flightlevel: 3 } - { name: "Platform Strategy", flightlevel: 3 } contributes-to: - { from: "Squad Aurora", to: "Reliability Mid" } - { from: "Squad Vega", to: "Reliability Mid" } - { from: "Reliability Mid", to: "Delivery Ops" } - { from: "Reliability Mid", to: "Platform Strategy" }
Here Reliability Mid (FL2) contributes to both Delivery Ops and
Platform Strategy (FL3) — the fan-out that makes this a network.
4. Tags
String tag lists on work-systems. The Local View draws one tags marker on the node: a tag icon with the count.
# tags — string lists on work-systems (one tags marker with the count in the rendered Local View). mode: declared work-systems: - { name: "Squad Aurora", flightlevel: 1, tags: ["delivery", "core"] } - { name: "Delivery Ops", flightlevel: 3, tags: ["strategy"] }
5. Focus + Radius
Local-View scoping: around: centers the view on a work-system and radius:
bounds how far up/down/lateral the ego-slice reaches.
# focus-radius — Local-View scoping. `around:` centers the view on a work-system; # `radius:` bounds how far up/down/lateral the 1-hop ego-slice reaches. # lateral stays at 1 (lateral > 1 / relates-to expansion is not yet supported). mode: declared around: "[[Reliability Mid]]" radius: { up: 2, down: 1, lateral: 1 } work-systems: - { name: "Squad Aurora", flightlevel: 1 } - { name: "Squad Vega", flightlevel: 1 } - { name: "Reliability Mid", flightlevel: 2 } - { name: "Delivery Ops", flightlevel: 3 } contributes-to: - { from: "Squad Aurora", to: "Reliability Mid" } - { from: "Reliability Mid", to: "Delivery Ops" }
Why “Squad Vega” is not in the rendered view. It is declared in
work-systemsbut has nocontributes-toedge connecting it to the focal Work System, so the radius walk never reaches it. Only Work Systems inside the focal ego-slice appear in the Local View — declaring a Work System does not force it to render if it falls outsidearound+radius.
6. Mixed Delta + Anchors
Diff authoring: mode: mixed overlays add/change/remove deltas onto the
current topology, and anchors: declares type-keyed entities attached to a
work-system. Squad Vega and Delivery Ops carry no delta: — they are the
part of that topology the change leaves as it is.
# mixed-delta-anchors — diff authoring. `mode: mixed` overlays declared deltas# (add/change/remove) onto the current topology, and `anchors:` declares the# type-keyed entities attached to a work-system (agreements, meetings, ...).# Squad Vega and Delivery Ops carry no `delta:` — the part of today's topology# the change leaves as it is. With an `around:` in a workspace, `mode: mixed`# infers that base from the work-system files.mode: mixedwork-systems: - { name: "Squad Vega", flightlevel: 1 } - { name: "Delivery Ops", flightlevel: 3 } - name: "Squad Aurora" flightlevel: 1 delta: add anchors: agreement: ["Team Working Agreement"] meeting: ["Weekly Sync"] - name: "Reliability Mid" flightlevel: 2 delta: change - name: "Legacy Ops" flightlevel: 3 delta: removecontributes-to: - { from: "Squad Vega", to: "Reliability Mid" } - { from: "Reliability Mid", to: "Delivery Ops" } - { from: "Reliability Mid", to: "Legacy Ops", delta: remove } - { from: "Squad Aurora", to: "Reliability Mid", delta: add }Like what you see? → Start — build your own org folder in ~2 min