feat(server): let the operator select a playbook at session start - #84
Conversation
The new-investigation form gains an optional Playbook picker fed by GET /api/playbooks (locked launcher metas and disabled entries filtered out). When set, the id flows preflight → Investigation → metadata.json → sessions.Options → prompts.Env, and the opening prompt points the agent at that playbook instead of the profile's guided investigation flow, skipping the closing playbook as well. Preflight rejects unknown or disabled ids with 400. The session header shows the selected playbook, and it survives launcher restarts via persisted metadata. Signal-watch spawns are unchanged and keep the default flow. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Sh4mHX8JUzvrdpWg56iZth
There was a problem hiding this comment.
🟡 Changes recommended
Server-side preflight validation currently allows locked (system/meta) playbook ids to be explicitly selected, which can unintentionally bypass the intended guided/default flow semantics.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds an optional “start session on a specific playbook” entrypoint that bypasses the default guided investigation flow (and its closing capture_offer) when an operator explicitly selects a playbook at session start. This threads the chosen playbook id from the UI → preflight validation → investigation persistence/DTOs → session options → prompt construction, so sessions can reliably resume with the intended entrypoint.
Changes:
- Extend prompt generation to honor
Env.Playbookby setting onlysuggested-entrypoint-playbookand omitting the closing playbook guidance when a playbook is explicitly selected. - Carry
playbookthrough server preflight, investigation snapshot/restore (metadata.json), and session option → prompt env projection. - Add frontend playbook picker + catalog filtering/sorting utilities, with vitest coverage.
File summaries
| File | Description |
|---|---|
| prompts/prompts.go | Adds Env.Playbook and adjusts prompt output/tool guidance when set. |
| prompts/prompts_test.go | Adds tests for prompt shape with and without a selected playbook. |
| internal/sessions/session.go | Adds Options.Playbook and centralizes prompt env building via promptEnv(). |
| internal/sessions/session_test.go | Tests that Options.promptEnv() forwards the selected playbook (and cluster id). |
| internal/server/persist.go | Persists playbook in metadata.json and restores it on load. |
| internal/server/manager.go | Adds Playbook to investigation state, DTO, snapshot, and session start options. |
| internal/server/manager_test.go | Tests playbook round-trips via persisted metadata restore. |
| internal/server/handlers.go | Validates optional playbook on preflight and records it on the investigation. |
| internal/server/handlers_start_test.go | Adds preflight tests for accept/unknown/disabled/unset playbook behavior. |
| frontend/lib/playbook-select.ts | Filters/sorts playbooks for the picker (drops locked/disabled/broken). |
| frontend/lib/playbook-select.test.ts | Tests picker filtering and ordering. |
| frontend/lib/api.ts | Adds playbook to preflight request type and investigation DTO type. |
| frontend/components/investigations/SessionView.header.tsx | Displays selected playbook id in the session header when present. |
| frontend/components/investigations/InvestigationForm.tsx | Fetches playbook catalog, renders optional picker, submits selected id. |
| frontend/components/investigations/InvestigationForm.test.tsx | Adds tests for playbook picker visibility/filtering and submission behavior. |
| frontend/app/(main)/investigations/new/page.tsx | Forwards optional playbook field into api.preflight call. |
| docs/content/investigations.md | Documents the new optional playbook picker behavior. |
Review details
- Files reviewed: 17/17 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
The UI already hides launcher metas from the picker, but the server accepted them, so a crafted request could start a session on capture_offer or select investigation with the closing playbook suppressed. Enforce the same contract server-side. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Sh4mHX8JUzvrdpWg56iZth
There was a problem hiding this comment.
🟢 Approval recommended
The change is consistently plumbed end-to-end (UI → preflight validation → persistence → session/prompt) with targeted tests covering default and override behaviors.
Review details
- Files reviewed: 17/17 changed files
- Comments generated: 0 new
- Review effort level: Lite
…-select # Conflicts: # prompts/prompts.go # prompts/prompts_test.go
There was a problem hiding this comment.
🟢 Approval recommended
The end-to-end plumbing (UI → preflight validation → persistence → prompt behavior) is implemented coherently and is backed by targeted server/frontend/prompt tests, with only a minor comment/doc mismatch noted.
Review details
- Files reviewed: 17/17 changed files
- Comments generated: 1
- Review effort level: Lite
| // can't be walked. Investigation-typed playbooks sort first, then | ||
| // other types, each group by id. |
…-select # Conflicts: # internal/sessions/session.go # internal/sessions/session_test.go
There was a problem hiding this comment.
🟢 Approval recommended
The change is end-to-end (UI → API validation → persistence → prompt shaping) with targeted Go and frontend tests covering the new behavior and edge cases.
Review details
- Files reviewed: 17/17 changed files
- Comments generated: 0 new
- Review effort level: Lite
Description
Closes #83
Operators can now start a session against a specific playbook (a release-verification runbook, say) instead of the guided
investigationflow, which was the only entrypoint and dragged every non-triage session through routing andcapture_offer. The new-investigation form gains an optional Playbook picker; the chosen id flows preflight →Investigation→metadata.json→sessions.Options→prompts.Env, and the opening prompt points the agent at that playbook with no closing playbook. Sessions started this way skip wiki capture entirely; that's deliberate, since the closing offer only makes sense for investigations.Changes
GET /api/playbookswith locked launcher metas and disabled entries filtered out (frontend/lib/playbook-select.ts).POST /api/preflightacceptsplaybook, rejects unknown, disabled, or locked (launcher meta) ids with 400, and records it on the investigation;InvestigationDTOandmetadata.jsoncarryplaybookso it survives restarts.prompts.BuildhonoursEnv.Playbook: it becomessuggested-entrypoint-playbook,suggested-closing-playbookis omitted, and the strategies tool bullet tells the agent the operator chose it and there is no closing playbook.playbook: <id>for such sessions.Testing
TDD throughout:
promptstests for both prompt shapes; server tests for accept / unknown / disabled / locked / unset on preflight and ametadata.jsonround-trip; asessionstest thatOptions.promptEnv()forwards the id; vitest for the catalog filter and for the form submitting with and without a selection.make test,make lint, andcd frontend && npm run typecheckall pass. Worth poking at manually: start a session with a user playbook selected and confirm the agent's first call iswalk_playbookon that id and that nocapture_offerwalk followssummarize.🤖 Generated with Claude Code
https://claude.ai/code/session_01Sh4mHX8JUzvrdpWg56iZth