TASKS: VoiceTask
Work strictly in order unless a task's Depends line allows otherwise. One task at a time. Run the Verify commands before checking a task off. All tests run with MOCK_PROVIDERS=1 (vitest config sets it globally).
T1 Scaffold
- npm package with
server/,client/(Vite React TS template),shared/. Scripts:dev(server + Vite concurrently),build,typecheck(tsc --noEmit over all three),test(vitest run). Add zod, fastify + plugins, @anthropic-ai/sdk, vitest. One placeholder test that asserts true. - Depends: nothing
- Verify:
npm run typecheckandnpm testandnpm run buildall exit 0.
- npm package with
T2 Shared types and session store
- Implement
shared/types + zod schemas from PLAN.md. Implementserver/store/sessionStore.ts: create, get, list, append segment, update coverage/summary/status, persisted todata/sessions/<id>/session.jsonatomically (write temp file, rename). - Depends: T1
- Verify:
npm test(store unit tests: create/reload roundtrip, sequential segment ids S1..Sn, list).
- Implement
T3 Provider interfaces, factory, mocks
server/providers/types.ts,factory.ts,sttMock.ts,llmMock.tsexactly as specified in PLAN.md (including the echo-text behavior of sttMock and the deterministic interview script and bad-marker SPEC.md of llmMock).- Depends: T2
- Verify:
npm test(mock behavior tests: echo, turn script reaches done, factory returns mocks under MOCK_PROVIDERS=1).
T4 Session and answer routes
POST /api/sessions,GET /api/sessions,GET /api/sessions/:id,POST /api/sessions/:id/answerwired to store + interview engine stub that calls the InterviewLlm provider. "done" detection per SPEC (exact match, case-insensitive, trimmed).- Depends: T3
- Verify:
npm test(route tests via fastify.inject: create, answer produces interviewer segment + coverage update, done ends session).
T5 Interview engine
server/engine/: coverage state handling, prompt construction (summary + last 40 segments), summary maintenance, contradiction passthrough from the LLM response, weakest-category question selection enforced in the prompt. Anthropic implementationllmAnthropic.tsper PLAN.md (compiles and is unit-tested for prompt construction only; no network in tests).- Depends: T4
- Verify:
npm test(engine tests with llmMock: coverage progresses in category order, >40 segments triggers summary path, contradiction from mock is surfaced).
T6 Audio route and OpenAI STT
@fastify/multipartupload routePOST /api/sessions/:id/audio,sttOpenai.tsper PLAN.md, empty-transcript rejection, provider errors mapped to 502 with{error}.- Depends: T4
- Verify:
npm test(audio route with sttMock: uploaded text buffer becomes a segment and triggers a turn; empty buffer returns 4xx and stores nothing).
T7 Client: interview UI
- Session list/create screen, interview screen with Transcript, QuestionCard, CoveragePanel, text input, Done button. Typed api.ts wrappers. Vite dev proxy to the server.
- Depends: T4 (T5 makes it meaningful, but the API contract is enough to build against)
- Verify:
npm run typecheckandnpm run buildexit 0. Manual:npm run devwith MOCK_PROVIDERS=1, typing answers advances coverage in the panel.
T8 Client: push-to-talk and TTS
- MediaRecorder hold-to-record button (spacebar and mouse), upload to the audio route, recording state indicator. TTS toggle speaking each new interviewer question via speechSynthesis.
- Depends: T6, T7
- Verify:
npm run typecheckandnpm run buildexit 0. Manual: recording in Chrome produces a segment (mock mode).
T9 Spec pack generator
server/generator/: five per-file prompts, generation orchestration through the InterviewLlm provider,sources.jsonemission, provenance validation per FR-013, existing-file refusal +overwriteflag + backup tospec/backup-<timestamp>/on regenerate.- Depends: T5
- Verify:
npm test(with llmMock into a temp dir: all six files written; bogus[S999]marker removed and[unverified]appended; second run without overwrite fails; with overwrite creates backup dir).
T10 Generate route and UI
POST /api/sessions/:id/generate, GeneratePanel with missing-category confirmation dialog per FR-008, result/warnings display.- Depends: T7, T9
- Verify:
npm test(route test) andnpm run typecheck.
T11 Blocker import
server/blockers/parse.tsfor the BLOCKED.md format defined in the repo rootBLOCKED.mdtemplate,POST /api/sessions/:id/blockers, engine mode that asks only imported questions, UI entry point. Missing/empty file handled per SPEC edge case.- Depends: T5, T7
- Verify:
npm test(parser tests incl. empty file; route test: import then next turn asks a blocker question).
T12 End-to-end smoke test
- Single vitest test: boot the server with mocks, create session (temp target dir), answer until done via the answer route, generate, assert all six files exist, all remaining
[S<n>]markers resolve against sources.json, and HANDOFF.md contains the stringclaude. - Depends: T9, T10
- Verify:
npm testruns it green; thennpm run typecheck,npm test,npm run buildall exit 0 as the final full check.
- Single vitest test: boot the server with mocks, create session (temp target dir), answer until done via the answer route, generate, assert all six files exist, all remaining
T13 Non-technical onboarding pass
client/src/labels.tsmaps eachCategoryIdto a plain-language label and one-line explanation used byCoveragePanel. Rewrite session-list and interview-screen copy (headings, empty states, button text) to not assume the reader is a developer. UpdatebuildInterviewSystemPromptinllmAnthropic.tsto instruct plain-language, jargon-free questions per updated SPEC FR-006.- Depends: T7
- Verify:
npm run typecheckandnpm run buildexit 0. Manual: every category in CoveragePanel shows a plain-language label, not aCategoryId.
T14 Folder browser
server/routes/fs.ts:GET /api/fs/browse(defaults to the OS home directory, lists subdirectories, returns{path, parent, directories}),POST /api/fs/mkdir(creates one subdirectory). Shared zod schemas for both.client/src/components/FolderBrowser.tsx: modal that navigates the tree, creates a folder, and returns the chosen path to the session-create form; the raw text input stays available alongside it.- Depends: T7
- Verify:
npm test(route tests: browse lists directories and a parent, browsing an unreadable path returns a 4xx, mkdir creates a directory and 4xxs on a duplicate name) andnpm run typecheck. Manual: browsing, creating a folder, and selecting it fills the target directory field.
T15 Export: spec pack zip and transcript
shared/transcript.ts:formatTranscript(segments)plain-text renderer.server/exporter/zip.ts: dependency-free ZIP (STORE method) writer.GET /api/sessions/:id/export/spec-pack.zip(404 with a clear error ifspec/doesn't exist yet in the target directory) andGET /api/sessions/:id/export/transcript.md. Client: a transcript "Copy" / "Download" control usable at any time, and a "Download spec pack (.zip)" button inGeneratePanelthat appears once a pack exists.- Depends: T9, T10
- Verify:
npm test(zip writer roundtrips through Node's own unzip via a temp-file check or a byte-level structural check; export route: 404 before generate, 200 with correctContent-Type/Content-Dispositionafter) andnpm run typecheck. Manual: after generating, the zip downloads and contains all six files; transcript copy/download works mid-interview.
T16 Cross-platform offline demo and verification
- Add
npm run demo, with an explicit server flag that forces mock providers after.envis loaded. Replace test calls to the externalunzipcommand with dependency-free byte-level ZIP checks so the full suite passes on Windows, macOS, and Linux. - Depends: T15
- Verify:
npm run typecheck,npm test, andnpm run buildexit 0. Manual: with a real-provider.envpresent,npm run demoreports mock providers and opens no provider connection.
- Add
T17 Mainstream first-run explanation
- Redesign the home screen around a direct outcome statement, the three-part flow, local privacy, and a representative source-backed requirement. Make folder browsing the obvious path, add plain helper copy to both fields, and keep earlier sessions easy to resume. Implement the visual system and responsive layout in PLAN.md without a UI dependency.
- Depends: T16
- Verify:
npm run typecheckandnpm run buildexit 0. Static audit: every first-run claim maps to an existing requirement and all interactive controls have visible keyboard focus.
T18 Easier interview controls and progress
- Change the microphone to click once to record and click again to send, while keeping Space as hold-to-talk outside controls. Add explicit idle, recording, sending, and error copy. Replace the coverage count and color-only dots with plain progress language and per-category status labels.
- Depends: T17
- Verify:
npm run typecheckandnpm run buildexit 0. Manual: mouse click toggles one recording, Space still records only while held, and coverage statuses are understandable without color.
T19 Clear completion and user-driven sharing
- Add a HEAD readiness check for the existing spec-pack export. Redesign the completed state around the primary zip download, recipient guidance, a copyable project handoff message, and a secondary generated-file disclosure. Add a separate optional VoiceTask recommendation action using the canonical repository link. Clipboard failures must be visible.
- Depends: T18
- Verify:
npm test,npm run typecheck, andnpm run buildexit 0. Tests cover the readiness check plus deterministic handoff and recommendation copy. Manual: refresh a completed session with an existing pack and confirm the download remains visible.
T20 Mainstream documentation and final product check
- Rewrite README.md for a first-time evaluator: outcome, audience, what the pack contains, one-command offline demo, real-provider setup, privacy, and the send-to-someone flow. Update VERIFICATION.md to use cross-platform commands and run the complete product gate.
- Depends: T19
- Verify:
npm run checkexits 0 andgit diff --checkreports no errors.
T21 Language-correct speech and keyboard access
- Distinguish audio sending from typed-answer waiting in microphone copy. Select speech voices by browser locale and default status instead of hardcoding English. Announce new questions, expose focus on the read-aloud switch, and contain and restore focus in the folder dialog.
- Depends: T20
- Verify:
npm test,npm run typecheck, andnpm run buildexit 0. Voice-selection tests cover locale match, default fallback, and an empty voice list.
T22 In-app provider setup
- Start the server without keys instead of exiting. Add
GET /api/configandPOST /api/config(server/routes/config.ts,server/config/runtimeConfig.ts): report the provider mode and key hints, save the offline demo or one or both keys into the local.envwithout losing the rest of that file, and apply them to the running process. Resolve providers per request so a saved key works without a restart. A server started withnpm run demostores keys but stays on mocks and reports that a restart is needed. Accept writes only from the local app origin. Addclient/src/components/ProviderSetup.tsx, show it in place of the create form until a mode is chosen, and show the current mode in the home header. Turn a missing key into a plain-language 503 instead of a generic server error. - Depends: T21
- Verify:
npm test,npm run typecheck, andnpm run buildexit 0. Tests cover the .env merge, demo-locked saving, key hints that never contain the key, the missing-key error, and origin rejection. Manual: with no.env,npm run devstarts, the browser asks for setup, and saving keys starts an interview without restarting the server.
- Start the server without keys instead of exiting. Add