Board DSL — Anchors, Agreements & Interactions
This page covers how a board reaches outward (agreements: / interactions:)
and how external entities point into board positions via a locator, the unified
render surface (grouped buckets + shared drawer), inline markdown-lite, and the
overflow affordances. See the reference index for the board header
and the other constructs.
Anchors, agreements & interactions
A board node reaches outward (agreements: / interactions: declared on the
node — the inside-out direction), and external entities (meetings,
agreements) point into board positions via a locator (the outside-in
direction). Both directions resolve through one shared surface. For the mental
model see Inside-Out / Outside-In; for
the authoritative locator syntax (including how it works — the four-part shape
and the exact-one resolution walk) see the
Locator grammar (this section does not
re-derive it — it summarizes how the board renders the result).
The locator (outside-in), in brief
An external entity addresses a board position with a locator string:
locator := head ('#' boardId)? ('/' path)? ('::' position)?- head —
[[file]](canonical, resolved by lowercased basename). An optional#boardIdsuffix selects a board by its title when one Markdown file hosts multiple board blocks (D-14/D-15 — e.g.[[Sprint Board]]#Salespicks the board titled Sales); omit the head entirely for a relative locator that inherits its container’s frontmatter head. - typed path — a
/-chained set ofkind:Namesegments, case-insensitive:col:Name,lane:Name,group:Name,split:Name(e.g.lane:Alice/col:Doing,col:Build/split:QA). The resolver returns exactly one node (or a synthetic lane×columncell), or degrades tonot-found/ambiguous— no wildcards. - position — a trailing
::before/::in/::after; bare =::in.
See the Board Locator grammar for head forms, the
value-polymorphic interaction-of: / agreement-of: keys, the for-domain:
role-scope key, the container body-table convention (one entity file → N
anchors), and the ## Outcome(s) channel (a per-anchor outcome line in the
drawer, allowlisted to ## Outcome / ## Outcomes / ## What is the outcome?,
truncated to 280 chars).
The unified render surface — buckets, drawer & disclosure tiers
Per board unit, internal declarations + external markers merge into at most two
grouped buckets per side plus an optional fallback marker. A unit that is anchored
only in (the common case) therefore shows at most two buckets; anchors on other
sides add a set of their own (see “One bucket set per side” below):
| Bucket | Source | Chip |
|---|---|---|
.anchor-bucket[data-bucket="agreements"] | internal agreements: + external type: agreement | Agreements (N) |
.anchor-bucket[data-bucket="interactions"] | internal interactions: + external type: interaction or type: meeting (a meeting is an interaction) | Interactions (N) |
.anchor-marker (⚓) | an external entity with no recognized type | graceful fallback |
- Disclosure tiers (deterministic, no live measurement). Tier 1
namesshows inline per-entity labels whencount ≤ 2 AND total name length ≤ 24; otherwise Tier 2collapsedshows a singleAgreements (N)/Interactions (N)count.N = 1always shows the (truncated) label, never a count. - Wikilink entries show their name. An internal entry in the quoted wikilink form
(
"[[ART Sync]]") showsART Syncon the chip and in the drawer, never the brackets. The name, not the bracketed string, counts toward the 24-character budget. - One entity, one entry. When the same entity is both declared internally
(
"[[ART Sync]]") and anchored at the same unit from outside (theART Syncdocument’s locator), the chip counts it once and the drawer lists it once — the external entry is kept, because it carries the link to the source. The match is case-insensitive, on the display name or the link target, within one bucket. - Names never wrap. A chip is one line: a name that does not fit ends in
…. In a group bar the group name keeps its line; a crowded bar truncates its chips instead. - Names read in the chip’s own color. A chip shows its names in the chip’s own color, never as blue link text. The link to an entity’s file is a row in the drawer: click the chip to open it.
- Shared drawer. Clicking a chip walks to the nearest anchor marker and opens
one shared drawer listing every related entity (with its container, outcome,
and nav target). The bucket carries a deterministic
data-anchor-keyper unit (column#name,lane#name,group#name,split#col#idx,cell#lane#col,board) so the drawer routes correctly. - One bucket set per side. A unit anchored before, in and after shows all
three sets, not only the last one written. Internal entries (declared on the unit
itself) have no side and join the
inset; an externalinanchor still blends into that oneinbucket, while an externalbeforeorafteranchor adds its own agreements / interactions set. Thebeforeset sits at the unit’s start edge (the left edge of a column, lane header, group bar, split section or cell), theafterset at its end edge (the right edge); theinset stays where it always was. Every bucket carriesdata-anchor-side. - Board-scope anchors show in the board header. An external anchor whose locator
addresses the whole board (
[[Order Studio Board]]#Order Studio::in: a#Titleand no path) shows in the board header as the board’s one agreements bucket (plus one interactions bucket), merged with the board’s own internal entries and with the sides merged — the header has no edges, so every side appears in a single set taggedin. An entity declared both internally and at board scope counts once. A board with such an anchor always gets a header, also an unnamed one (it shows the bucket, no invented title). - Board-scope pins show in the header too. A navigation pin (
observes:and its family) whose locator addresses the whole board shows in the change pill in the board header, keyedboard. Every board pin keeps its side asdata-anchor-side; pins do not move by side, and pins of different sides at one place are one pill. - One grouped chip per scope. At every scope — board, column, lane, group, and
split section —
agreements:(andinteractions:) render as a single grouped chip → the shared drawer, never as separate per-entry chips.
Mandates on a position
A mandate whose Mandate of cell (a row on a holder’s file) or mandate-of: (a type: mandate file) names
a board position shows there as one mandate chip with a key glyph, in its own bucket
.anchor-bucket[data-bucket="mandates"] (data-layer="mandates", addressable as chip:mandate). The chip is
labeled with the holder, not with the mandate text. Several holders at one place share the bucket and list their names;
when the names do not fit it reads Mandates (N). Clicking the chip opens the shared drawer, which lists each holder
with the mandate text beside a key glyph. The chip is Terracotta (#C9956B border, #F6ECE2 fill, #6B4423 text), the
same hue as the border of a note, and the Mandates layer of the filter menu hides it. Mandates come from outside
the board only; a board has no mandates: key. A row without a Mandate of locator draws nothing. See Mandates.
Colors and the own layer are the current defaults, not settled.
Graceful degradation
The anchor surface never crashes and never blanks the board. An unresolved
locator (missing file, wrong board id, no matching column) renders no marker;
the rest of the board renders normally. An unresolved internal [[wikilink]]
decorates with .wikilink-unresolved + a !N badge. The parser performs no
filesystem access — resolution against the workspace happens in the host
indexer.
Navigation pins (signals, insights, drivers & proposals)
Beyond agreements/interactions, a board position is anchored by a signal or an insight,
two of the four in-flux change entities (signal, insight, driver, proposal; see the
vendored in-flux types reference for the full type model, and
the change category page for where they sit in the chain).
“Navigation pin” is the name of the data (BoardPin) and of the old glyph, kept because
it is what the code calls it; the category is change. These are pins, not
markers: all pins of one place show up as ONE change pill, a quiet capsule in the header’s own colors at
the right end of the header of the column, lane, group bar, split section or cell (and
of the board header for a board-scope pin), distinct from the agreement/interaction
bucket chips. The pill is a level indicator: four small dots (signal, insight, driver,
proposal), filled in the header’s name color up to the highest stage that has an entry and
faint above it, then the entry count; its outline is the column border. At a board position
only a signal or insight is placed (format 1.3), so for now the driver and proposal dots stay empty there. It has no type colors. Hovering it shows the card “Change story here · n entries”
with one grey circle and count per stage; clicking it opens the drawer. See
Where the pins render.
-
Anchoring is outside-in via the same locator. A
signal/insightuses itsobserves:field. Adriver/proposalis not placed on a board position byobserves: it names its domain withfor-domain:(a unit or work system) and shows on that domain’s box in the structure views. Theobserves:value is the same value-polymorphic locator theinteraction-of:/agreement-of:keys use — a board-position value (#BoardNameand/or a/col:…/lane:…/group:…/split:…path, optional::before|in|after, bare =::in) anchors the pin to that node.---type: signalobserves: "[[Sprint Board]]#Sprint Board/col:Build::in"--- -
The four categories share ONE drawer super-group. Clicking the pill opens the drawer; the four pin categories render under a single contiguous “Change conversation” band in stage order (each a per-type sub-row with a
(count)badge), ADD-ALONGSIDE — not replacing — the flat Agreements / Interactions / AI-Agents buckets. The band can be folded into a long pill and back, and hovering a row fades the rows outside itsderived-fromnet. One click on a row opens the entity; the drawer has no action that opens a Change Trail. Per-type body richness (insight Category/Severity, proposal status, the driver four-part body) surfaces as drawer sub-row content, not as separate markers. -
derived-fromis metadata only — it links down the chain but is not a typed edge and paints no pin (the drawer reads it to fade rows outside a hovered row’s net). It is the shared emergence key, not a field of these four types. -
Graceful degradation. An unresolved pin locator renders no pin; the rest of the board renders normally (the shared never blank, never break contract).
-
A change entity does not belong in
agreements:. A signal, insight, driver, proposal or organizational decision record listed in a board’s (or column’s, lane’s, group’s)agreements:shows a warning,board.change-entity-in-agreements, on the wikilink: a change entity points at the board from outside and does not become part of the work system. A signal or insight does that with anobserveslocator on the entity; a driver, proposal or decision record names its domain withfor-domain. The entry still renders as a row of the agreements bucket. The editor shows the warning with the workspace index;dwsd-dsl checklists it as skipped.
Inline markdown-lite
Agreement / interaction text supports a small, non-nesting inline markdown
subset (first match wins, rendered without innerHTML):
**bold**,*italic*,`code`[[wikilink]]→ a.wikilinkto the target entity[text](url)→ a.md-link
No other markdown is interpreted, and there is no nesting.
Overflow & graceful degradation affordances
The renderer follows “show as much as possible, never blank, never break.”
tags:chips render single-line with a…ellipsis when they overflow.- Anchor chips collapse to a
Agreements (N)/Interactions (N)count tier; the full names live in the chiptitleand the drawer. - Outcome text truncates to 280 chars + a single
….
Example
A focused board exercising the inside-out direction — board-level agreements:
(a [[wikilink]] linked entity + an inline agreement string) and interactions:
(a [[wikilink]] meeting pointer), plus a column-scoped agreements: entry. Each
renders as a single grouped bucket chip → the shared drawer, never per-entry chips:
title: Sprint Board agreements: - "[[Team Working Agreements]]" - "WIP per column: 3" interactions: - "[[Daily Standup]]" columns: - ToDo - name: Doing agreements: - "Pull only when capacity is free" - Done
Like what you see? → Start — build your own org folder in ~2 min