Authoring topologies
How to turn a real network into Marrow YAML — identifiers, devices, links, ports, status, and annotations.
A topology file has four parts: a header, zones, devices, and links.
Everything else is detail hung off those. The complete key-by-key listing is in
the schema reference; this page is about judgment.
Start from the story
Before writing YAML, decide what the diagram is for. The same site produces very different files depending on the answer:
- "Where does traffic go?" → tiers on every device, links carry
speedandkind. - "What's in each building?" → zones per site, tiers secondary.
- "How is it segmented?" →
modeon links: trunk/access VLANs, routed L3, VPN tunnels, LACP bundles. - "What's broken right now?" →
statuson devices and links, notes explaining each one. - "What does this branch look like?" → hub-and-spoke, spokes connected only to the hub.
Marrow renders what you declare. A diagram that tries to answer all four at once answers none of them well.
Identifiers
Every id is kebab-case: [a-z0-9._-], starting with a letter or digit.
They must be unique across devices, and separately unique across zones.
Pick a convention and hold it. IDs appear in link endpoints, in ha_pair_with,
in URLs on multi-page sites, and in every diagnostic — a consistent scheme is
the difference between a readable diff and an unreadable one.
name: is the human label and is free text. If you omit it, the id is used.
Devices
Only id and icon are truly required, but a device with nothing else
declared gives the engine nothing to work with:
note and config are the two keys that pay for themselves later. They show in
the inspector, and on large topologies a device carrying either one earns its
own dedicated page in the built site.
ha_pair_with must be declared on both devices. The engine does not infer
the reverse direction, and a one-sided declaration is a common cause of "why
didn't my pair sit together?".
Links
A link is from and to, each device-id:Port or bare device-id:
Only the first colon splits device from port. core-01:Gi1/0/1 parses as
device core-01, port Gi1/0/1 — the slashes are part of the port name, which
is what you want. An id containing a colon cannot be expressed; ids are
kebab-case so this never comes up.
Two axes: the cable, and what it carries. kind/speed describe the
physical link; mode describes its logical function. They compose — a 10G fiber cable can be an access port, a trunk, or a routed L3 link. speed drives
stroke width; status drives colour; mode drives the symbol:
mode: | Symbol | Companion keys |
|---|---|---|
access | plain line | vlans (the single VLAN) |
trunk | double rail | vlans, native_vlan |
routed | solid + protocol chip | protocol |
peering | dotted | protocol (ospf/ebgp/…) |
tunnel | dashed + 🔒 | encap (ipsec/gre/vxlan/…) |
stack | thick bar | — |
Like structure, meaning is declared, never guessed — the engine will not
infer trunk from a port name. The exact VLANs/encap/protocol ride a small chip
so the pattern stays uncluttered. Mismatched attributes (e.g. encap on a
non-tunnel link) are advisory MRW-W105 warnings, not errors.
LAGs. Give the members a shared lag id — they bundle onto one strand
chipped with that id (PO1); add lacp: active|passive|on|static|pagp to name
the control protocol. Aggregation is orthogonal to mode, so a port-channel can
be a trunk, an access, or a routed bundle. Use lag for port channels only, not
as a general grouping key.
animated: true draws a flowing dash. It's loud on purpose. One or two per
diagram to mark the path that matters; a diagram where everything is animated
communicates nothing.
Status
status is a declaration in the file, not a live reading. Marrow never
polls anything.
| Value | Device | Link |
|---|---|---|
up (default) | green LED | normal stroke |
down | red LED | red stroke |
degraded | amber LED | amber, long dashes |
planned | grey LED | grey, dotted, rounded caps |
unknown | grey LED | — (devices only) |
If you want live status, generate the YAML from your monitoring system on a schedule and rebuild. That's a legitimate and common pattern — the file is the interface.
Ports and interfaces
Two different things, easy to conflate:
- Interfaces (
interfaces:on a device) are documentation. They appear in the inspector and on device pages. - Ports (the part after the colon in a link endpoint) are geometry. Marrow places a port chip on the device's edge and routes the cable to it.
They don't have to match — a link may use a port you never listed under
interfaces — but a topology where they agree produces a far more useful
inspector.
Reusing the same port on two links raises warning MRW-W101. That's usually a
copy-paste mistake, occasionally a legitimate shared physical port.
Hero, theme, description
hero sets where the reader's eye lands first. Choose the device the diagram is
about. You can also set hero: true on a device rather than naming it at the
top; do one or the other.
Private annotations
Any key prefixed with x- is preserved and ignored:
Unknown keys without the prefix are errors (MRW-E005). That is deliberate —
a silently ignored typo like teir: core would quietly change your layout. See
ADR-0006.
A checklist before you say it's done
validatepasses with zero errors.- You have looked at a snapshot or the live preview.
- Every device that matters has a
tieror azone— meaning is declared, not implied by its name. ha_pair_withis declared on both sides of each pair.- No credentials, no secrets, no real management passwords anywhere in the file.
- Warnings are either fixed or understood.