PostHog / PostHog/wizard

Decompose the wizard store + session into composable, program-defined slices

Open
#768 1 comment 0 reactions 1 assignee View on GitHub

@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.ts404 lines, ~164 fields/members on the session interface.
  • src/ui/tui/store.ts944 lines, 29 explicit setters (each must remember to call emitChange()).
  • 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 an audit or revenue-analytics run 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 (so emitChange() is wired once, generically).
  • Migrate the obvious clusters first: mcp*, slack*, skill* → owned by the programs that use them.

Acceptance criteria

  • Core WizardSession no 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 test green; router/screen-resolution behavior unchanged.

Notes

  • Read .claude/skills/wizard-development/SKILL.md + references/ARCHITECTURE.md first — 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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.