---
summary: "Task Management concept: log/board/tasks lifecycle, status enum, KIND-as-folder — the human-readable companion to AGENTS.md § Task Management."
type: guide
last_updated: 2026-06-21
related:
  - AGENTS.md
  - docs/structure.md
---

# Task Management

## Concept

Central task tracking from the bridge. Log activities, manage tasks,
archive weekly summaries. All data persists in `work/` on your user branch.
(The system concept is **Task Management**; the directory name `work/` stays.)

**Two orthogonal axes.** KIND is the **folder** a task lives in; `status:` is the
**frontmatter field**. They never collapse into one another:

- `work/tasks/<slug>/` = **FINITE** task — reaches `done`.
- `work/streams/<slug>/` = **LONG-RUNNER** — never `done`, excluded from WIP.
- `work/done/YYYY-MM/<slug>/` = closed.

Moving KIND = `mv` the directory; there is **no `kind:` frontmatter field**.
`status:` is the only state field.

## Structure

```
work/
├── log.md                Weekly log with daily blocks
├── board.md              GENERATED task board (Doing / Review / Backlog / Streams / Done-YYYY-MM)
├── tasks/{slug}/         FINITE tasks with a STATUS.md (reaches done)
│   ├── STATUS.md         Frontmatter + body; SoT for one task
│   ├── PLAN.md           Implementation plan (from brainstorming/planning)
│   └── SPEC.md           Design spec (from brainstorming/design)
├── streams/{slug}/       LONG-RUNNERS (same artifacts; never done, excluded from WIP)
├── done/YYYY-MM/         Closed tasks (status: done, folder moved here)
├── archive/              Weekly summaries
├── imports/              Universal inbox (.gitignored)
├── import-rules.yaml     File-pattern → action mapping
└── templates/            CORE skeletons:
    ├── week-skeleton.md  Fresh weekly log.md (CW-wrapper + first day-block)
    ├── day.md            One day-block (appended into the current week)
    ├── board.md          Empty board
    ├── STATUS.md         Per-task status + _schema.status.yaml
    └── week-summary.md   /archive weekly summary
```

`backlog`, `doing`, `review`, `done` are **status values** carried in each
STATUS.md — not folders. The folder encodes **KIND**, not status: `work/tasks/`
(finite) and `work/streams/` (long-runner). There is no `work/doing/`,
`work/queue/`, `work/review/`, or per-status folder. Two moves relocate a folder:
the close move (→ `work/done/YYYY-MM/<slug>/`) and a KIND reclassification
(`work/tasks/ ↔ work/streams/`). The full STATUS.md schema (status enum, context
pattern, headline field, sync block) lives at `work/templates/_schema.status.yaml`.

## Status semantics

`status:` is a **closed enum** — exactly `{backlog, doing, review, done}`,
CI-validated against `work/templates/_schema.status.yaml`. No synonyms, no new
states without editing the schema.

- **`backlog`** — captured, not started.
- **`doing`** — actively in flight.
- **`review`** — required hop before `done`; the human confirms the final `done`
  (no-direct-Done). `review` is also what the GitHub Projects `state_map` expects.
- **`done`** — completed. The human confirms the final transition.

Two things that are **not** statuses:

- **Blocked is a FLAG, not a status.** A blocked task stays `doing` (or `review`)
  and carries a free-text `blocked_by: "<reason>"`. The enum never grows to absorb
  a `waiting` state.
- **Declined is an OUTCOME, not a status.** A task closed without completion is
  `status: done` **+** `outcome: declined`.

`waiting`, `building`, `in-progress`, `in_review`, `active`, `cancelled` are all
**invalid** — they fail the schema.

## Generated board

`board.md` is **generated from the task directories** — never hand-curated. Its
sections map 1:1 to the enum (+ Streams + Done):

```
## Doing          ← work/tasks/* with status: doing
## Review         ← work/tasks/* with status: review
## Backlog        ← work/tasks/* with status: backlog
## Streams        ← work/streams/*  (excluded from WIP)
## Done — YYYY-MM  ← rolled from work/done/<current-month>/
```

Counts derive from `ls` over the task dirs, so they **cannot drift**. Humans edit
**STATUS.md**, never the board; the board is regenerated by
`scripts/gen-board.py` (run `--check` for a dry-run drift summary). A blocked
task shows its status with a `🚧 blocked` marker, derived from its `blocked_by:`
field — not a separate section.

**Regenerate trigger:** at session-start and on every task move/close (3-step close
below). A board row that disagrees with the dirs is a regeneration artifact, not a
hand-edit to reconcile — fix the STATUS.md `status:` and regenerate.

## WIP cap — warning only

The WIP cap is a **warning, never a block**. At session-start, when the count of
`doing + review` tasks in `work/tasks/` exceeds `bridge-config.yaml`
`work.max_active`, the bridge surfaces a warning. New work is **never** auto-refused.
The remedy is to close, reprioritise, or **reclassify a genuine long-runner to
`work/streams/`** — streams never count against WIP. (`gen-board.py` mirrors the
same threshold and flags `⚠️ WIP n > cap` in the generated header.)

## 3-step close

Closing or reclassifying a task is three steps, in order:

1. **`mv` the directory** — `git mv work/tasks/<slug>/ work/done/$(date +%Y-%m)/<slug>/`
   (or `work/tasks/ ↔ work/streams/` for a KIND change).
2. **Regenerate `board.md`** from the dirs via `scripts/gen-board.py` (it is
   generated, never hand-edited).
