Files
msd-core/docs/how-to/work-in-parallel-with-workstreams.md
Tom Boucher fd07e1a357 fix(#2850): resolve the active workstream in the statusline GSD-state segment (#3012)
* test(#2850): add failing-first tests for workstream statusline state

readGsdState only ever reads the flat .planning/STATE.md via a directory
walk-up; it has no path for .planning/workstreams/<ws>/STATE.md and never
consults GSD_WORKSTREAM or the stored active-workstream pointer, so the
GSD-state segment silently disappears in workstream mode. These tests
prove the RED before the fix lands.

Uses shared saveSessionEnv/restoreSessionEnv/clearSessionEnv helpers now
added to tests/helpers.cjs (single source of truth for the session-env-var
save/clear/restore pattern also used by tests/active-workstream-store.unit.test.cjs,
which is updated here to consume the same shared helpers instead of its own
local, already-diverged copy).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(#2850): resolve active workstream in the statusline

readGsdState only ever walked up looking for a flat .planning/STATE.md; it
had no branch for .planning/workstreams/<ws>/STATE.md and never consulted
GSD_WORKSTREAM or the stored active-workstream pointer, so the GSD-state
segment silently vanished in workstream-mode projects with no root
STATE.md (exit 0, no diagnostic).

Reuses the existing CLI>env>store resolution seam (resolveActiveWorkstream,
active-workstream-store.cts) and the existing mode-detection/path-building
seam (listAvailableWorkstreams/planningPaths, planning-workspace.cts)
rather than re-implementing either inline. When workstream mode is
detected but nothing resolves, readGsdState now returns a
{noActiveWorkstream:true} sentinel that formatGsdState/formatGsdStateCompact
render as "no active workstream" -- observable, never silent emptiness.
Flat-mode behavior and the case where a resolved workstream has no
STATE.md yet are both unchanged.

Adds active-workstream-store.cts's peekActiveWorkstream: a read-only
sibling of getActiveWorkstream. resolveActiveWorkstream's default store
lookup self-heals a stale/invalid pointer by deleting it
(adapter.clear()) -- correct for a command, but not for a renderer
invoked once per prompt, which must never mutate persistent, possibly
cross-session state as a side effect of drawing a screen. The statusline
now injects peekActiveWorkstream via resolveActiveWorkstream's own
getStored override, keeping the env>store precedence itself fully reused
while removing only the store tier's write side effect. This satisfies
the issue's AC4 ("the fix is purely additive to what's displayed").

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* chore(#2850): backfill changeset PR number to 3012

---------

Co-authored-by: sim <sim@local>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 21:44:04 -04:00

5.3 KiB

How to work on multiple areas in parallel with workstreams

Goal: Run concurrent work on different milestone areas — backend API, frontend dashboard, infrastructure, or any other concern — without planning state from one area bleeding into another.

Prerequisites: An active GSD Core project (.planning/ROADMAP.md exists). If not, run /gsd-new-project first.


What workstreams are

A workstream is an isolated planning context within a single codebase. Each workstream gets its own .planning/workstreams/<name>/ subtree containing independent STATE.md, ROADMAP.md, REQUIREMENTS.md, and phases/ directories. The codebase itself — source code, git history, and branches — is shared across all workstreams.

.planning/
├── PROJECT.md          ← shared
├── config.json         ← shared
├── codebase/           ← shared
└── workstreams/
    ├── backend-api/
    │   ├── STATE.md
    │   ├── ROADMAP.md
    │   ├── REQUIREMENTS.md
    │   └── phases/
    └── frontend-dash/
        ├── STATE.md
        ├── ROADMAP.md
        ├── REQUIREMENTS.md
        └── phases/

When a workstream is active, every GSD command — /gsd-progress, /gsd-discuss-phase, /gsd-plan-phase, /gsd-execute-phase — reads from and writes to that workstream's directory. Switching workstreams redirects all of those commands to a different subtree without touching the source tree.


Create a workstream

/gsd-workstreams create backend-api

GSD creates the workstream directory under .planning/workstreams/backend-api/ and seeds it with a skeleton STATE.md and ROADMAP.md. The workstream is not automatically activated — you switch to it explicitly.


List workstreams

/gsd-workstreams list

Shows all workstreams and which one is currently active in your session.


Switch to a workstream

/gsd-workstreams switch backend-api

From this point forward, all GSD workflow commands operate in the backend-api context. The switch is session-scoped: when multiple Claude Code terminals are open on the same repo, each session can hold a different active workstream without interfering with the others.

The statusline's GSD-state segment (milestone, phase, progress) reflects whichever workstream resolves as active — the same GSD_WORKSTREAM env var / stored pointer precedence every workstream-aware command uses. If no workstream can be resolved in a workstream-mode project, the segment shows no active workstream rather than disappearing silently.

Once switched, drive the normal phase workflow:

/gsd-discuss-phase 1
/gsd-plan-phase 1
/gsd-execute-phase 1
/gsd-verify-work 1

To work on another area, switch workstreams in a second terminal:

/gsd-workstreams switch frontend-dash
/gsd-discuss-phase 1
/gsd-plan-phase 1

Check progress across all workstreams

/gsd-workstreams progress

Prints a cross-workstream summary — phase status, current position, and outstanding work for every workstream — without requiring you to switch between them.

For detailed status on a single workstream:

/gsd-workstreams status backend-api

Resume work in a workstream

After a context reset or a new session, restore your position:

/gsd-workstreams resume backend-api

This activates the workstream and restores your last known position within it, equivalent to switching and then running /gsd-resume-work.


Archive a completed workstream

When a workstream's milestone work is done:

/gsd-workstreams complete backend-api

GSD marks the workstream as archived and moves it out of the active listing. The planning artifacts are preserved under .planning/workstreams/backend-api/ for audit purposes.


Scope a single command to a workstream without switching

If you need to run one command against a specific workstream without changing your session's active context, use the --ws flag:

/gsd-progress --ws frontend-dash
/gsd-plan-phase 2 --ws backend-api

--ws takes highest priority in the resolution order and does not alter the session-scoped pointer.


When to use workstreams instead of workspaces

Choose workstreams when:

  • All the work lives in the same repository and shares the same git history
  • You want to plan or discuss different concern areas (API, UI, infra) concurrently without one workstream's STATE.md overwriting another's
  • You do not need a separate branch per workstream at creation time (though you can branch as normal within each workstream's execution)
  • The overhead of creating full git worktrees is not justified by the isolation you need

Choose workspaces instead when:

  • You are working across multiple repositories (e.g., hr-ui and ZeymoAPI)
  • You need the isolation of a separate git worktree or clone per feature — fully independent branches, lock files, and build artefacts
  • You want to run /gsd-new-project independently in each workspace with a wholly separate .planning/ root, not a subdirectory of the main repo's .planning/