---
title: Workstream
---
```js
import {API} from "../components/config.js";
import {fieldRow} from "../components/field-help.js";
```
```js
const wsId = observable.params.id;
const [raw, taskRows, workplanIndex] = await Promise.all([
fetch(`${API}/workstreams/${wsId}`)
.then(r => r.ok ? r.json() : r.json().then(e => ({error: e.detail ?? `HTTP ${r.status}`})))
.catch(e => ({error: String(e)})),
fetch(`${API}/tasks/?workstream_id=${wsId}&limit=1000`)
.then(r => r.ok ? r.json() : [])
.catch(() => []),
fetch(`${API}/workstreams/workplan-index`)
.then(r => r.ok ? r.json() : {workstreams: {}})
.catch(() => ({workstreams: {}})),
]);
```
```js
if (raw.error) {
display(html`
⚠️ ${raw.error}
`);
} else {
const workplan = (workplanIndex.workstreams ?? {})[wsId] ?? {};
const name = raw.title || raw.slug || wsId;
const shortName = name.length > 60 ? name.slice(0, 60) + "…" : name;
display(html`Workstream · ${shortName}
`);
display(html`← Overview | ← Workstreams | ← Token Cost
`);
display(html`
Status${raw.status ?? "—"}
Workplan${workplan.filename ?? "not file-backed"}
Tasks${taskRows.length}
`);
const statusOrder = {blocked: 0, in_progress: 1, todo: 2, done: 3, cancelled: 4};
const sortedTasks = [...taskRows].sort((a, b) => {
const statusCompare = (statusOrder[a.status] ?? 9) - (statusOrder[b.status] ?? 9);
if (statusCompare !== 0) return statusCompare;
return (a.title ?? "").localeCompare(b.title ?? "");
});
display(html`Tasks
`);
if (sortedTasks.length === 0) {
display(html`No tasks are attached to this workstream.
`);
} else {
display(html`
| Status | Priority | Task | Human |
${sortedTasks.map(t => html`
| ${t.status} |
${t.priority ?? "—"} |
${t.title ?? t.id} |
${t.needs_human ? "yes" : ""} |
`)}
`);
}
const FIELD_ORDER = [
"id","slug","title","status","topic_id","repo_id","repo_goal_id",
"created_at","updated_at",
];
const rows = FIELD_ORDER.map(k => fieldRow(k, raw[k] ?? null));
for (const k of Object.keys(raw)) {
if (!FIELD_ORDER.includes(k)) rows.push(fieldRow(k, raw[k]));
}
display(html``);
}
```