Decompose the wizard store + session into composable, program-defined slices
@gewenyu99 is already working on this.
Since Jun 30, 2026.
- Dominant language
- TypeScript
- Stars
- 197
- Forks
- 51
- Avg merge
- 1d 23h
- Merged PRs (30d)
- 94
Description
Problem
The global WizardSession and the TUI store have become a catch-all. Every program's state lives flat on one shared object, so the core keeps growing and infrastructure code carries product knowledge it shouldn't.
Today:
src/lib/wizard-session.ts— 404 lines, ~164 fields/members on the session interface.src/ui/tui/store.ts— 944 lines, 29 explicit setters (each must remember to callemitChange()).- Program-specific state is flat on the shared session regardless of which program is running, e.g.
mcpComplete/mcpOutcome/mcpInstalledClients/mcpSuggestedPromptsDismissed,slackStepDismissed/slackConnected,skillsComplete/skillId, … These exist on the session for anauditorrevenue-analyticsrun that never touches MCP or Slack.
This violates the repo's own design discipline (AGENTS.md: product knowledge never enters infrastructure code). The store/session are machinery, but they currently know about MCP, Slack, skills, etc. Adding a program means widening the shared session and adding setters to the shared store — the bloat compounds.
Goal
Make the store and session composable and driven by program definitions (src/lib/programs/), so:
- The core session holds only program-agnostic state (install dir, credentials, detected framework, run phase, current screen).
- Each program contributes its own typed state slice (e.g.
mcp,slack,skills) declared alongside its program definition, mounted only when that program runs. - The store composes setters/selectors from the active program's slices instead of hardcoding all 29.
- Screens read/write their program's slice, not a flat global.
Sketch (not prescriptive)
- A program definition declares an optional
state: { initial, setters }slice with a typed shape. buildSession()composes core + the active program's slices; the store derives its setter surface from them (soemitChange()is wired once, generically).- Migrate the obvious clusters first:
mcp*,slack*,skill*→ owned by the programs that use them.
Acceptance criteria
- Core
WizardSessionno longer references program-specific concepts (MCP/Slack/skills/etc.). - At least the MCP, Slack, and skills state are program-owned slices, mounted only for programs that declare them.
- Store setter/selector surface is composed from active slices, not a flat hardcoded list;
emitChange()stays centralized. - Adding a new program needs no edits to the core session/store — only its own definition + slice.
-
pnpm build && pnpm testgreen; router/screen-resolution behavior unchanged.
Notes
- Read
.claude/skills/wizard-development/SKILL.md+references/ARCHITECTURE.mdfirst — this is a structural change to the pipeline's core. - Keep the nanostore single-shallow-copy + explicit-setter invariant; the change is about where slices are defined and composed, not how mutation/emit works.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.