Add state-hub v0.1 — local-first state service for the Custodian
Implements the first live layer of the Custodian cognitive infrastructure:
PostgreSQL schema, FastAPI REST API, FastMCP stdio server, and Observable
Framework telemetry dashboard.
- state-hub/: full stack (docker-compose, FastAPI, Alembic, MCP server, dashboard)
- 5 DB tables: topics, workstreams, tasks, decisions, progress_events
- 11 MCP tools + 5 resources registered in .mcp.json
- Observable dashboard: Overview, Workstreams, Decisions, Progress pages
- CLAUDE.md: session protocol (get_state_summary / add_progress_event ritual)
- ~/.claude/CLAUDE.md: global cross-project reference to the hub
- scripts/pull_image.py: WSL2 TLS-resilient Docker image downloader
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 17:47:49 +01:00
---
title: Workstreams
---
2026-02-24 23:19:26 +01:00
```js
const API = "http://127.0.0.1:8000";
const POLL = 15_000;
```
```js
2026-02-25 23:33:14 +01:00
// Fetch workstreams + topics + summary (for dep graph) in parallel
2026-02-24 23:19:26 +01:00
const wsState = (async function*() {
while (true) {
2026-02-25 23:33:14 +01:00
let data = [], openWs = [], ok = false;
2026-02-24 23:19:26 +01:00
try {
2026-02-25 23:33:14 +01:00
const [rw, rt, rs] = await Promise.all([
2026-02-24 23:19:26 +01:00
fetch(`${API}/workstreams/` ),
fetch(`${API}/topics/` ),
2026-02-25 23:33:14 +01:00
fetch(`${API}/state/summary` ),
2026-02-24 23:19:26 +01:00
]);
2026-02-25 23:33:14 +01:00
ok = rw.ok & & rt.ok & & rs.ok;
2026-02-24 23:19:26 +01:00
if (ok) {
2026-02-25 23:33:14 +01:00
const [wsList, topicList, summary] = await Promise.all([rw.json(), rt.json(), rs.json()]);
2026-02-24 23:19:26 +01:00
const topicMap = Object.fromEntries(topicList.map(t => [t.id, t]));
data = wsList.map(w => ({
...w,
domain: topicMap[w.topic_id]?.domain ?? "unknown",
topic_title: topicMap[w.topic_id]?.title ?? "—",
}));
2026-02-25 23:33:14 +01:00
// open_workstreams from summary carry depends_on / blocks lists
openWs = summary.open_workstreams ?? [];
2026-02-24 23:19:26 +01:00
}
} catch {}
2026-02-25 23:33:14 +01:00
yield {data, openWs, ok, ts: new Date()};
2026-02-24 23:19:26 +01:00
await new Promise(res => setTimeout(res, POLL));
}
})();
```
```js
2026-02-25 23:33:14 +01:00
const data = wsState.data ?? [];
const openWs = wsState.openWs ?? [];
const _ok = wsState.ok ?? false;
const _ts = wsState.ts;
2026-02-24 23:19:26 +01:00
```
Add state-hub v0.1 — local-first state service for the Custodian
Implements the first live layer of the Custodian cognitive infrastructure:
PostgreSQL schema, FastAPI REST API, FastMCP stdio server, and Observable
Framework telemetry dashboard.
- state-hub/: full stack (docker-compose, FastAPI, Alembic, MCP server, dashboard)
- 5 DB tables: topics, workstreams, tasks, decisions, progress_events
- 11 MCP tools + 5 resources registered in .mcp.json
- Observable dashboard: Overview, Workstreams, Decisions, Progress pages
- CLAUDE.md: session protocol (get_state_summary / add_progress_event ritual)
- ~/.claude/CLAUDE.md: global cross-project reference to the hub
- scripts/pull_image.py: WSL2 TLS-resilient Docker image downloader
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 17:47:49 +01:00
# Workstreams
```js
2026-02-24 23:19:26 +01:00
display(html`< div class = "live-bar" >
< span style = "color:${_ok ? 'var(--theme-foreground-focus)' : 'red'}" > ●< / span >
${_ok
? `Live · updated ${_ts?.toLocaleTimeString()}`
: `<span style="color:red">Offline — run: <code>make api</code></span>` }
< / div > `);
Add state-hub v0.1 — local-first state service for the Custodian
Implements the first live layer of the Custodian cognitive infrastructure:
PostgreSQL schema, FastAPI REST API, FastMCP stdio server, and Observable
Framework telemetry dashboard.
- state-hub/: full stack (docker-compose, FastAPI, Alembic, MCP server, dashboard)
- 5 DB tables: topics, workstreams, tasks, decisions, progress_events
- 11 MCP tools + 5 resources registered in .mcp.json
- Observable dashboard: Overview, Workstreams, Decisions, Progress pages
- CLAUDE.md: session protocol (get_state_summary / add_progress_event ritual)
- ~/.claude/CLAUDE.md: global cross-project reference to the hub
- scripts/pull_image.py: WSL2 TLS-resilient Docker image downloader
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 17:47:49 +01:00
```
```js
2026-02-26 00:05:58 +01:00
// Static options — no dependency on `data` , so selections survive polls
const DOMAINS = ["custodian", "railiance", "markitect", "coulomb_social", "personhood", "foerster_capabilities"];
const STATUSES = ["active", "blocked", "completed", "archived"];
const filters = view(Inputs.form(
{
domain: Inputs.checkbox(DOMAINS, {label: "Domain"}),
status: Inputs.checkbox(STATUSES, {label: "Status"}),
owner: Inputs.text({label: "Owner contains", placeholder: "filter by owner…"}),
},
{
template: ({domain, status, owner}) => html`< div class = "filter-bar" >
< div class = "filter-group" > ${domain}< / div >
< div class = "filter-group" > ${status}< / div >
< div class = "filter-group filter-group-text" > ${owner}< / div >
< / div > `,
}
));
Add state-hub v0.1 — local-first state service for the Custodian
Implements the first live layer of the Custodian cognitive infrastructure:
PostgreSQL schema, FastAPI REST API, FastMCP stdio server, and Observable
Framework telemetry dashboard.
- state-hub/: full stack (docker-compose, FastAPI, Alembic, MCP server, dashboard)
- 5 DB tables: topics, workstreams, tasks, decisions, progress_events
- 11 MCP tools + 5 resources registered in .mcp.json
- Observable dashboard: Overview, Workstreams, Decisions, Progress pages
- CLAUDE.md: session protocol (get_state_summary / add_progress_event ritual)
- ~/.claude/CLAUDE.md: global cross-project reference to the hub
- scripts/pull_image.py: WSL2 TLS-resilient Docker image downloader
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 17:47:49 +01:00
```
```js
2026-02-26 00:05:58 +01:00
// Empty array = no filter applied (show all)
Add state-hub v0.1 — local-first state service for the Custodian
Implements the first live layer of the Custodian cognitive infrastructure:
PostgreSQL schema, FastAPI REST API, FastMCP stdio server, and Observable
Framework telemetry dashboard.
- state-hub/: full stack (docker-compose, FastAPI, Alembic, MCP server, dashboard)
- 5 DB tables: topics, workstreams, tasks, decisions, progress_events
- 11 MCP tools + 5 resources registered in .mcp.json
- Observable dashboard: Overview, Workstreams, Decisions, Progress pages
- CLAUDE.md: session protocol (get_state_summary / add_progress_event ritual)
- ~/.claude/CLAUDE.md: global cross-project reference to the hub
- scripts/pull_image.py: WSL2 TLS-resilient Docker image downloader
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 17:47:49 +01:00
const filtered = data.filter(w =>
2026-02-26 00:05:58 +01:00
(filters.domain.length === 0 || filters.domain.includes(w.domain)) & &
(filters.status.length === 0 || filters.status.includes(w.status)) & &
(!filters.owner || (w.owner ?? "").toLowerCase().includes(filters.owner.toLowerCase()))
Add state-hub v0.1 — local-first state service for the Custodian
Implements the first live layer of the Custodian cognitive infrastructure:
PostgreSQL schema, FastAPI REST API, FastMCP stdio server, and Observable
Framework telemetry dashboard.
- state-hub/: full stack (docker-compose, FastAPI, Alembic, MCP server, dashboard)
- 5 DB tables: topics, workstreams, tasks, decisions, progress_events
- 11 MCP tools + 5 resources registered in .mcp.json
- Observable dashboard: Overview, Workstreams, Decisions, Progress pages
- CLAUDE.md: session protocol (get_state_summary / add_progress_event ritual)
- ~/.claude/CLAUDE.md: global cross-project reference to the hub
- scripts/pull_image.py: WSL2 TLS-resilient Docker image downloader
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 17:47:49 +01:00
);
display(Inputs.table(filtered.map(w => ({
2026-02-24 23:19:26 +01:00
Title: w.title,
Domain: w.domain,
Status: w.status,
Owner: w.owner ?? "—",
Due: w.due_date ?? "—",
Updated: new Date(w.updated_at).toLocaleDateString(),
})), {rows: 20}));
Add state-hub v0.1 — local-first state service for the Custodian
Implements the first live layer of the Custodian cognitive infrastructure:
PostgreSQL schema, FastAPI REST API, FastMCP stdio server, and Observable
Framework telemetry dashboard.
- state-hub/: full stack (docker-compose, FastAPI, Alembic, MCP server, dashboard)
- 5 DB tables: topics, workstreams, tasks, decisions, progress_events
- 11 MCP tools + 5 resources registered in .mcp.json
- Observable dashboard: Overview, Workstreams, Decisions, Progress pages
- CLAUDE.md: session protocol (get_state_summary / add_progress_event ritual)
- ~/.claude/CLAUDE.md: global cross-project reference to the hub
- scripts/pull_image.py: WSL2 TLS-resilient Docker image downloader
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 17:47:49 +01:00
```
2026-02-24 23:19:26 +01:00
## Status Distribution
Add state-hub v0.1 — local-first state service for the Custodian
Implements the first live layer of the Custodian cognitive infrastructure:
PostgreSQL schema, FastAPI REST API, FastMCP stdio server, and Observable
Framework telemetry dashboard.
- state-hub/: full stack (docker-compose, FastAPI, Alembic, MCP server, dashboard)
- 5 DB tables: topics, workstreams, tasks, decisions, progress_events
- 11 MCP tools + 5 resources registered in .mcp.json
- Observable dashboard: Overview, Workstreams, Decisions, Progress pages
- CLAUDE.md: session protocol (get_state_summary / add_progress_event ritual)
- ~/.claude/CLAUDE.md: global cross-project reference to the hub
- scripts/pull_image.py: WSL2 TLS-resilient Docker image downloader
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 17:47:49 +01:00
```js
import * as Plot from "npm:@observablehq/plot ";
2026-02-24 23:19:26 +01:00
const byStatus = Object.entries(
filtered.reduce((acc, w) => { acc[w.status] = (acc[w.status] ?? 0) + 1; return acc; }, {})
).map(([status, count]) => ({status, count}));
Add state-hub v0.1 — local-first state service for the Custodian
Implements the first live layer of the Custodian cognitive infrastructure:
PostgreSQL schema, FastAPI REST API, FastMCP stdio server, and Observable
Framework telemetry dashboard.
- state-hub/: full stack (docker-compose, FastAPI, Alembic, MCP server, dashboard)
- 5 DB tables: topics, workstreams, tasks, decisions, progress_events
- 11 MCP tools + 5 resources registered in .mcp.json
- Observable dashboard: Overview, Workstreams, Decisions, Progress pages
- CLAUDE.md: session protocol (get_state_summary / add_progress_event ritual)
- ~/.claude/CLAUDE.md: global cross-project reference to the hub
- scripts/pull_image.py: WSL2 TLS-resilient Docker image downloader
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 17:47:49 +01:00
display(Plot.plot({
marks: [
2026-02-24 23:19:26 +01:00
Plot.barX(byStatus, {y: "status", x: "count", fill: "status", tip: true}),
Add state-hub v0.1 — local-first state service for the Custodian
Implements the first live layer of the Custodian cognitive infrastructure:
PostgreSQL schema, FastAPI REST API, FastMCP stdio server, and Observable
Framework telemetry dashboard.
- state-hub/: full stack (docker-compose, FastAPI, Alembic, MCP server, dashboard)
- 5 DB tables: topics, workstreams, tasks, decisions, progress_events
- 11 MCP tools + 5 resources registered in .mcp.json
- Observable dashboard: Overview, Workstreams, Decisions, Progress pages
- CLAUDE.md: session protocol (get_state_summary / add_progress_event ritual)
- ~/.claude/CLAUDE.md: global cross-project reference to the hub
- scripts/pull_image.py: WSL2 TLS-resilient Docker image downloader
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 17:47:49 +01:00
Plot.ruleX([0]),
],
marginLeft: 80,
width: 500,
}));
```
2026-02-24 23:19:26 +01:00
2026-02-25 23:33:14 +01:00
## Dependencies
```js
// Build dep cards from the enriched open_workstreams in the summary
2026-02-26 00:05:58 +01:00
const wsWithDeps = openWs.filter(w => {
const domain = data.find(d => d.id === w.id)?.domain ?? "unknown";
return (filters.domain.length === 0 || filters.domain.includes(domain)) & &
(filters.status.length === 0 || filters.status.includes(w.status)) & &
(w.depends_on.length > 0 || w.blocks.length > 0);
});
2026-02-25 23:33:14 +01:00
if (wsWithDeps.length === 0) {
display(html`<p class="dim">No dependency edges recorded for the current filter. Use <code>create_dependency()</code> via the MCP server to link workstreams.</p>` );
} else {
display(html`< div class = "dep-grid" > ${wsWithDeps.map(w => {
const depRows = w.depends_on.map(d =>
html`<div class="dep-row dep-on">↳ depends on <strong>${d.workstream_title}</strong>${d.description ? html` < span class = "dep-desc" > — ${d.description}</ span > ` : ""}</div>`
);
const blockRows = w.blocks.map(d =>
html`<div class="dep-row dep-block">⊳ blocks <strong>${d.workstream_title}</strong>${d.description ? html` < span class = "dep-desc" > — ${d.description}</ span > ` : ""}</div>`
);
return html`< div class = "dep-card" >
< div class = "dep-title" > ${w.title}< / div >
< div class = "dep-status dep-status-${w.status}" > ${w.status}< / div >
${depRows}${blockRows}
< / div > `;
})}< / div > `);
}
```
2026-02-24 23:19:26 +01:00
< style >
.live-bar { font-size: 0.8rem; color: gray; text-align: right; margin-bottom: 0.5rem; }
2026-02-25 23:33:14 +01:00
.dim { color: gray; font-style: italic; }
2026-02-26 00:05:58 +01:00
.filter-bar { display: flex; flex-wrap: wrap; gap: 1.5rem; align-items: flex-start; padding: 0.75rem 1rem; background: var(--theme-background-alt); border-radius: 8px; margin-bottom: 1rem; }
.filter-group { min-width: 140px; }
.filter-group-text { align-self: flex-end; }
2026-02-25 23:33:14 +01:00
.dep-grid { display: flex; flex-direction: column; gap: 0.75rem; }
.dep-card { border: 1px solid #e0e0e0 ; border-radius: 6px; padding: 0.75rem 1rem; background: var(--theme-background-alt, #fafafa ); }
.dep-title { font-weight: 600; margin-bottom: 0.25rem; }
.dep-status { display: inline-block; font-size: 0.7rem; padding: 1px 6px; border-radius: 10px; margin-bottom: 0.5rem; text-transform: uppercase; }
.dep-status-active { background: #d4edda ; color: #155724 ; }
.dep-status-blocked { background: #f8d7da ; color: #721c24 ; }
.dep-status-completed { background: #cce5ff ; color: #004085 ; }
.dep-row { font-size: 0.85rem; margin: 0.2rem 0 0 0.5rem; color: #444 ; }
.dep-on { color: #1a5276 ; }
.dep-block { color: #6e2f00 ; }
.dep-desc { color: #888 ; font-size: 0.8rem; }
2026-02-24 23:19:26 +01:00
< / style >