Task: Arrange the .pm board
/pm is the only skill that writes to .pm/. It arranges milestones and tasks under the conventions below. /pm-brainstorm proposes; /pm materializes. This file is the canonical definition of the board conventions — hierarchy, sizing rule, quality gate, standing closing tasks, templates. /pm-brainstorm reads it at runtime and must not restate or diverge from it. Parse the subcommand from $ARGUMENTS (default = status).
The .pm hierarchy
| Level | Path | Meaning | Effort |
|---|---|---|---|
| Workstream | wN/ (w1, w2, w3, …) |
a general-purpose worker queue; README.md + inbox notes |
— |
| Inbox note | wN/NNN.md (w1/005.md) |
one idea or a sub-hour unit of work, plain markdown | ≤ ~1h |
| Milestone | wN/mN/ (m1, m2, …) |
a shippable chunk: README.md + task files |
> ~1h, multiple tasks |
| Task | wN/mN/tNNN.md |
a single unit | tens of minutes |
Rules (enforce every time)
Respect the anti-goals. Read
.pm/DO_NOT_DO.mdbefore proposing or materializing work. Do not create milestones/tasks that conflict with it.Workers are general-purpose. Every
wNmay take work anywhere in the bex project. Workstream placement records scheduling and history, not a permanent mission, specialty, component boundary, or ownership claim. Do not assign themes or missions to workstreams, and do not use prior milestones to reject otherwise appropriate work.Sizing rule. A milestone must be > ~1 hour of work across more than one task. If a chunk is ≤ ~1h (tens of minutes, a task or two), do NOT create an
mN/directory — record it as a loose inbox notewN/NNN.md. Tasks take tens of minutes; milestones take hours.IDs must match the path. A task's
id: wN/mN/tNNNfrontmatter must equal the directory it lives in. Never create a milestone dir whose path disagrees with the IDs inside it (the existingw2/m1-holds-w1/m1-IDs drift is the anti-example — if you touch it, flag/repair, don't copy it).Keep status in sync across all three places it lives: the workstream
README.mdmilestone checkbox, the milestoneREADME.md**Status:**line + the— DONEmarker in the task table, and each task'sstatus:frontmatter.Numbering: next free zero-padded 3-digit for inbox notes (
NNN) and tasks (tNNN); next freewN/mN. Scan the tree first; don't reuse a number.Use
worker: worker1unless the workstream README names another worker.Milestones must be meaningful. Every milestone must include direct project-goal linkage, an observable expected outcome, and why this work matters now (dependency/risk/sequence rationale).
Every board item briefly explains why. Milestones carry it in the milestone
README.md(## Source + Goal linkage). Single tasks — inbox noteswN/NNN.md— carry it in the note itself: a one-lineWhy: …directly under the title (a sentence on the motivation/payoff is enough).Every milestone ends with standing closing tasks, appended after the implementation tasks whenever a milestone is materialized:
- Render parity — only when the milestone is feature development or a fix that touches a user/tenant-facing surface. Check that the change is consistent across every surface it exposes: REST, GraphQL, and MCP in
lego/backend/(same fields, semantics, error shapes — bex-api is meant to be Render-compatible, seedocs/ADR006-bex-api.md) and thedashboard/UI (dashboard/CLAUDE.md). Compare against the equivalent render.com behavior/API and flag any drift as follow-up work rather than silently diverging. Omit this task only for milestones with no REST/GraphQL/MCP/UI surface change (pure infra, operator-internal mechanism, docs, etc.) — note why it was omitted in the milestone's## Source + Goal linkage. - Simplify — run
/simplifyover the code this milestone changed (reuse / simplification / efficiency; behavior-preserving). - Test coverage — add meaningful tests for the behavior this milestone shipped. Tests must assert real behavior and failure modes; never game coverage with trivial, tautological, or snapshot-everything tests.
- Closeout — the final task, added last. When the milestone's other tasks are all complete and its definition of done is actually met, close the milestone: set every remaining task's
status: done, move eachtNNN.mdtowN/mN/done/, mark every row— **DONE**and set**Status:** donein the milestoneREADME.md, move the wholewN/mN/directory towN/done/mN/, and check- [x]in the workstreamREADME.md. Completing this task is the move — running/pm done <wN/mN/tNNN>on it last triggers the milestone move (thedonesubcommand's step 4). Do not run it until the DoD holds: a milestone lands indone/when its observable end state is real, not merely when the code is written.
Each
depends_onthe last implementation task(s) (Simplify and Test coverage depend on Render parity when it's present; Closeout depends on Test coverage) and all count toward the(N tasks)total.add-taskinserts new work before these (before Closeout) and updates theirdepends_on.- Render parity — only when the milestone is feature development or a fix that touches a user/tenant-facing surface. Check that the change is consistent across every surface it exposes: REST, GraphQL, and MCP in
After editing any
.md, runnpx prettier@3.4.2 --write "**/*.md"(repo rule).
Subcommands
status (default)
Read the tree (find .pm -type f -name '*.md', skipping done/) and .pm/DO_NOT_DO.md. Print, per open workstream: its milestones with **Status:**, and the next actionable task per milestone — the first non-done task whose depends_on are all satisfied. Also list open inbox notes. Then run a lightweight validation pass and flag:
- items conflicting with
.pm/DO_NOT_DO.md, - milestones missing
## Source + Goal linkage, - milestones whose definition of done is vague/non-testable,
- inbox notes missing a
Why:line.
Touch no files.
new workstream
Create the next free wN/ with a role-neutral README.md from the workstream template below.
add <wN> <idea…>
Create the next free inbox note wN/NNN.md with the idea as plain terse markdown (no frontmatter), with a one-line Why: … directly under the title. This is the default home for sub-hour work.
promote <wN/NNN> / new milestone <wN> <title>
Apply the sizing rule first.
- If the work is > ~1h and splits into more than one task: create
wN/mN/withREADME.md(milestone template) + onetNNN.mdper task (task template) + the standing closing tasks (Render parity when it's feature dev/a fix touching REST/GraphQL/MCP/UI, then Simplify, then Test coverage, then Closeout), add the- [ ] **mN** — …line to the workstreamREADME.md, and fill## Source + Goal linkagewith source + goal linkage + expected outcome + why-now rationale (note there why Render parity was included or omitted). - If it is ≤ ~1h: do NOT create a milestone. Keep/append it as an inbox note
wN/NNN.md(with its one-lineWhy: …) and tell the user why (too small for a milestone).
add-task <wN/mN> <title>
Create the next tNNN.md from the task template and add its row to the milestone README.md table before the standing closing tasks, updating their depends_on to include it. Update the (N tasks) count in the workstream README.
done <wN/mN/tNNN>
- Set the task's frontmatter
status: done. - In the milestone
README.md: mark the row— **DONE**and update the**Status:**line (e.g.todo (t001 done)). - Move the file to
wN/mN/done/tNNN.md. - If no open tasks remain in the milestone, move the whole milestone to
wN/done/mN/and check its box (- [x]) in the workstreamREADME.md.
Show the intended moves before mutating if the user passed DRY_RUN=1.
Templates
Workstream README.md
# wN — project workstream (<worker>)
**Worker:** <worker>. This is a general-purpose bex workstream. It may take work anywhere in the project; the milestones below are scheduled work and historical records, not a permanent purpose, specialty, or ownership boundary.
## Milestones
- [ ] **mN** — <title> (<N> tasks) ← from <source>
Milestone README.md
# wN · mN — <name>
**Worker:** <worker> **Goal:** <what shipping this achieves> **Status:** todo
## Tasks (in order)
| id | title | est | depends_on |
| ---- | ------- | --- | ---------- |
| t001 | <title> | 30m | — |
## Definition of done
<observable, testable end state>
## Source + Goal linkage
- **Source:** <pointer to the inbox note / brainstorm / docs this came from>
- **Goal linkage:** <which project goal / pillar this advances>
- **Expected outcome:** <observable impact after shipping>
- **Why now:** <dependency / risk / sequence rationale>
Task tNNN.md
---
id: wN/mN/tNNN
title: <title>
worker: <worker>
status: todo
estimate: 30m
depends_on: [wN/mN/tMMM]
---
## Objective
<one paragraph>
## Context
- <concrete paths / k8s resources / facts>
## Steps
1. <step>
## Files
- <paths to touch>
## Acceptance criteria
- [ ] <testable check>
## Out of scope
- <deferred adjacent work>
Inbox note wN/NNN.md
Plain terse markdown, no frontmatter — one idea or a sub-hour unit of work. Opens with, directly under the title:
Why: <one sentence — motivation / payoff>
Arguments
$ARGUMENTS