get-shit-done/references/workstream-flag.md
--ws)The --ws <name> flag scopes GSD operations to a specific workstream, enabling
parallel milestone work by multiple Claude Code instances on the same codebase.
--ws <name> flag (explicit, highest priority)GSD_WORKSTREAM environment variable (per-instance).planning/active-workstream file (legacy shared fallback when no session key exists)null — flat mode (no workstreams)The shared .planning/active-workstream file is fundamentally unsafe when multiple
Claude/Codex instances are active on the same repo at the same time. One session can
silently repoint another session's STATE.md, ROADMAP.md, and phase paths.
GSD now prefers a session-scoped pointer keyed by runtime/session identity
(GSD_SESSION_KEY, CODEX_THREAD_ID, CLAUDE_CODE_SSE_PORT, terminal session IDs,
or the controlling TTY). This keeps concurrent sessions isolated while preserving
legacy compatibility for runtimes that do not expose a stable session key.
When GSD resolves the session-scoped pointer in step 3 above, it uses this order:
GSD_SESSION_KEY, CODEX_THREAD_ID,
CLAUDE_SESSION_ID, CLAUDE_CODE_SSE_PORT, OPENCODE_SESSION_ID,
GEMINI_SESSION_ID, CURSOR_SESSION_ID, WINDSURF_SESSION_ID,
TERM_SESSION_ID, WT_SESSION, TMUX_PANE, and ZELLIJ_SESSION_NAMETTY or SSH_TTY if the shell/runtime already exposes the terminal pathtty probe, but only when stdin is interactiveIf none of those produce a stable identity, GSD does not keep probing. It falls
back directly to the legacy shared .planning/active-workstream file.
This matters in headless or stripped environments: when stdin is already
non-interactive, GSD intentionally skips shelling out to tty because that path
cannot discover a stable session identity and only adds avoidable failures on the
routing hot path.
Session-scoped pointers are intentionally lightweight and best-effort:
null
until the session explicitly sets a new active workstream againGSD does not currently run a background garbage collector for historical temp directories. Cleanup is opportunistic at the pointer being cleared or self-healed, and broader temp hygiene is left to OS temp cleanup or future maintenance work.
All workflow routing commands include ${GSD_WS} which:
--ws <name> when a workstream is activeThis ensures workstream scope chains automatically through the workflow:
new-milestone → discuss-phase → plan-phase → execute-phase → transition
.planning/
├── PROJECT.md # Shared
├── config.json # Shared
├── milestones/ # Shared
├── codebase/ # Shared
├── active-workstream # Legacy shared fallback only
└── workstreams/
├── feature-a/ # Workstream A
│ ├── STATE.md
│ ├── ROADMAP.md
│ ├── REQUIREMENTS.md
│ └── phases/
└── feature-b/ # Workstream B
├── STATE.md
├── ROADMAP.md
├── REQUIREMENTS.md
└── phases/
# All gsd-sdk query commands accept --ws
gsd-sdk query state.json --ws feature-a
gsd-sdk query find-phase 3 --ws feature-b
# Session-local switching without --ws on every command
GSD_SESSION_KEY=my-terminal-a gsd-sdk query workstream.set feature-a
GSD_SESSION_KEY=my-terminal-a gsd-sdk query state.json
GSD_SESSION_KEY=my-terminal-b gsd-sdk query workstream.set feature-b
GSD_SESSION_KEY=my-terminal-b gsd-sdk query state.json
# Workstream CRUD
gsd-sdk query workstream.create <name>
gsd-sdk query workstream.list
gsd-sdk query workstream.status <name>
gsd-sdk query workstream.complete <name>