---
phase: 22-bionic-reading-mode
plan: 02
type: execute
wave: 2
depends_on: ["22-01"]
files_modified:
  - ~/Library/Application Support/SwiftBar/Plugins/claude-hq.10s.sh
  - ~/Library/Application Support/SwiftBar/Plugins/nc-action.sh
autonomous: false
requirements:
  - BION-01

must_haves:
  truths:
    - "SwiftBar settings menu shows a Bionic Reading toggle item"
    - "Clicking the toggle sends POST /settings/subtitle with displayMode field"
    - "Toggle state reflects the current displayMode from GET /settings"
  artifacts:
    - path: "~/Library/Application Support/SwiftBar/Plugins/claude-hq.10s.sh"
      provides: "Bionic Reading menu item in SwiftBar"
      contains: "Bionic"
    - path: "~/Library/Application Support/SwiftBar/Plugins/nc-action.sh"
      provides: "displayMode toggle action handler"
      contains: "displayMode"
  key_links:
    - from: "claude-hq.10s.sh"
      to: "nc-action.sh"
      via: "act set-subtitle displayMode"
      pattern: "set-subtitle displayMode"
    - from: "nc-action.sh"
      to: "http://localhost:8780/settings/subtitle"
      via: "curl POST with displayMode JSON"
      pattern: "displayMode"
---

<objective>
Add Bionic Reading toggle to SwiftBar menu and nc-action.sh handler so users can toggle bionic mode from the menu bar.

Purpose: Users control bionic reading from the familiar SwiftBar control surface (BION-01, per D-04).
Output: SwiftBar shows Bionic Reading toggle that cycles displayMode between karaoke/bionic.
</objective>

<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/phases/22-bionic-reading-mode/22-01-SUMMARY.md

<interfaces>
<!-- From Plan 01: displayMode is now a string field in subtitle settings -->
<!-- GET /settings returns: { subtitle: { ..., displayMode: "karaoke"|"bionic"|"plain" } } -->
<!-- POST /settings/subtitle accepts: { displayMode: "bionic" } -->
</interfaces>
</context>

<tasks>

<task type="auto">
  <name>Task 1: SwiftBar plugin + nc-action.sh displayMode toggle</name>
  <files>
    ~/Library/Application Support/SwiftBar/Plugins/claude-hq.10s.sh
    ~/Library/Application Support/SwiftBar/Plugins/nc-action.sh
  </files>
  <read_first>
    ~/Library/Application Support/SwiftBar/Plugins/claude-hq.10s.sh
    ~/Library/Application Support/SwiftBar/Plugins/nc-action.sh
  </read_first>
  <action>
    1. Update claude-hq.10s.sh (per D-04):
       - In the settings parsing section (around line 34), add:
         `DISPLAY_MODE=$(echo "$SETTINGS" | $JQ '.subtitle.displayMode // "karaoke"')`
       - In the fallback defaults (around line 40), add: `DISPLAY_MODE="karaoke"`
       - In the Subtitle section (after the Karaoke toggle around line 100), add a Bionic Reading toggle:
         ```
         [ "$DISPLAY_MODE" = "bionic" ] && B_DOT="🟢" || B_DOT="🔴"
         echo "$B_DOT Bionic Reading | $(act set-subtitle displayMode toggle-bionic)"
         ```
       - Keep the existing Karaoke toggle as-is (it still controls karaokeEnabled). The displayMode toggle is a separate, more explicit control.

    2. Update nc-action.sh:
       - In the `set-subtitle` case, add handling for `displayMode` with `toggle-bionic` value:
         After the existing karaokeEnabled toggle block and before the string/number field block, add:
         ```bash
         elif [ "$VALUE" = "toggle-bionic" ] && [ "$FIELD" = "displayMode" ]; then
           # Toggle between karaoke and bionic display modes
           CUR=$(curl -sf --max-time 2 "$API_BASE/settings" | python3 -c "import json,sys; print(json.load(sys.stdin)['subtitle']['displayMode'])")
           NEW=$(python3 -c "print('karaoke' if '$CUR' == 'bionic' else 'bionic')")
           JSON=$(python3 -c "import json; print(json.dumps({'displayMode': '$NEW'}))")
           curl -sf --max-time 3 -X POST -H 'Content-Type: application/json' -d "$JSON" "$API_BASE/settings/subtitle" >/dev/null
           log_event "set-subtitle:$FIELD" "ok" "toggled:$CUR->$NEW"
         ```

    3. Build and verify the service is running, then test:
       - `curl -s http://localhost:8780/settings | python3 -c "import json,sys; d=json.load(sys.stdin); print('displayMode:', d['subtitle'].get('displayMode', 'MISSING'))"`

  </action>
  <verify>
    <automated>grep -q "Bionic" "$HOME/Library/Application Support/SwiftBar/Plugins/claude-hq.10s.sh" && grep -q "displayMode" "$HOME/Library/Application Support/SwiftBar/Plugins/nc-action.sh" && echo "PASS" || echo "FAIL"</automated>
  </verify>
  <acceptance_criteria>
    - grep -q "Bionic Reading" ~/Library/Application\ Support/SwiftBar/Plugins/claude-hq.10s.sh
    - grep -q "DISPLAY_MODE" ~/Library/Application\ Support/SwiftBar/Plugins/claude-hq.10s.sh
    - grep -q "toggle-bionic" ~/Library/Application\ Support/SwiftBar/Plugins/nc-action.sh
    - grep -q "displayMode" ~/Library/Application\ Support/SwiftBar/Plugins/nc-action.sh
  </acceptance_criteria>
  <done>SwiftBar menu shows Bionic Reading toggle with green/red dot. nc-action.sh toggles displayMode between karaoke and bionic via HTTP API.</done>