3. **Append a `log.md` row** with a timestamp.

## Log format — weekly file, daily blocks

`log.md` is **one file per week**. The week header `# Week {CW} — {DATE_FROM} to {DATE_TO}`
plus an `**Active Focus:**` line wrap a sequence of daily blocks. `/archive`
rolls a finished week into `work/archive/weeks/` and resets `log.md` from
`work/templates/week-skeleton.md`.

Each day-block (template: `work/templates/day.md`):

```markdown
## Mon 18.05

<details open>
<summary>Worklog (1)</summary>

| YYYY-MM-DD HH:MM | Type | Context | What |
|------------------|------|---------|------|
| 2026-05-18 14:55 | 📋   | bridge  | ...  |

</details>
```

Conventions:

- **ONE log row format, frozen:** `| YYYY-MM-DD HH:MM | Type | Context | What |` — a
  full-ISO `YYYY-MM-DD HH:MM` timestamp via `date '+%Y-%m-%d %H:%M'`, a glyph/name Type, a
  context, and the what. Every row **self-dates** (never `xx:xx` placeholders), so you can
  always tell which day a row belongs to without scrolling to the header — a stale or
  unarchived log is never ambiguous. The legacy time-only `| HH:MM | ... |` row is **retired**
  — do not emit it.
- **Header `## {Weekday} DD.MM`** (locale weekday name + `DD.MM`, no separators,
  no week suffix). `/archive` and `/briefing` parse exactly this as `^## \S+ DD.MM`
  and derive any date/CW from `DD.MM`, never from the weekday name — `## 2026-05-21 — Thursday`
  is drift and is invisible to the archive parser.
- **Worklog rows carry a full `YYYY-MM-DD HH:MM`** — self-dating; the `## {Weekday} DD.MM`
  header stays only a display anchor for the parsers.
- **Logging is mandatory + continuous** — every substantive unit of work gets its own
  row the moment it lands, not batched. The `worklog-drift-check.sh` Stop hook is the
  deterministic backstop (it blocks end-of-turn when code changed without a log row for
  today, and when a STATUS.md body asserts completion while its `status:` is not `done`).
- **Log sits in a `<details>` block** with a `(N)` count in the `<summary>`. The
  current day ships `<details open>` (working memory stays visible); collapse it
  (drop `open`) once the day closes so past days stay compact.

## Session start

Automatic at the start of every session when Task Management is enabled:

1. **Read** `work/log.md` + `work/board.md`.
2. **If `log.md` is missing**, create it from `work/templates/week-skeleton.md` —
   never fail on a missing work file.
3. **Open today's day-block** from `work/templates/day.md`; the header **must** match
   `## {Weekday} DD.MM` (e.g. `## Mon 18.05`) — `/archive` and `/briefing` parse exactly
   that pattern.
4. **Regenerate the board** from the dirs (`scripts/gen-board.py`) so its counts
   reflect reality.
5. **Warn on WIP overflow** — if `doing + review` in `work/tasks/` exceeds
   `work.max_active`, surface the warning (never block; see WIP cap above).
6. **Load standing orders** with `scope: always`.

## When does work become a Board task?

Three-class rule from [`protocols/standing-orders/board-task-criteria.md`](../protocols/standing-orders/board-task-criteria.md):

- **A — Board task** (STATUS.md + board row): cross-session pickup needed **or** external recipient (mandant / external tracker / customer wiki).
- **B — Log-only**: state changed, but session-bounded and no external party.
- **C — Silent**: read-only routine commands (`/briefing`, `/bridge-status`, `/archive`).

Sub-items of an existing task are checked off in the parent STATUS.md — no own task. Cold ideas without pickup plan live in `work/backlog.md` (lazily created, split threshold >15 backlog rows).

## Configuration

Single source: `bridge-config.yaml` (USER layer), `work:` block. Controls:
- **Logging level** (hybrid/auto/manual) — how aggressively to log
- **Activity types** — emoji × name list for log entries
- **Limits** — `max_active` (WIP warning threshold for doing+review in `work/tasks/`; warns, never blocks), daily goals
- **Imports** — directory + rules for the universal inbox

The legacy `work/.config.yaml` is obsolete (merged into `bridge-config.yaml` on 2026-04-11).

## Activation

Say "set up task management" (or the legacy "set up work system") or enable during
`/bridge-onboard`. The toggle is `work.enabled` in `bridge-config.yaml`.

## Task Artifacts

Each task directory can contain:

| File | Created by | Purpose |
|------|-----------|---------|
| `STATUS.md` | Task creation | Status, description, log entries |
| `PLAN.md` | `/brainstorm` → planning | Step-by-step implementation plan |
| `SPEC.md` | `/brainstorm` → design | Design specification, architecture decisions |
| `*.md` | Any workflow | Additional notes, research, meeting notes |

Plans and specs **belong to their task**, not in a separate docs/ folder.
When a task moves to done/, its artifacts travel with it — preserving
the full decision context for future reference.

## Daily: /briefing → work → /briefing

## Weekly: /archive → summary → fresh week

## 30-Minute Rule

If you've been working for 30+ minutes without a log entry, log immediately.
The bridge will remind you during active work sessions.

## Per-Dir Documentation

When a task folder needs navigation (plan + spec + research + meetings side by side),
write a `README.md` (industry standard). No bespoke `_MOC.md` / `index.md` convention —
see [`CLAUDE.md` → Documentation Navigation](../CLAUDE.md).

A stale doc is worse than none — update it on task switch, or delete it.
