# Send-to Menu Redesign + Settings Page Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Redesign the Send-to menu as a two-step bottom sheet with model selection, add a Settings page with saved instructions management and per-adapter preferences. **Architecture:** Three layers of changes: (1) Server — new `saved_instructions` DB table + API endpoints, (2) Client API — new instruction CRUD methods, (3) UI — rewritten ReviewActionMenu, new SettingsView with sub-pages, updated App routing and SessionsView header. **Tech Stack:** React + TypeScript + Vite (client), Express + SQLite + better-sqlite3 (server), Tailwind CSS (styling) **Spec:** `docs/superpowers/specs/2026-03-26-send-to-menu-settings-design.md` --- ## File Map | File | Action | Responsibility | |------|--------|---------------| | `server/db.ts` | Modify | Add `saved_instructions` table + prepared statements + `savedInstructions` operations | | `server/index.ts` | Modify | Add 3 instruction API endpoints | | `src/lib/api.ts` | Modify | Add instruction CRUD client methods | | `src/components/ReviewActionMenu.tsx` | Rewrite | Two-step bottom sheet with adapter/model/instructions | | `src/components/ChatView.tsx` | Modify | Simplify `handleReviewSelect` — no more context assembly | | `src/App.tsx` | Modify | Add `settings` view to routing | | `src/components/SessionsView.tsx` | Modify | Add settings icon in header | | `src/components/SettingsView.tsx` | Create | Main settings page with sections | | `src/components/SavedInstructionsView.tsx` | Create | Instruction list with add/delete | | `src/components/AdapterSettingsSection.tsx` | Create | Per-adapter model/permission/effort dropdowns | --- ## Task 1: Saved Instructions — Server DB + API **Files:** - Modify: `server/db.ts` - Modify: `server/index.ts` - [ ] **Step 1: Add `saved_instructions` table to DB** In `server/db.ts`, add to the `db.exec()` block (after `session_reviews` table): ```sql CREATE TABLE IF NOT EXISTS saved_instructions ( id TEXT PRIMARY KEY, label TEXT NOT NULL, instruction TEXT NOT NULL, created_at TEXT DEFAULT (datetime('now')) ); ``` - [ ] **Step 2: Add prepared statements** In the `PreparedStatements` interface, add: ```typescript instructionCreate: BetterSqlite3.Statement; instructionGetAll: BetterSqlite3.Statement; instructionDelete: BetterSqlite3.Statement; ``` In the `stmts()` function, add: ```typescript instructionCreate: d.prepare( `INSERT INTO saved_instructions (id, label, instruction) VALUES (?, ?, ?)` ), instructionGetAll: d.prepare( `SELECT * FROM saved_instructions ORDER BY created_at ASC` ), instructionDelete: d.prepare( `DELETE FROM saved_instructions WHERE id = ?` ), ``` - [ ] **Step 3: Add `savedInstructions` export object** After the `sessionReviews` export, add: ```typescript export const savedInstructions = { create(id: string, label: string, instruction: string): void { stmts().instructionCreate.run(id, label, instruction); }, getAll(): { id: string; label: string; instruction: string; created_at: string }[] { return stmts().instructionGetAll.all() as any[]; }, delete(id: string): void { stmts().instructionDelete.run(id); }, }; ``` - [ ] **Step 4: Add API endpoints in `server/index.ts`** Import `savedInstructions` from `./db.js`. Add 3 routes after the review routes: ```typescript // --- Saved Instructions API --- app.get('/api/instructions', authMiddleware, (_req: Request, res: Response) => { try { res.json(savedInstructions.getAll()); } catch (error) { res.status(500).json({ error: (error as Error).message }); } }); app.post('/api/instructions', authMiddleware, (req: Request, res: Response) => { try { const { label, instruction } = req.body; if (!label || !instruction) return res.status(400).json({ error: 'label and instruction required' }); const id = randomUUID(); savedInstructions.create(id, label, instruction); res.json({ id, label, instruction }); } catch (error) { res.status(500).json({ error: (error as Error).message }); } }); app.delete('/api/instructions/:id', authMiddleware, (req: Request, res: Response) => { try { savedInstructions.delete(req.params.id); res.json({ ok: true }); } catch (error) { res.status(500).json({ error: (error as Error).message }); } }); ``` Note: `randomUUID` is already imported in `server/index.ts`. - [ ] **Step 5: Verify TypeScript compiles** Run: `npx tsc --noEmit` Expected: No errors - [ ] **Step 6: Commit** ```bash git add server/db.ts server/index.ts git commit -m "feat: add saved_instructions DB table and API endpoints" ``` --- ## Task 2: Client API — Instruction Methods **Files:** - Modify: `src/lib/api.ts` - [ ] **Step 1: Add instruction API methods** Add to the `api` object, following the existing pattern (see `registerReview`, `endReview` for reference): ```typescript async getInstructions(): Promise<{ id: string; label: string; instruction: string; created_at: string }[]> { return request('/api/instructions'); }, async createInstruction(label: string, instruction: string): Promise<{ id: string; label: string; instruction: string }> { return request('/api/instructions', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ label, instruction }), }); }, async deleteInstruction(id: string): Promise { return request(`/api/instructions/${id}`, { method: 'DELETE' }); }, ``` - [ ] **Step 2: Verify TypeScript compiles** Run: `npx tsc --noEmit` - [ ] **Step 3: Commit** ```bash git add src/lib/api.ts git commit -m "feat: add instruction CRUD methods to client API" ``` --- ## Task 3: ReviewActionMenu — Two-Step Bottom Sheet **Files:** - Rewrite: `src/components/ReviewActionMenu.tsx` This is the core UI change. The component goes from a simple template picker to a two-step bottom sheet with adapter selection, model picker, and expandable instructions panel. - [ ] **Step 1: Rewrite ReviewActionMenu.tsx** New props interface: ```typescript interface ReviewActionMenuProps { visible: boolean; adapters: { id: string; displayName: string }[]; onDirectSend: (adapter: string, model: string) => void; onSendWithInstruction: (adapter: string, model: string, instruction: string, isCustom: boolean) => void; onClose: () => void; } ``` Component state: - `step`: `'adapter' | 'action'` — which step is shown - `selectedAdapter`: `string | null` — chosen adapter ID - `adapterConfig`: loaded from `api.adapterConfig(selectedAdapter)` when adapter is chosen - `selectedModel`: `string` — from adapterConfig.models, default to first item - `instructionsExpanded`: `boolean` — toggle for With Instructions section - `savedInstructions`: loaded from `api.getInstructions()` on mount - `customText`: `string` — free text input value **Step 1 UI** (adapter selection): - Backdrop overlay (click to close) - Bottom sheet with drag handle - "Send to…" title - Adapter rows: `` + adapter name, no model text, tap → set selectedAdapter + go to step 2 **Step 2 UI** (action selection): - `‹ {AdapterName}` header with colored adapter name (back arrow returns to step 1) - Model: `` dropdowns, each with a label: - "Model" → options from `config.models` (each has `value` + `label`) - "Permission Mode" → options from `config.permissionModes` - Effort label from `config.effortLabel` (e.g. "Thinking" for Claude, "Effort" for Codex) → options from `config.effortLevels` - On change: `patchAdapterPrefs(adapter, { [field]: value })` to persist to localStorage Import `loadAdapterPrefs`, `patchAdapterPrefs` from `@/lib/adapter-prefs`. Import `getBrand` from `@/lib/adapter-brands`. Import `AdapterIcon` from `./AdapterIcon`. - [ ] **Step 2: Verify TypeScript compiles** Run: `npx tsc --noEmit` - [ ] **Step 3: Commit** ```bash git add src/components/AdapterSettingsSection.tsx git commit -m "feat: create AdapterSettingsSection with per-adapter dropdowns" ``` --- ## Task 10: E2E Verification - [ ] **Step 1: Full TypeScript check** Run: `npx tsc --noEmit` Expected: No errors - [ ] **Step 2: Start server (without watch mode) and Vite** Start server and Vite in separate processes. Ensure tmux session exists first. - [ ] **Step 3: Visual verification in browser** Verify the following scenarios: 1. Settings icon visible in project list header 2. Settings page loads with all sections 3. Saved Instructions: add an instruction, verify it appears in list, delete it 4. Adapter settings: all dropdowns populate with correct adapter-specific options 5. In a chat, click send icon → two-step menu opens 6. Step 1 shows adapter icons + names (no model text) 7. Step 2 shows model dropdown + Direct Send + With Instructions 8. With Instructions has expand/collapse chevron 9. Direct Send sends only raw response text 10. With Instructions sends instruction + raw text 11. Save toast appears and works after custom instruction send - [ ] **Step 4: Final commit if any fixes needed**