Skip to content

Plan: Launcher prompt-toggle system

URL: https://mkdocs.justinsforge.com/memory/plans/launcher-prompt-toggles-2026-07-04/

Date: 2026-07-04 Approved spec: Add a collapsed "Coding session" expander to the chat.justinsforge session launcher. Default view is unchanged (plain text box for questions/thoughts/reports). The expander reveals a Target radio (CreatorTrack / Forge / Other-or-new + free-text), a Scenario radio (Feature build / Bug fix / Integrator / Deploy / Explore-only), and Modifier checkboxes (Dev-server+URL, Plan-first, Push-when-done, Notify, Commit-often, Don't-touch-main, Register-tool, Typecheck-only, Run-tests, Write-handoff). The backend holds canonical block text in a single PROMPT_BLOCKS dict and prepends the selected blocks to the user's free text. Launcher injects text only (the spawned agent runs any scripts itself); the agent derives the branch slug from the task. Feature build = worktree+branch with NO dev server unless the Dev-server modifier is ticked. Unknown keys ignored (fail-safe); no selection = today's plain behavior. Out of scope: launcher does not execute agent_bootstrap.sh/deploy.sh; no CI/branch-protection setup; no change to spawn/model/warm-pool logic; no Vector-target changes.

Task list

Task 1: Backend PROMPT_BLOCKS dict + assembler

  • Files: /home/justinwieb/forge/scripts/forge_session_launcher_api.py
  • What: Add a module-level PROMPT_BLOCKS = {"targets": {...}, "scenarios": {...}, "modifiers": {...}} dict (text mirroring memory/general/reference_session_prompt_toggles.md, with the dev-server split and new modifiers) and a pure fn assemble_toggle_prompt(repo, scenario, modifiers, free_text, other_text) -> str that prepends selected blocks (target, then scenario, then modifiers, then free text). Unknown keys are skipped. Empty selection returns free_text unchanged.
  • Verification: python3 -c "import sys; sys.path.insert(0,'scripts'); import forge_session_launcher_api as a; print(a.assemble_toggle_prompt('creatortrack','feature',['devserver','notify'],'add a settings page','')[:200]); assert 'creatortrack' in a.assemble_toggle_prompt('creatortrack','feature',[],'x',''); assert a.assemble_toggle_prompt('','', [], 'just a question','')=='just a question'"
  • Commit: feat(launcher): PROMPT_BLOCKS dict + toggle prompt assembler

Task 2: Wire SpawnRequest fields + inject into spawn path

  • Files: /home/justinwieb/forge/scripts/forge_session_launcher_api.py
  • What: Add repo: str = "", scenario: str = "", modifiers: list[str] = [], repo_other: str = "" to SpawnRequest with a fail-safe validator (drop unknown modifier keys, cap list length). In _spawn_job, change line ~681 prompt = req.prompt to prompt = assemble_toggle_prompt(req.repo, req.scenario, req.modifiers, req.prompt, req.repo_other). Keep _name_from_prompt on req.prompt (raw user text) so session names stay clean.
  • Verification: python3 -c "import sys; sys.path.insert(0,'scripts'); import forge_session_launcher_api as a; r=a.SpawnRequest(prompt='fix the sidebar', repo='creatortrack', scenario='bugfix', modifiers=['notify','bogus']); assert 'creatortrack' in r.repo; assert 'bogus' not in r.modifiers; print('ok', r.modifiers)"
  • Commit: feat(launcher): SpawnRequest toggle fields + inject assembled prompt

Task 3: Frontend expander + toggle controls (markup + styles)

  • Files: /home/justinwieb/forge/sites/justinsforge.com/chat/index.html, /home/justinwieb/forge/sites/justinsforge.com/chat/launcher.css
  • What: Add a collapsed <details class="coding-toggles"> (summary "Coding session") below the prompt box containing: Target radio group (creatortrack/forge/other + a hidden-until-other text input #repo-other), Scenario radio group, Modifier checkbox group. Style to match the existing launcher (reuse tokens/classes). Collapsed by default so plain use is unchanged.
  • Verification: grep -c 'coding-toggles\|data-repo\|data-scenario\|data-modifier' /home/justinwieb/forge/sites/justinsforge.com/chat/index.html returns >0, and curl -fsS http://127.0.0.1:7365/ui/ | grep -c coding-toggles returns >0 after the service reload in Task 5 (pre-reload: load the file directly).
  • Commit: feat(launcher-ui): coding-session expander with target/scenario/modifier controls

Task 4: Frontend wiring into the spawn request

  • Files: /home/justinwieb/forge/sites/justinsforge.com/chat/launcher.js
  • What: On spawn, read the selected radio/checkbox values and include repo, repo_other, scenario, modifiers in the POST body to /api/sessions. Toggle the #repo-other input visibility when Target=other. No selection = fields empty = unchanged behavior.
  • Verification: grep -c 'scenario\|modifiers\|repo_other' /home/justinwieb/forge/sites/justinsforge.com/chat/launcher.js returns >0; visual: open /ui/, expand, pick toggles, spawn a throwaway session and confirm the injected prefix appears in the worker prompt.
  • Commit: feat(launcher-ui): send toggle selections in spawn request

Task 5: Reload, register, document

  • Files: /home/justinwieb/forge/memory/general/reference_session_prompt_toggles.md (align to final set: dev-server split, new modifiers, Other target, branch-naming note), /home/justinwieb/forge/memory/plans/launcher-prompt-toggles-2026-07-04.md
  • What: Update the reference doc to match the shipped blocks. Reload the launcher service so /ui/ serves the new widget. MEMORY.md index entry already exists. Run the eval harness.
  • Verification: sudo systemctl restart forge-session-launcher.service && sleep 3 && curl -fsS http://127.0.0.1:7365/ui/ | grep -c coding-toggles returns >0; bash /home/justinwieb/forge/scripts/forge_eval_run.sh runs clean (warnings ok).
  • Commit: docs(launcher): align prompt-toggles reference to shipped set