Skip to content

Work Units (WUs)

A Work Unit (WU) is a small, well-defined piece of work with clear acceptance criteria and proof of completion.

Traditional tickets are:

  • Vague (“Fix the login bug”)
  • Unbounded (no clear definition of done)
  • Trust-based (marked done without proof)

WUs are:

  • Specific (“Add email validation to login form”)
  • Bounded (completable in a single session, <50 tool calls)
  • Evidence-based (tests and artifacts prove completion)
id: WU-0042
title: Add email validation to login form
lane: 'Experience: UI'
type: feature
status: ready
priority: P2
exposure: ui

description: |
  Add client-side email validation before form submission.
  Show inline error message for invalid formats.

acceptance:
  - Email field validates on blur
  - Invalid emails show "Please enter a valid email"
  - Valid emails allow form submission
  - Unit test covers validation logic

test_paths:
  unit:
    - src/components/__tests__/login-form.test.ts
  e2e:
    - e2e/login.spec.ts

code_paths:
  - src/components/LoginForm.tsx
  - src/utils/validation.ts

Every Work Unit has a canonical id made of a configurable prefix and a zero-padded integer. Defaults preserve backward compatibility — every existing LumenFlow repo keeps emitting WU- prefixed ids without any config change.

A canonical id is <prefix><zero-padded-integer> where:

  • prefix matches /^[A-Z][A-Z0-9]{1,9}-$/ (default 'WU-').
  • the integer body is at least width characters wide (default 4).
  • the integer body may be wider than width once the sequence overflows (e.g. WU-10000 is canonical even when width=4); the sequence never truncates.

wu:create canonicalizes --id input before any file is written — passing --id WU-14 writes WU-0014.yaml. Auto-generated ids are zero-padded too.

Two different string forms of the same integer cannot coexist: WU-14 and WU-0014 resolve to the same canonical integer and wu:create hard-errors if the integer is already represented anywhere on disk. The error ships with a copy-pasteable wu:rename remediation command.

Canonical ID behaviour is controlled by software_delivery.wu_id.* in workspace.yaml:

software_delivery:
  wu_id:
    width: 4 # 1-6; default 4 → WU-0001
    strict: true # enforce canonical format at creation; lumenflow:doctor --deep flags drift
    prefix: 'WU-' # pattern /^[A-Z][A-Z0-9]{1,9}-$/; try TASK-, STORY-, TICKET-, …
# Fresh repo, no config changes — auto-generated ids are WU-0001, WU-0002, …
pnpm wu:create --lane "Experience: UI" --title "Add login form"
# ↳ WU-0001

# --id input is canonicalized before any file is written:
pnpm wu:create --id WU-14 --title "…"
# ↳ writes WU-0014.yaml with id: WU-0014

Teams that prefer a non-WU- prefix can pick a different one without touching any WU source file:

pnpm config:set --key software_delivery.wu_id.prefix --value TASK-
pnpm wu:create --lane "Experience: UI" --title "Add login form"
# ↳ TASK-0001

pnpm wu:create --id TASK-14 --title "…"
# ↳ writes TASK-0014.yaml with id: TASK-0014

pnpm lumenflow:doctor --deep flags any WU YAML whose id is valid but not canonical (e.g. WU-5.yaml when width=4). Offenders come with copy-pasteable repair commands:

pnpm wu:rename --from WU-5 --to WU-0005

wu:rename moves the YAML, rewrites the id: field, moves the .done stamp, appends a wu_renamed event to .lumenflow/state/wu-events.jsonl, and regenerates backlog.md and status.md. When a downstream repo has already canonicalized its YAML out-of-band but the generated views still regenerate with legacy ids, use --replay-only to append the event without touching the filesystem:

pnpm wu:rename --from WU-5 --to WU-0005 --replay-only

Either form is append-only — history is never rewritten. Historical events retain their original wuId; a replay-time projection resolves them to the new canonical id so generated views only show the post-rename form.

  • strict: true (default) — lumenflow:doctor --deep treats drift as exit code 1, wu:rename’s CLI guard refuses a non-canonical --to.
  • strict: false — legacy unpadded ids are tolerated (warning-only). Use this as a migration ramp for repos that cannot normalize in one go; integer-level collision detection still hard-blocks same-integer duplicates.
ready → in_progress → [blocked] → done
StatusMeaning
readyApproved, can be claimed
in_progressSomeone is working on it
blockedWaiting on external dependency
doneAcceptance met, stamp created

wu:create --type accepts seven canonical WU types:

TypeUse it for
featureNet-new user or system capability
bugBroken or regressed behavior fix
documentationDocumentation-only change
processWorkflow or operating-process maintenance
toolingTooling, automation, or developer-experience work
choreRepository upkeep or housekeeping
refactorBehavior-preserving code restructure

Two rules matter in practice:

  • feature WUs require spec_refs. A plan link or spec reference is part of the contract, not an optional note.
  • documentation and process are the non-code WU types. Use them when the work truly changes docs or operating workflow without touching runtime behavior.

WUs should be completable in a single session (<50 tool calls, <30% context). If bigger, split them.

❌ “Implement user authentication system”

✅ “Add login form UI” ✅ “Add password validation” ✅ “Connect login to auth API” ✅ “Add session persistence”

See Sizing Guide for detailed heuristics.

In LumenFlow:

TraditionalLumenFlow
Create ticket → Code → Open PR → Review → MergeCreate WU → Claim → Code in worktree → Gates → Done

The “review” is automated gates, not human PR review. This unblocks flow while maintaining quality.

LumenFlow provides two levels of completion evidence:

Every tool call during a WU’s execution is recorded in the evidence store:

  • Content-addressed inputs — Tool inputs are hashed with SHA-256 and stored as immutable blobs
  • Tool tracesTOOL_CALL_STARTED and TOOL_CALL_FINISHED entries with timing, scope enforcement results, and policy decisions
  • Denial records — Even denied tool calls produce evidence, proving what the agent attempted

At completion, wu:done creates:

  1. Stamp file in .lumenflow/stamps/WU-XXX.done
  2. Test results proving acceptance criteria
  3. Git history linking to the WU spec

This audit trail answers: What was the agent asked to do? Was the action authorized? What actually happened? See Evidence Store for the full model.

# With required flags
pnpm wu:create \
  --title "Add password strength meter" \
  --lane "Experience: UI" \
  --type feature \
  --exposure ui \
  --description "Show password strength indicator during registration" \
  --acceptance "Strength meter shows weak/medium/strong" \
  --acceptance "Meter updates in real-time as user types" \
  --code-paths "src/components/PasswordStrength.tsx" \
  --test-paths-unit "src/components/__tests__/password-strength.test.ts" \
  --plan

The command prints the generated ID. The created WU goes into docs/operations/tasks/wu/WU-XXX.yaml with status ready.

Plan-less conversations: If your plan lives in chat or a meeting, keep it lightweight: use --plan to generate a stub at lumenflow://plans/WU-XXX-plan.md, summarize the plan there, and reference it in spec_refs. Feature WUs require spec_refs; notes do not replace the plan link.

  • Lanes — Organizing work streams with scope boundaries
  • Gates — Quality enforcement as kernel policies
  • Evidence Store — The immutable audit trail behind every WU
  • Kernel Runtime — How WU tasks map to kernel task lifecycle
  • Sizing Guide — How to size WUs properly