diff --git a/state-hub/dashboard/observablehq.config.js b/state-hub/dashboard/observablehq.config.js
index 3d994ff..28ff4f4 100644
--- a/state-hub/dashboard/observablehq.config.js
+++ b/state-hub/dashboard/observablehq.config.js
@@ -10,6 +10,8 @@ export default {
name: "Reference",
pages: [
{ name: "Live Data", path: "/docs/live-data" },
+ { name: "Workstreams", path: "/docs/workstreams" },
+ { name: "Decisions", path: "/docs/decisions" },
{ name: "Decision Health", path: "/docs/decisions-kpi" },
{ name: "Progress Log", path: "/docs/progress-log" },
],
diff --git a/state-hub/dashboard/src/decisions.md b/state-hub/dashboard/src/decisions.md
index c9dba84..971ca0f 100644
--- a/state-hub/dashboard/src/decisions.md
+++ b/state-hub/dashboard/src/decisions.md
@@ -160,6 +160,9 @@ const _liveEl = html`
`;
withDocHelp(_liveEl, "/docs/live-data");
+const _h1 = document.querySelector("#observablehq-main h1");
+if (_h1) { _h1.style.position = "relative"; withDocHelp(_h1, "/docs/decisions"); }
+
// ── Inject into TOC sidebar: KPI first (prepend → bottom), live last (→ top) ─
const _toc = document.querySelector("#observablehq-toc");
if (_toc) {
diff --git a/state-hub/dashboard/src/docs/decisions.md b/state-hub/dashboard/src/docs/decisions.md
new file mode 100644
index 0000000..a55ae35
--- /dev/null
+++ b/state-hub/dashboard/src/docs/decisions.md
@@ -0,0 +1,138 @@
+---
+title: Decisions — Reference
+---
+
+# Decisions — Reference
+
+The Decisions page tracks every choice that matters: things pending a verdict, things already resolved, and things that have been escalated for human approval before action can proceed.
+
+---
+
+## Decision types
+
+| Type | Meaning |
+|---|---|
+| **pending** | A question or fork that still needs an answer — actively blocking or influencing work |
+| **made** | A resolved choice; kept for historical context and to explain why things are the way they are |
+
+---
+
+## Decision statuses
+
+| Status | Border | Meaning |
+|---|---|---|
+| **open** | blue | Pending, no urgent flag |
+| **escalated** | amber | Requires human approval before any action (constitution §4) |
+| **resolved** | green | Decision has been made and recorded |
+| **superseded** | gray | Replaced by a newer decision |
+
+Decisions are sorted by status (escalated → open → resolved → superseded), then by deadline (earliest first within the same status group).
+
+---
+
+## Resolution History chart
+
+An area + step chart showing cumulative decisions over time. Each dot marks a period where at least one decision was recorded or resolved.
+
+**Period selector** — choose the time window:
+
+| Period | Bucket | Use for |
+|---|---|---|
+| day | hour | Today's activity |
+| week | day | Rolling 7 days |
+| month | week | Current calendar month |
+| quarter | month | Current quarter |
+| YTD | month | Year to date |
+| year | month | Rolling 12 months |
+| all | month | Full history |
+
+The chart respects the active filter — changing type, status, or search narrows the data plotted.
+
+---
+
+## Filter bar
+
+| Filter | Effect |
+|---|---|
+| **Type** | Show only `pending` or `made` decisions |
+| **Status** | Show one or more of open / escalated / resolved / superseded |
+| **Search** | Case-insensitive substring match on the decision title |
+
+All filters are applied client-side on the last 500 decisions fetched from the API.
+
+---
+
+## Decision cards
+
+Each card shows:
+
+- **Type badge** — amber `pending` or indigo `made`
+- **Status badge** — colour-coded (see table above)
+- **Domain** — which of the six tracked domains this decision belongs to (if linked to a topic)
+- **Due date** — shown in red with ⚠ if the deadline has passed
+- **Age badge** — `open Xd` for unresolved decisions; `took Xd` for resolved ones. Turns amber when an open decision has been open longer than the current average resolution time.
+- **Created date** — when the decision was first recorded
+- **Title** — the decision question or statement
+- **Description / rationale** — first 200 characters, truncated with `…`
+- **Resolved by** — who resolved it and when (resolved decisions only)
+- **Escalation note** — amber panel explaining why human approval is required (escalated decisions only)
+
+---
+
+## Decision Health card
+
+The **Decision Health** widget in the right margin shows two KPIs computed from the full (unfiltered) dataset:
+
+| KPI | How it's calculated |
+|---|---|
+| **avg resolve** | Mean time from creation to resolution, computed over the last 5 resolved decisions |
+| **avg open age** | Mean age of all currently open or escalated decisions |
+
+**Color coding for avg open age:**
+
+| Color | Condition |
+|---|---|
+| black (inherit) | All open decisions younger than the avg resolve time |
+| amber | At least one open decision older than the avg resolve time |
+| red | Mean open age exceeds the avg resolve time |
+
+---
+
+## Escalation
+
+Any `pending` decision whose title or rationale contains financial or legal keywords is automatically escalated by the API at creation time. Escalated decisions:
+
+- Sort to the top of the list
+- Carry an amber escalation note explaining the reason
+- Trigger the warning box at the bottom of the page listing all escalated items
+- **Must be reviewed and approved by Bernd before any related action is taken (constitution §4)**
+
+To clear an escalation, resolve the decision via `resolve_decision()` in the MCP server or the REST API.
+
+---
+
+## Adding decisions
+
+Via MCP:
+
+```
+record_decision(
+ title = "Should we use Redis or Postgres for session storage?",
+ decision_type = "pending",
+ workstream_id = "",
+ rationale = "Postgres is already in the stack; Redis adds a dependency",
+ deadline = "2026-03-01"
+)
+```
+
+Via REST:
+
+```bash
+curl -X POST http://127.0.0.1:8000/decisions/ \
+ -H "Content-Type: application/json" \
+ -d '{"title": "…", "decision_type": "pending", "workstream_id": ""}'
+```
+
+---
+
+*Decisions are never deleted — only resolved or superseded (constitution §5).*
diff --git a/state-hub/dashboard/src/docs/workstreams.md b/state-hub/dashboard/src/docs/workstreams.md
new file mode 100644
index 0000000..4e3920d
--- /dev/null
+++ b/state-hub/dashboard/src/docs/workstreams.md
@@ -0,0 +1,110 @@
+---
+title: Workstreams — Reference
+---
+
+# Workstreams — Reference
+
+A workstream is a bounded unit of work within a topic. It carries a status, an optional owner and due date, and belongs to exactly one of the six project domains. The Workstreams page gives you a filtered, visual overview of all active work and the dependency graph between workstreams.
+
+---
+
+## Status Distribution chart
+
+A horizontal bar chart showing the count of workstreams in each status for the current filter selection. Updates immediately as filters change.
+
+| Status | Meaning |
+|---|---|
+| **active** | Work in progress or ready to start |
+| **blocked** | Waiting on something outside the workstream — see Dependencies |
+| **completed** | Done |
+| **archived** | Closed without completion; no longer relevant |
+
+---
+
+## Filter bar
+
+| Filter | Effect |
+|---|---|
+| **Domain** | Multi-select — show only workstreams from selected domains |
+| **Status** | Multi-select — show only workstreams with selected statuses |
+| **Owner** | Text substring match on the owner field (case-insensitive) |
+
+Leaving a filter empty means "show all". All three filters combine with AND logic. Filters persist across polls — selections are not lost when the page refreshes live data.
+
+The six domains are: `custodian`, `railiance`, `markitect`, `coulomb_social`, `personhood`, `foerster_capabilities`.
+
+---
+
+## All Workstreams table
+
+| Column | Source |
+|---|---|
+| Title | Workstream title |
+| Domain | Derived from the parent topic |
+| Status | Current workstream status |
+| Owner | Assigned person (or `—` if unset) |
+| Due | Target completion date (or `—`) |
+| Updated | Last modification timestamp |
+
+Up to 20 rows displayed; paginate for more.
+
+---
+
+## Dependencies
+
+The Dependencies section shows workstreams that have at least one `depends_on` or `blocks` relationship. Each card displays:
+
+- **Workstream title** and current status badge
+- **↳ depends on** — workstreams that must complete before this one can proceed
+- **⊳ blocks** — workstreams that are waiting on this one
+
+Dependencies are created via the MCP server:
+
+```
+create_dependency(
+ from_workstream_id = "", # the one that depends
+ to_workstream_id = "", # the prerequisite
+ description = "needs auth before API can be built"
+)
+```
+
+If no dependency edges exist for the current filter, the section shows an empty-state message.
+
+---
+
+## Creating workstreams
+
+Via MCP:
+
+```
+create_workstream(
+ topic_id = "",
+ title = "Build user authentication",
+ description = "JWT-based auth, refresh tokens, middleware",
+ status = "active",
+ owner = "Bernd",
+ due_date = "2026-04-01"
+)
+```
+
+Via REST:
+
+```bash
+curl -X POST http://127.0.0.1:8000/workstreams/ \
+ -H "Content-Type: application/json" \
+ -d '{"topic_id": "", "title": "…", "status": "active"}'
+```
+
+---
+
+## Updating workstream status
+
+```
+update_workstream_status(workstream_id="", status="completed")
+```
+
+Valid transitions: `active` → `blocked` / `completed` / `archived`; `blocked` → `active`; `completed` → `archived`.
+
+---
+
+*Workstreams are never hard-deleted — use `archived` to close them without losing history.*
diff --git a/state-hub/dashboard/src/progress.md b/state-hub/dashboard/src/progress.md
index 9587976..3b5e5ed 100644
--- a/state-hub/dashboard/src/progress.md
+++ b/state-hub/dashboard/src/progress.md
@@ -30,8 +30,6 @@ const _ts = progState.ts;
# Progress Log
-*Append-only per constitution §5 — no deletions.*
-
```js
import {injectTocTop} from "./components/toc-sidebar.js";
import {withDocHelp} from "./components/doc-overlay.js";
diff --git a/state-hub/dashboard/src/workstreams.md b/state-hub/dashboard/src/workstreams.md
index e3c7d02..20856a7 100644
--- a/state-hub/dashboard/src/workstreams.md
+++ b/state-hub/dashboard/src/workstreams.md
@@ -58,6 +58,9 @@ const _liveEl = html`
`;
withDocHelp(_liveEl, "/docs/live-data");
injectTocTop("live-indicator", _liveEl);
+
+const _h1 = document.querySelector("#observablehq-main h1");
+if (_h1) { _h1.style.position = "relative"; withDocHelp(_h1, "/docs/workstreams"); }
```
```js