Conventions
Rules that apply to every entity, regardless of type. Each type’s spec page only adds what is specific to it.
One file, one entity
An organization is a folder of Markdown files. Each .md file is exactly one entity.
Files are grouped into per-type subfolders, but the folder is a convenience — the
type: field decides the type, not the folder.
Entities fall into four categories — but these are conceptual, not folders. Each
type keeps its own flat plural folder (individuals/, roles/, …, signals/, …); the
category is a way of thinking about an entity, not a directory.
- Structure — the organization’s makeup (who, and how they’re organized): individual, role, unit, work-system, ai-agent.
- Flow — how work is coordinated and flows: interaction, meeting, agreement, mandate, flight-item-type, flight-route, visualization.
- Change — working on the system: signal, insight, driver, proposal, organizational-decision-record. These look at the organization and decide about it; they are not part of it. The category spans two phases of that work (see below).
The Change category spans two phases
The five Change types divide by the phase of change work they belong to — two of the five D-MADE phases (Define · Map · Assess · Design · Elevate):
| Phase | Types | What it does |
|---|---|---|
| Assess | signal · insight · driver | Reads the organization as it is — selected data, its interpretation, and the need that follows |
| Design | proposal · organizational-decision-record | Says what should be instead — a proposed response, and the decision once taken |
Define is the starting point: what you want to achieve or what is bothering you right now, and who should have a say. It produces goals or a tension, and no Change type belongs to it. Map is the topology itself (the as-is picture), and Elevate — actually moving from as-is toward to-be — is deliberately not modeled here: it is facilitation work (experiments, guides, katas), a practice artifact rather than a record, and it belongs elsewhere.
The phases are a way of thinking about these five types. They are not how a reader filters
them: what matters when working is whether something is still in flux (signal → proposal) or
decided (the ODR, and the agreements that follow). Those two cuts run across each other on
purpose — proposal is Design by phase but still in flux by status.
---type: individual---A file with no frontmatter, or with an unknown/missing type, is silently
skipped by the parser. It is not an entity.
Types that are not entities. Two type values name a note on purpose: readme (the
org’s README) and tour (a guided reading tour through an org’s files). They are not
entity types — no tool lists, counts or links them as entities — but they give the file
the non-empty type that OKF asks of every Markdown file (see okf.md). Their frontmatter
holds type and nothing else, except the README’s dwsd-format; tools that stamp
entities on save (updated_at and the like) leave these files alone.
The org’s README. A README.md at the org root is such a file, with type: readme. For lack of anything
better, its first # heading serves as the organization’s name and its first paragraph
as its description — a tool that shows the org reads them from there, as written. There
is no extra key for name or description, and nothing else in the README is read, except
the format id below.
The format id. The README’s frontmatter holds exactly two keys, type: readme
and dwsd-format: the format version the folder is written to, quoted
(dwsd-format: "1.0.0"). The README stays a note. What the version means, how readers
treat it and when writers move it: Format versions.
A README.md that carries dwsd-format marks the organization’s root: a tool that
looks for the organization a file belongs to walks up to it, and wikilinks resolve within
that folder. The organization as an entity is its root unit (unit-type: company or
similar), not the README.
---type: readmedwsd-format: "1.0.0"---
# Goldcrust Bakery
A small, fictional bakery described in DWSD: …Notes. Such files — a README (type: readme), a tour (type: tour), any page without
a type: — are notes. A
wikilink may point at a note and then resolves (it is not broken), but a note is not a node
in the organization’s graph, and the wikilinks inside it are not relationships.
Host files. A host may keep files of its own in an org folder — guides, drafts,
anything the org model does not describe — in folders of its own, with any type it
likes. The format does not list them. The model folders are the per-type folders the
contract names for each entity type (folders), directly under the org root: units/
and work-systems/ for unit, decision-records/ for the decision record, and so on.
Inside a model folder, a type the contract does not know is reported as a likely typo.
Anywhere else, such a file is a note: no warning, its links resolve, it is not in the graph.
The type: field still decides — a type: role file outside roles/ is a role. Since
format 1.2.0; under 1.0 and 1.1 an unknown type is reported wherever it stands.
Format versions
The format is a contract between an org folder and every tool that reads or writes it. It
has a version of its own, MAJOR.MINOR.PATCH, independent of any tool, package or plugin
version. An org names it in its README (dwsd-format: "1.0.0", above); CHANGELOG.md
names it on each entry that changes it, on a line Format: x.y.z.
What it covers. Everything a file in an org folder may contain, and what it means: the types, their frontmatter keys and values, the discriminators, the relationship and wikilink rules, the folder layout, the body sections a tool reads, and the grammar of the embedded fences (their keys and syntax). Not covered: how a renderer draws a picture, the wording of the spec, the plugin skills, and the versions of tools.
Which step. Ask of each change: is every file that was correct before still correct, and does it still mean the same?
| Step | When | Examples |
|---|---|---|
Major (2.0.0) | No — an existing file becomes incorrect, or reads differently. Always comes with a migration. | a key renamed without an alias; a new required field; a type or value removed; a value changes its meaning; an allowed set shrinks |
Minor (1.1.0) | Yes, and new files may use something new. It only adds. | a new type (mandate); a new optional key; a new value in an allowed set; a new fence key; an old spelling accepted as an alias |
Patch (1.0.1) | Yes, and nothing new is allowed. A rule is worded more precisely. | a sentence that two readers took two ways now says one thing — the one tools already follow |
- When in doubt, take the higher step. A clarification that turns out to change what is correct is a minor or a major, not a patch.
- Typos, examples, type-page prose and skills need no version; their entries carry no
Format:line. - An old spelling retires in two steps. A minor makes the new spelling current and keeps reading the old one as an alias, with an info; only a later major drops the alias.
- The fence grammar counts. A change to it reaches orgs only through an entry here: the
DSL marks such changes
fence grammarin its changelog, and this spec decides the step. - Every major entry describes its migration in words, for people and agents without the tool; the migration itself is a script that ships with the DSL library.
Reading. A reader never refuses a folder.
- It reads every form of a major version it supports, and the aliases that version keeps.
- A newer minor of a major it knows: it checks against the newest minor it knows, and warns. That is safe, because a minor only adds.
- An unknown major: it warns and skips the format checks.
- No id, or one it cannot parse: it warns and reads on as best it can.
- A tool declares the range it supports (for example
>=1.0 <2); its own version stays free.
Writing. A writer that changes a file anyway brings it to the current form of its major
version in the same commit (focus: → around:). When what it writes needs a newer minor —
a mandate file in a 1.0 org — it raises the README’s id to that minor in the same commit.
Three limits: one commit (never a 1.1 file in an org that still says 1.0); upward
only, and only to a version the writer itself knows; only the version line of the
README changes, the rest stays byte for byte. Anyone who may write may do this.
Major jumps. A writer never crosses a major on its own. A migration to a new major is offered as a proposal: the owner sees the diff and accepts or declines, as with a dependency update. Until then, tolerant reading carries the folder. Each migration step is a commit of its own, carries the new id, and can be reverted.
The checkable part. What a tool can check in one file without the rest of the org — the
types, which of them are entities, their required keys, their model folders, conditional
requirements — is in contracts/<major>.<minor>.json, one complete file per minor (a
patch changes nothing that can be checked). Tools read it as data instead of copying this spec.
Findings about the id. Every tool reports them with the same codes, which this spec owns. None is an error, so they never change a check’s exit code.
| Code | Severity | When |
|---|---|---|
format.missing | warning | no README with type: readme above the file, or no dwsd-format in it; the format checks are skipped |
format.unparseable | warning | neither three numbers ("1.0" and "v1.0.0" are not) nor a known alias |
format.unquoted | warning | the id is written without quotes |
format.alias | info | a date alias; the report carries the version it stands for |
format.newer-minor | warning | a minor newer than the tool knows; checked against the newest it knows |
format.unknown-major | warning | a major the tool does not know; the format checks are skipped |
format.raise-missing | warning | (org check only) a file uses something a newer minor added than the README names |
Before versions. Until 1.0.0 the id was the date of a CHANGELOG.md entry.
"2026-10-24" and "2026-10-25" are aliases of 1.0.0: a reader treats them as 1.0.0, and
a writer may replace them with "1.0.0" under the rules above.
Quote it. Unquoted, YAML reads 1.0 as a number. The id is three numbers and nothing
else: no v, no pre-release tag.
Filename = label = slug
The filename without extension is both the display label and the source of the slug (the stable id used in wikilinks and internally).
individuals/Aaron Turner.md→ labelAaron Turner, slugaaron-turner- Spaces and non-ASCII are allowed in filenames; the slug is normalized.
A wikilink finds its target by label, never by slug. Cut the target at |, trim the
surrounding whitespace, and compare keys: key = NFC(lowercase(NFC(label))), with
plain Unicode lowercasing (no locale rules, no full case folding), and no character
dropped or transliterated. The same rule holds for every wikilink — frontmatter and body.
| Target | File | Match? |
|---|---|---|
[[café]] | Café.md | yes — case |
[[Café]] (e + combining accent) | Café.md (é) | yes — NFC |
[[STRAẞE]] | Straße.md | yes — ẞ lowercases to ß |
[[STRASSE]] | Straße.md | no — ß is not folded to ss |
[[Mueller]] | Müller.md | no — no transliteration |
[[Bakery Ops]] (two spaces) | Bakery Ops.md | no |
Two files with the same key in one organization are an error — labels are unique. The slug
(aaron-turner, umlauts spelled out) serves URLs and internal ids only; it is lossy, so it
is never used to match a link.
Because the filename is the identity, renaming a file renames the entity — update the wikilinks that point at it.
Relationships are wikilinks
Connections between entities are expressed in the frontmatter as Obsidian-style wikilinks pointing at the label of the target:
member-of: "[[Sales Team]]" # singlerole-keeper: # or a list - "[[Head of 3P]]" - "[[Head of 4P]]"[[Target]]and[[Target|Alias]]both resolve toTarget.- A field can hold a single wikilink or a list of them.
- The target is a label, matched as above. An unresolved target is kept as a dangling reference.
- Every wikilink in the frontmatter is a relationship — under any key, single or in a
list. The keys in the table below carry a defined meaning (structure or flow, up or into
the detail, a locator). Any other key —
derived-from,delegator,decision-makers, or a key of the author’s own likementor:— is a plain link named by its key: it connects the two entities, but no view draws a marker from it. Wikilinks in the body are references, not relationships.
Relationship fields
Both hyphen and underscore spellings are accepted (reports-to = reports_to).
| Field (variants) | Meaning |
|---|---|
reports-to / reports_to | Reporting line — individuals only (individual → individual) |
member-of | Belongs to a unit / work system — an individual or a unit can be a member |
contributes-to | A work system contributes to a higher-level work system |
role-keeper / role_keeper | Who holds this role |
for-domain / for_domain | The domain — a work system, a role or a unit — that a role, agreement, mandate, interaction (or meeting), AI agent, ODR, driver or proposal is scoped to, and that a flight route (in its dwsd.flightroute block) names as the domain responsible for the route — points up. Naming a role lands the entity on every keeper of that role |
interaction-of | The board (position) an interaction is of — points into the detail: a board locator [[Board]]#BoardName/col:Column::in (or [[Board]]#BoardName::in for the whole board), or a bare [[entity]] — a work system, a unit or a person |
agreement-of | The board (position) an agreement is of — the same board locator as interaction-of (or a bare [[entity]]); coexists with for-domain |
mandate-of | Where a mandate hangs — the same locator as interaction-of (or a bare [[entity]]); coexists with for-domain |
bound-to | Where an AI agent’s surface appears — the same locator as interaction-of / agreement-of (or a bare [[entity]] — a work system, a unit or a person) |
observes | What a signal or insight observes — what was seen / interpreted — a work system, a unit, a person, or another entity; or, since format 1.3.0, a place in the detail: the same locator as interaction-of (a board position or a route stage) |
derived-from / derived_from | What this entity emerged from — the shared lineage key, see below |
uses-route | The flight route an entity uses |
defined-for | The entity something is defined for |
visualization-of / visualization_of | The work system a visualization renders |
Up vs. into the detail.
for-domainnames the domain (points up);interaction-of/agreement-ofname a board position (a locator — points into the detail). A domain is a work system, a role or a unit — any named grouping that decides something for itself: a department, a site, a circle that governs without running a flow.for-domainnever names a person — a decision about a person is anchored through the role the person keeps, and it then shows on the box of every keeper of that role (one hop: the role’s ownfor-domainis not followed further). A board is not a work system, so the two coexist and neither field is overloaded to mean both. A board renders exactly one work system (visualization-of), so the work system is inferable from the board —for-domainis therefore optional, and stating it is just clearer. If both are present and the board’s work system differs fromfor-domain, that mismatch is something a validator can flag. On a flight route,for-domainsays who takes care when the route changes; the work systems the route flows through are derived (bound-to→ board →visualization-of), never authored there.The locator (
interaction-of/agreement-of/mandate-of/bound-to) is value-polymorphic: a bare[[…]]wikilink anchors to the entity it names — a work system, a unit, or a person (a 1:1, a personal working agreement) — wherever that entity is drawn (the topology, the org chart, the units view); a unit that is also a work system shows the same anchors in both pictures. A person and a unit never share a name — labels are unique in an organization (see above); a path form such as[[units/Name]], still found in older files, resolves by its last segment. A value carrying a#BoardNameand/or a/kind:Namepath is a board-position locator. The path drills in with/-chainedcol:·lane:·group:·split:·stage:segments and an optional trailing::before·::in·::after(bare =::in), e.g.[[Sprint Board]]#Sprint Board/col:Build/split:QA::before. This is the outside-in direction; the board may also declare relationships inside-out with inlineagreements:/interactions:keys on a column/lane/group (see Embedded DSL fences).
stage:anchors into a route, not a board. The same locator can point at a route stage:[[Route]]/stage:<itemType> @ <Band>::before|in|after, where the name afterstage:is the fullitemType @ Bandpair (single space each side of@), e.g.[[Daily Replenishment Flow]]/stage:order @ Shops::before. A#Route Namefragment disambiguates when one file hosts several routes. A stage whose item type is a wikilink is named by its link target, without brackets:[[Feature Route]]/stage:Feature @ Train::infor the stage[[Feature]] @ Train.
derived-from — the shared emergence key
derived-from says what an entity emerged from. It is a shared key, not a per-type
field: any entity may carry it, and it is documented here once rather than repeated on each
type page.
It traces the design conversation and what follows from it:
signal → insight → driver → proposal → organizational-decision-record → agreement(s)Each step may name its origin — an insight the signal(s) it interprets, a driver the insight(s)
it answers to, a proposal the driver, an ODR the proposal, and an agreement the ODR it
operationalizes. That last link is what makes an ODR’s bundle expressible: the agreements
belonging to a decision are exactly those whose derived-from names it. No separate bundle
field is needed — the bundle is the reverse reading of this key.
- Optional everywhere. An entity without
derived-fromis complete; the key adds lineage, it does not gate validity. - Single or list.
derived-from: "[[X]]"or a list, like every other relationship field. - Metadata only. There is no
derived-fromrelationship type — it is preserved and readable, but it resolves to no marker and creates no typed edge. Read backwards (“what did this come from?”) it sits in the document; read forwards (“what came of this?”) it needs a reverse index over the key.
Why a shared key and not a per-type field. It used to be documented on each type that happened to use it, and the type that most needed it —
agreement, the one that answers “why does this rule apply?” — never got it, because a per-type field has to be remembered at every new type and eventually is not. Documented once, that whole class of omission goes away.
Shared optional fields
Like derived-from, these are documented once and may appear on any entity; no type page
repeats them.
| Field | Meaning |
|---|---|
tags | Descriptive chips on any entity type — a list of short words, e.g. tags: [core, pilot]. The renderers read them from the entity’s frontmatter wherever the entity is drawn (the topology, the org chart, the units view); the view documents (board, flight-route, topology, org chart, units) carry a document-level tags: as well. A tag is a label, not a relationship — it resolves to nothing |
Structure vs. flow
Two orthogonal views of the organization, modeled with two different relationships. Keep them apart — an entity can sit very differently in each.
-
reports-to→ structure (the formal reporting line — “who reports to whom”). Individuals only. -
member-of→ flow, optionally (value creation — how work flows).member-ofexpresses belonging to a unit or work system; an individual or a unit can be a member. That belonging can describe the flow side — but need not. Use the membership that matters in context.
A unit sits between the two: a named grouping that one or more people, teams, or
other units belong to. It need not be a team — it can be an R&D department, a SAFe ART, or
any other named unit, and units can nest. A unit that also participates in flow is a work
system (its unit-type includes work-system, and it carries a flightlevel). See
types/unit.md and types/work-system.md.
The unit tree need not mirror the topology. contributes-to already says how work
systems feed each other; member-of between work systems that only repeats it adds a
second copy of the same picture. Cut the units by whatever dimension the organization
actually groups by — departments, disciplines, sites — and let a work system carry
member-of only where it really sits inside such a unit. A person can be member-of a
unit and a work system at once (a list).
Work systems are marked on unit-type
unit is the base structural type. A unit is a work system when its unit-type
includes work-system — it then carries the full domain description (Purpose …
Evaluation Schedule; see types/work-system.md) and a
flightlevel recording its flight level. A unit without work-system in its
unit-type is purely structural — e.g. a plain unit-type: team.
The marker is explicit on unit-type, not inferred from the presence of a
flightlevel. flightlevel is an attribute a work system carries — required on every
work system — but it is not what makes a unit one. This lets a single unit declare both
of its hats at once: a team that is also a work system is unit-type: [team, work-system].
This is a deliberate simplification: a unit and “its” work system are modeled as one
entity wearing two hats — now stated literally by the multi-valued unit-type — not as
two linked entities. The cleaner two-entity model — where a work system can span several
teams, or a team can have none — was considered and dropped for simplicity.
flightlevelis written as one word — no underscore, no hyphen.
Reserved and descriptive unit-type values
unit-type holds two kinds of value, and they behave differently:
- Reserved — today
work-systemandteam. A reserved value carries meaning in the model. It is part of the format, like a field name: it is always written in English, and tools match it without regard to case. A view may draw it as a mark of its own and may label it in the reader’s language.work-systemmakes the unit a work system, with everything that follows (flight level, topology,contributes-to, validation).teammarks a stable group of people who work together. Its members are the individuals whosemember-ofnames it, and a view may show the team’s size as their number — the members the org folder models, which can be fewer than the real headcount. Units that aremember-ofa team are not counted.teamandwork-systemcombine freely:[team, work-system]is a team that is also a work system; a plainteamis not.
- Descriptive — every other value:
site,department,company,ART,Werk, … An open vocabulary in the author’s words and language. No tool derives anything from it. Views show it exactly as written — no capitalization, no label lookup — so an acronym is spelled the way the author spelled it (ART, notart).
A descriptive value becomes reserved only by a change to this spec, when the model gives it a meaning (a mark in a view, a rule in validation). Until then it is description.
Subtypes and kinds — the <base>-type key
Where a type has subtypes or kinds, the discriminator key is named after the
base type (<base>-type), not a generic subtype, so it reads unambiguously for both
humans and tools:
type: visualization+visualization-type: boardtype: unit+unit-type: team
A <base>-type discriminator holds a single token or a YAML list — a list when the
entity is several kinds at once. This is what lets a unit wear two hats:
type: unit+unit-type: [team, work-system]— a team that is also a work system.
Every <base>-type (unit-type, visualization-type, agreement-type,
interaction-type) accepts a list; in practice only unit-type uses it today.
A meeting is an interaction whose interaction-type holds the token meeting (alone
or in a list, matched without regard to case). There is no type: meeting; a reader may
accept it as an old spelling of the same thing, and a validator warns.
Tracking fields
Optional provenance/timestamps. Hyphen and underscore spellings both accepted:
created_at: "2026-03-15"updated_at: "2026-03-20"created_by: "thomas"sources block (discovered / synced entities)
Entities pulled in from an external system carry a sources: block recording where
they came from (one key per source system, each with an id and url):
sources: atlassian: id: "00000000-0000-0000-0000-000000000000" url: "https://example.atlassian.net/o/<org-id>/people/team/00000000-0000-0000-0000-000000000000" discovery: id: discovery-00000000 url: "https://www.notion.so/00000000000000000000000000000000"Some synced entities instead carry flat atlassian_id / atlassian_url fields — both
patterns are valid.
Modeling notes in the body
Body text tells the organization’s story. Where a file explains how it is modeled — why
it is anchored here, why a field is set or left out, which locator it uses — put that in
one callout at the end of the file (after any ## In context view), as a GitHub alert:
> [!NOTE]> **Modeling note.** Anchored on the [[Daily Replenishment Flow]] where the dispatch> stands on the shelf (`dispatch @ Shops::in`).Readers can skip it; tools can tell it apart from content. Place it next to a passage only when it explains that one passage and would lose its meaning at the end. Wikilinks inside the callout are ordinary wikilinks. A file with nothing to explain about its modeling has no callout.
Mandates — what a holder must or may do
A mandate is something a holder must or may do: open the building, count the stock,
spend up to a limit, decide who gets a key. The holder is the file the mandate is
written in — an individual, a role, a unit (work systems included) and, preliminary
like the type itself, an ai-agent. Nothing requires mandates; an org without a single
one is complete.
Mandate or agreement? In an organization nearly everything is agreed in the end. The difference is who can change it: an agreement is changed by its parties together; a mandate is handed to its holder by someone with the power to do so — a domain or a person, the delegator — who can widen, narrow or withdraw it alone. That is a way of reading, not a field.
Mandates sit under any of these body headings, each optional:
| Heading | Holds |
|---|---|
## Accountabilities | what the holder must do |
## Decision Rights | what the holder may decide or do |
## Key Responsibilities | on a work system: what it must deliver (its accountabilities) |
## Mandates | either, for whoever prefers the general form |
Each takes a list, prose, or a two-column table. A row whose Mandate of holds a
locator shows as a mandate chip where the locator points — on a board position, a
route stage, a meeting, a work system — as an interaction row with Interaction of does
in a meeting’s table. A list item, a sentence or a row without a locator is read, not
drawn.
## Decision Rights
| Name | Mandate of ||----------------------------------------------------|-----------------------------------------|| Decide who else holds a key | || Set the back-door delivery slot with [[Deliveries]] | || Pull the next batch when the shelf runs low | [[Shop Board]]#Shop/col:Reorder::before || [[Market Street Opening Hours]] | |- Name — the mandate in a short sentence, including how free the holder is and
with whom: “with [[Deliveries]]”, “up to $200 alone”, “within the band [[…]] sets”. Or a
[[…]]link to a mandate file (below). - Mandate of — optional: where the mandate hangs, as a locator — the same form as
interaction-ofandagreement-of; a relative locator inherits nothing, since a mandate’s holder is not a board.
There is no fixed scale for how free a holder is. An organization that wants a shared one may agree on it and use its words in the names; John Cutler’s Mandate Levels, from a very specific mandate to a very general one, are an inspiration for that — not a grade, and not part of the spec.
How the holder decides is its own business. A person decides alone; a role through its
keeper. A unit settles internally how it uses a mandate — who may act alone, up to what,
when two decide together — and may record that in one of its agreements (for-domain or
agreement-of naming the unit). When it records nothing, the org does not say; readers
say so rather than assume.
A row has no identity of its own — the same rule as a meeting’s ## Interactions
table (below). When a mandate
gains weight — a band it must stay in, a delegator worth naming, a history, something that
wants to link to it — pull it out into a mandate file and name
that file in the Name column. The file is the source: Mandate of stays empty, the file
says where it hangs in mandate-of. Many such files mean many names; collisions are
handled by the label rules above, like any other file.
Mandates can be written as prose first and turned into rows later — the extract-mandates
skill proposes the rows from the text.
Reading guide
How the model is meant to be used and read — by people and by agents. Nothing here adds a field; it settles how existing structure is interpreted.
How do I refer to an interaction from a meeting table?
A meeting’s ## Interactions table names small interactions inline, one per row. When one
of them gains weight — it needs its own description, someone wants to anchor something to
it or link to it — pull it out into its own interaction file and name that file in the
row’s Name column:
| Name | Outcome | Interaction of ||----------------------------|---------|----------------|| [[Where is each feature]] | | |- There is no locator for a table row. Locators say where something hangs (a board position, a route stage, an entity); they never point at a line in a document. To make a row addressable, give it its own file.
- The file is the source. For a
[[…]]row,OutcomeandInteraction ofstay empty; the outcome is in the file’s body, the anchor in itsinteraction-of. If a cell is filled anyway, it is a copy: the file wins, and a validator reports any difference. Values from row and file are never merged and never silently dropped. - The way back needs no field. The table links the file, so its backlinks name the meeting that embeds it.
- Readers read the table in reverse: meeting → row → anchor. For a
[[…]]row they take outcome and anchor from the file. - The same holds for an agreement container:
## Agreementswith itsAgreement ofcolumn.
Anchors and around
Two ideas carry every picture of the organization, and they point in opposite directions.
- An anchor says where an entity sits. It is written in the entity’s own file:
for-domainanchors it up, to the domain that decides about it; a locator (interaction-of,agreement-of,mandate-of,bound-to) anchors it into the detail — an entity, a board position or a route stage;observesanchors a signal or an insight to what was seen — an entity, or, with a locator, a board position or a route stage. Every view finds an entity through its anchors and shows it on the box, column or stage it is anchored to. around:says from where the organization is looked at. Each inferred view — topology, org chart, units, change trail — takesaround:, a wikilink orself(the entity whose file hosts the fence), and draws the organization from that entity outward, as far asradius:reaches.around:belongs to the view, not to the model: changing it changes what is shown, never what is true.
Anchors are written once, from each entity outward; around: reads them back from any
point. An org chart with around: self in a person’s file shows that person’s line; the
change trail with around: self in a decision record shows where the decision came from
and where its agreements landed. Same files, read from a different place.
Embedded DSL fences
Six fence tags are parsed and rendered by the app. All six DSLs are plain YAML, and all fence tags use the dot form. The first two are tied to a type and are authored; the other four are inferred views that may appear in any entity body — the topology, org chart and units view may also stand alone as a file (see below):
-
visualization(boards) →```dwsd.board— columns, lanes, groups, and inline inside-outagreements:/interactions:; no inline sugar; the board name is the sharedtitle:header key. Seetypes/visualization.md. -
flight-route→```dwsd.flightroute—title:,for:,bands:,triggers:, glyph-typedpath:edges, and abound-to:layer that maps bands onto boards via wikilinks and the locator above. The old@-handle references (@work-system#Column) are retired. Seetypes/flight-route.md. -
any entity (optional) →
```dwsd.topology— an inline flight-level context map, inferred from the org’s relationships rather than authored. Keys:mode: infer(the only mode so far),around:(a wikilink naming the entity to center on; when omitted, the map centers on the entity hosting the block), andradius:(how many relationship hops the map reaches). Purely a view — it declares no relationships and is never part of a type’s required body structure. -
any entity (optional) →
```dwsd.orgchart— the line organization: everyindividualand itsreports-tochain, drawn top-down as a tree of person boxes. A person withoutreports-tois a root; a vacancy is an individual with the position inrole:(the Goldcrust and Voltfeld examples name theirsNA1). Keys:mode: infer,around:(a person),radius:(a number or{ up, down }), andnotes:— a note written on a box, naming it with a bare wikilink. Nothing else is listed in the fence: rename a file or move areports-to, and the chart follows. -
any entity (optional) →
```dwsd.units— the unit structure: everyunit(work systems included) nested by its firstmember-of; a unit withoutmember-ofis a root.layout: nested(default) draws children inside the parent box,layout: treethe same containment as a tree; each box wears itsunit-typevalues as chips, so a[team, work-system]is told from a plainteamat a glance. Units only — no people (that is the org chart), no flow between work systems (that is the topology). Samemode:/around:/radius:/notes:keys as the org chart. -
any entity (optional) →
```dwsd.change-trail— the change trail: the org’s change entities as one network, left to right — signal → insight → driver → proposal → decision record → agreement, one rung back alongderived-from(an agreement may derive from the proposal directly) — and where each agreement lands: the units and work systems it names infor-domainor in a bareagreement-of(a board position or a role does not count). A signal or insight thatobservesa decision record or an agreement draws a loop-back. An entity nothing derives from yet is an open end and shows its next step; agreements are never open, and astatusofdeclined,rejected,withdrawnorsupersededcloses an entity.created_at(fallbackdate:) dates each entry. Keys:around:(a wikilink, orself— the entity whose file hosts the fence),show:(all, the default,openorrecent) andradius:(a number orinf); an empty body is the whole trail. Witharound:the trail keeps that entity’s own line: back alongderived-fromto the signals, forward to what derives from it and where that lands. A decision record carries one this way (around: self), so its file shows where the decision came from and where its agreements apply. Around a unit or work system, the trail starts from the change entities scoped to it —for-domainon a driver, proposal, decision record or agreement,observeson a signal or insight — and follows each one’s line; an entity scoped to a role does not count here.A change trail fence may also hold entries of its own, chosen by
mode:—infer(the default) draws the organization’s trail and ignores entries;mixedlaysentries:over it;declareddraws onlyentries:, a sketch that needs no organization. Brackets point outward, here as everywhere in the format:[[…]]is a file, a bare name is something in the same fence. So each item is one of two kinds:- an inline entry — a mapping whose
nameis bare: a change entity defined right in the fence. It carries the frontmatter keys of itstype, spelled and formatted as the file would carry them (type: insight,type: organizational-decision-record, no short forms;derived-from,observes,status,created_at, …);namestands for the file name. - a reference —
- "[[Name]]", or a mapping whosenameis a wikilink: the file is the definition, so a reference carries none of its frontmatter keys.
A link value inside the fence says by its form where its target lives:
derived-from: hhis the inline entryhhof the same fence,derived-from: "[[hh]]"the file. A file never holds a bare name — an inline entry moved out into a file takes its frontmatter keys along, its inline ancestors alongderived-frommove out with it, and the fence’s bare references to it gain brackets. Either kind of item may also carry annotations, which exist only in the fence:delta: addordelta: removemarks what a change would add or take away (removeon a reference: “going away”). Annotations are set on purpose; an inline entry needs none.mode: mixedentries:- name: Swap times differ per hubtype: insightderived-from: "[[Late Swaps at Hub North]]"- name: One swap standardtype: driverderived-from: Swap times differ per hub- name: "[[Weekly Swap Review]]"delta: removeInline entries live only in their fence: no other view, backlink or graph sees them — the organization is the files.
- an inline entry — a mapping whose
The topology, org chart and units view are annotated from the entity files, never
from the fence: a
signal or insight that observes a person or unit pins on that box; an interaction,
agreement or AI agent whose locator names an entity shows on it (a unit that is also a work
system shows the marker on its unit box and its topology node); an entity scoped
for-domain to a role reaches the box of every keeper of that role — one hop; one scoped
to a plain unit shows on that unit’s box in the units view. They declare
no relationships and are never part of a type’s required body structure. All four take
around: as described in Anchors and around; focus: is its earlier
name and is still read as an alias — when both are written, around: wins. ⚠ Preliminary
— the key sets of the four inferred views may still change.
Fence ids. Any of the six fences may carry an id after its tag:
```dwsd.board id=intake. The id names the diagram within its file, so a mark or an
address that points at it survives when other diagrams are inserted, moved or removed
around it. id= is the first and so far only attribute after the tag; the value is
kebab-case ([a-z0-9][a-z0-9-]*), unquoted, unique within the file, and stays as it is
when the fence’s title: or the enclosing heading changes. The id is optional — a fence
without one is valid — and tools that create a fence should assign one. It is a plain
name, not a wikilink, and not part of the YAML, so the key sets above are unaffected; a
board’s title: still names it in locators (#BoardName). Readers recognize a fence by
its tag, the first word of the info string, and ignore attributes they do not know. A
standalone view file (below) has no fence and no id; its filename names it.
Standalone view files. The topology, org chart and units view may also live as a
standalone file at the org root — .dwsd-topology, .dwsd-orgchart, .dwsd-units — holding the same YAML
without a fence (the examples keep one org chart and one units file each, e.g.
Goldcrust Org Chart.dwsd-orgchart). Such a file is not an entity: no frontmatter, no
type:, skipped by the entity parser — a picture of the organization, not a part of it.
Markwhen siblings (.mw)
A scheduled interaction (e.g. a recurring meeting) may have a sibling file with the same
basename and a .mw extension holding a one-line Markwhen timeline
entry:
interactions/3P Coordination.mdinteractions/3P Coordination.mwThe .mw file is not an entity on its own; it is attached to the interaction.
An org folder may additionally keep one consolidated timeline file (e.g.
operating-rhythm.mw) that aggregates the sibling lines — a pragmatic workaround while
Markwhen viewers operate on a single file. It is not an entity either; the per-interaction
siblings remain the source of truth.
Like what you see? → Start — build your own org folder in ~2 min