---
phase: 08-http-control-api
plan: 02
type: execute
wave: 2
depends_on: [08-01]
files_modified:
  - plugins/claude-tts-companion/Sources/claude-tts-companion/main.swift
autonomous: true
requirements: [API-01, API-02, API-03, API-04, API-05, API-06]

must_haves:
  truths:
    - "HTTP server starts on port 8780 when binary launches"
    - "curl localhost:8780/health returns JSON with status ok"
    - "curl POST localhost:8780/subtitle/show displays text on screen"
    - "HTTP server shuts down cleanly on SIGTERM"
  artifacts:
    - path: "plugins/claude-tts-companion/Sources/claude-tts-companion/main.swift"
      provides: "HTTPControlServer wiring with lifecycle management"
      contains: "HTTPControlServer"
  key_links:
    - from: "main.swift"
      to: "HTTPControlServer.swift"
      via: "creates and starts server instance"
      pattern: "HTTPControlServer\\("
    - from: "main.swift"
      to: "SettingsStore.swift"
      via: "creates shared settings store"
      pattern: "SettingsStore\\("
---

<objective>
Wire HTTPControlServer into main.swift lifecycle and verify the complete API works end-to-end with curl.

Purpose: Make the HTTP API active when the binary runs, completing the Phase 8 integration.
Output: Updated main.swift with HTTP server startup/shutdown, verified via swift build.
</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/08-http-control-api/08-01-SUMMARY.md

@plugins/claude-tts-companion/Sources/claude-tts-companion/main.swift
@plugins/claude-tts-companion/Sources/claude-tts-companion/HTTPControlServer.swift
@plugins/claude-tts-companion/Sources/claude-tts-companion/SettingsStore.swift

<interfaces>
<!-- From Plan 01 outputs -->

From SettingsStore.swift:

```swift
final class SettingsStore: @unchecked Sendable {
    func getSettings() -> AppSettings
    func updateSubtitle(_ update: (inout SubtitleSettings) -> Void)
    func updateTTS(_ update: (inout TTSSettings) -> Void)
}
```

From HTTPControlServer.swift:

```swift
final class HTTPControlServer: @unchecked Sendable {
    init(settingsStore: SettingsStore, subtitlePanel: SubtitlePanel, ttsEngine: TTSEngine)
    func start() async throws
}
```

From Config.swift:

```swift
static let httpPort: UInt16 = 8780
```

</interfaces>
</context>

<tasks>

<task type="auto">
  <name>Task 1: Wire HTTPControlServer into main.swift with lifecycle management</name>
  <files>plugins/claude-tts-companion/Sources/claude-tts-companion/main.swift</files>
  <read_first>
    - plugins/claude-tts-companion/Sources/claude-tts-companion/main.swift
    - plugins/claude-tts-companion/Sources/claude-tts-companion/HTTPControlServer.swift
    - plugins/claude-tts-companion/Sources/claude-tts-companion/SettingsStore.swift
  </read_first>
  <action>
Edit main.swift to add HTTP server startup. Insert the following changes in order:

1. **After the `let ttsEngine = TTSEngine()` line**, create the settings store:

```swift
// Create settings store (persists to ~/.config/claude-tts-companion/settings.json)
let settingsStore = SettingsStore()
```

1. **After settingsStore creation**, create and start the HTTP control server:

```swift
// Create HTTP control API server
let httpServer = HTTPControlServer(
    settingsStore: settingsStore,
    subtitlePanel: subtitlePanel,
    ttsEngine: ttsEngine
)

// Start HTTP server in background task
Task {
    do {
        logger.info("Starting HTTP control API on port \(Config.httpPort)")
        try await httpServer.start()
    } catch {
        logger.warning("HTTP server failed to start: \(error) -- continuing without HTTP API")
    }
}
```

1. **Add keepAlive reference** to prevent ARC deallocation. Add near the other `nonisolated(unsafe) var keep*` lines:

```swift
nonisolated(unsafe) var keepHTTPServer: HTTPControlServer? = httpServer
nonisolated(unsafe) var keepSettingsStore: SettingsStore? = settingsStore
```

1. **In the SIGTERM handler**, the HTTP server does not need explicit stop -- FlyingFox cancels when the Task is cancelled or the process exits. No changes needed to the SIGTERM block.

Do NOT change any existing functionality. The HTTP server is additive -- it starts in a background Task and the binary continues to work exactly as before even if the server fails to bind.
</action>
<verify>
<automated>cd plugins/claude-tts-companion && swift build 2>&1 | tail -10</automated>
</verify>
<acceptance_criteria>swift build succeeds. main.swift creates SettingsStore, HTTPControlServer, starts server in background Task, and holds strong references to prevent ARC deallocation.</acceptance_criteria>
<done>Binary compiles with HTTP server wired in. Server starts on port 8780 at launch. Graceful fallback if port is busy (warning log, no crash).</done>
</task>

<task type="auto">
  <name>Task 2: Build verification and endpoint smoke test</name>
  <files>plugins/claude-tts-companion/Sources/claude-tts-companion/main.swift</files>
  <read_first>
    - plugins/claude-tts-companion/Sources/claude-tts-companion/main.swift
    - plugins/claude-tts-companion/Sources/claude-tts-companion/HTTPControlServer.swift
  </read_first>
  <action>
Run release build to verify everything compiles clean:
```bash
cd plugins/claude-tts-companion && swift build -c release 2>&1
```

Verify binary size is still reasonable (should be under 30MB per BUILD-04):

```bash
ls -lh .build/release/claude-tts-companion
```

Verify the new files exist and have expected content:

```bash
grep -c "HTTPControlServer" Sources/claude-tts-companion/main.swift
grep -c "SettingsStore" Sources/claude-tts-companion/main.swift
grep -c "/health" Sources/claude-tts-companion/HTTPControlServer.swift
grep -c "/settings" Sources/claude-tts-companion/HTTPControlServer.swift
grep -c "/subtitle" Sources/claude-tts-companion/HTTPControlServer.swift
```

This is a build-only verification task. No runtime curl tests because the binary requires sherpa-onnx model files and Telegram tokens to start. The HTTP server integration is validated by successful compilation with all type checks passing.
</action>
<verify>
<automated>cd plugins/claude-tts-companion && swift build -c release 2>&1 | tail -3</automated>
</verify>
<acceptance_criteria>Release build succeeds with zero errors. Binary exists at .build/release/claude-tts-companion. All endpoint route strings present in HTTPControlServer.swift.</acceptance_criteria>
<done>Phase 8 complete: release build succeeds, HTTPControlServer has 6 endpoints, SettingsStore persists to disk, main.swift wires everything together.</done>
</task>

</tasks>

<verification>
- `swift build -c release` succeeds
- HTTPControlServer.swift contains all 6 endpoint routes
- SettingsStore.swift contains disk persistence logic
- main.swift creates and starts the HTTP server
</verification>

<success_criteria>
Binary compiles with FlyingFox HTTP server integrated. All 6 API endpoints are routed. Settings persist to disk via JSON file. Server starts automatically on binary launch at port 8780.
</success_criteria>

<output>
After completion, create `.planning/phases/08-http-control-api/08-02-SUMMARY.md`
</output>