</task>

<task type="checkpoint:human-verify" gate="blocking">
  <name>Task 2: Visual verification of bionic reading mode</name>
  <files>none</files>
  <action>
    Human verifies the complete bionic reading feature visually. No code changes in this task.
    What was built: DisplayMode enum, BionicRenderer with 40% bold prefix, SettingsStore persistence, HTTP API endpoint, SubtitlePanel integration, and SwiftBar toggle.
    Steps to verify:
    1. Open SwiftBar menu -- verify "Bionic Reading" toggle appears in the Subtitle section
    2. Click "Bionic Reading" toggle -- dot should turn green
    3. Run: curl -X POST -H 'Content-Type: application/json' -d '{"text":"Welcome to the bionic reading mode demonstration"}' http://localhost:8780/subtitle/show
    4. Verify subtitle text shows with bold first ~40% of each word and regular-weight remainder
    5. Click "Bionic Reading" toggle again -- dot should turn red (back to karaoke mode)
    6. Run the same curl command -- verify subtitle now shows plain white text (karaoke mode, no TTS playing)
    7. Verify settings persist: curl -s http://localhost:8780/settings | python3 -m json.tool shows displayMode field
  </action>
  <verify>
    <automated>curl -sf http://localhost:8780/settings | python3 -c "import json,sys; d=json.load(sys.stdin); assert 'displayMode' in d['subtitle'], 'displayMode missing'; print('PASS: displayMode =', d['subtitle']['displayMode'])"</automated>
  </verify>
  <acceptance_criteria>
    - User confirms bionic rendering is visually correct
    - User confirms SwiftBar toggle works
  </acceptance_criteria>
  <done>User approved bionic reading mode visual appearance and SwiftBar toggle functionality.</done>
</task>

</tasks>

<verification>
1. SwiftBar menu shows Bionic Reading toggle with correct state indicator
2. Toggling bionic mode via SwiftBar sends correct HTTP API call
3. Subtitle text renders with bold prefix when bionic mode is enabled
4. Bionic and karaoke modes are mutually exclusive
</verification>

<success_criteria>

- SwiftBar settings menu has a "Bionic Reading" toggle item (BION-01)
- Toggle sends POST /settings/subtitle with displayMode field
- Visual confirmation that bionic rendering shows bold-prefix words
- Mode switching works correctly between karaoke and bionic
  </success_criteria>

<output>
After completion, create `.planning/phases/22-bionic-reading-mode/22-02-SUMMARY.md`
</output>
