# CLAUDE.md — Phase 12: Local LLM Conversational Layer

## Scope of This File

This file instructs you (Claude Code) to implement **Phase 12 only** of the Seedbox Command Center.

**Do not implement phases 13 through 15.** Stay in scope.

## Authoritative Specification

`PROJECT.md` §8.5 (Conversational Layer with Local LLM) and Appendix F (system prompt template) are authoritative. Read both. Also read:
- `PROGRESS.md` and `DECISIONS.md`.
- Every preceding `internal/intelligence/*` module — the LLM's tools surface those module outputs.

## Phase 12 Mission

A grounded conversational interface to the operator's data, backed by a local LLM running in Ollama. The operator asks questions like "what is hurting my ratio this week" or "which torrents should I delete to free 100 GB" and gets answers derived from structured tool calls against their actual database, not hallucinated from training.

After Phase 12, the operator can ask a question instead of clicking through five views to compose the answer manually. The Shortcuts integration lets them ask via Siri.

## Deliverables Checklist

Phase 12 is complete when every item below is true:

- [ ] SQLite migration `012_phase12_llm.sql` adds the `llm_conversations` and `llm_messages` tables per Appendix A.
- [ ] `internal/llm` provides:
    - Ollama HTTP client (configurable base URL via `llm.ollama_url`, default `http://127.0.0.1:11434`).
    - Tool-call orchestrator: the model emits tool calls, the orchestrator dispatches to registered tool functions, the result is passed back in the conversation loop until the model returns a final answer.
    - System prompt rendered from `config/llm-system-prompt.yaml` (operator-customizable) using the Appendix F template as default.
    - Conversation persistence in `llm_conversations` + `llm_messages`.
- [ ] Tool registry: each tool is a typed Go function exposed to the model with a JSON-Schema description. Phase 12 ships the tools mentioned in Appendix F:
    - `get_tracker_ratio(tracker_id, window)`
    - `get_torrent_summary(filters)`
    - `get_filter_performance(filter_id, window)`
    - `get_hr_risk()`
    - `get_recent_decisions(limit)`
    - `get_dead_swarms()`
    - `get_disk_forecast()`
    - `get_budget_state(budget_name)` (uses Phase 10)
    - `get_audit_log(filters)`
- [ ] Privacy guard: an optional remote inference adapter (OpenAI-compatible endpoint) routes through a redaction layer that strips identifiers (tracker names, torrent names beyond first 12 chars, info hashes) before sending. Default is local-only Ollama; remote is opt-in per conversation. Document the trade-off in the UI.
- [ ] API endpoints (auth required, under `/api/llm`):
    - `POST /api/llm/conversations` — start a new conversation.
    - `GET /api/llm/conversations` — list (paginated, pinned-first).
    - `GET /api/llm/conversations/:id` — full message history.
    - `POST /api/llm/conversations/:id/messages` — send a message; streams the response via SSE.
    - `DELETE /api/llm/conversations/:id` — soft-delete (audit-logged).
    - `PATCH /api/llm/conversations/:id` — pin/unpin, rename.
- [ ] iOS Shortcuts endpoints:
    - `GET /api/shortcuts/ratio/:tracker_id` — returns ratio + recent trend in one JSON.
    - `GET /api/shortcuts/torrents/count` — count by state.
    - `GET /api/shortcuts/disk-usage` — current usage + forecast.
    - `GET /api/shortcuts/recent-activity` — last N notable events.
    - `POST /api/shortcuts/ask` — fire-and-forget LLM query; returns a short answer suitable for Siri speech.
    - Documentation: a Shortcut template (.shortcut file) the operator imports into iOS Shortcuts that calls these endpoints with their session cookie.
- [ ] Frontend:
    - `/chat` route: ChatGPT-style conversation UI with streaming responses.
    - Pinned conversations sidebar.
    - Tool calls render inline ("I queried the tracker stats and found...") with the tool's name and a collapsible "show inputs/output" disclosure.
    - "Remote inference" toggle per conversation with the privacy implications shown clearly.
- [ ] Tests: tool dispatcher correctly routes synthetic tool calls; redaction layer strips identifiers on the remote path; Ollama client handles streaming responses and errors.
- [ ] `PROGRESS.md` and `DECISIONS.md` updated. `DECISIONS.md` records: chosen model defaults (e.g., `llama3.1:8b`), context window strategy (truncate? summarize? Phase 12: truncate with a notice), tool-call timeout (default 30s per tool), error semantics (model retries on transient tool failure, gives up after 3).

## Phase 12 Database Scope

Migration `012_phase12_llm.sql` creates:
- `llm_conversations`
- `llm_messages`

## Repository Layout

```
internal/
  llm/
    ollama.go                # client
    orchestrator.go          # tool-call loop
    tools/
      registry.go
      get_tracker_ratio.go
      get_torrent_summary.go
      get_filter_performance.go
      get_hr_risk.go
      get_recent_decisions.go
      get_dead_swarms.go
      get_disk_forecast.go
      get_budget_state.go
      get_audit_log.go
      *_test.go
    redaction/
      remote_guard.go        # strip identifiers before remote inference
      *_test.go
    persistence.go           # conversation + messages CRUD
    *_test.go
config/
  llm-system-prompt.yaml     # operator-customizable template
scripts/
  Command Center.shortcut    # iOS Shortcut template
```

Files added under existing packages:
- `internal/server/routes_llm.go`
- `internal/server/routes_shortcuts.go`

Frontend additions:
- `web/src/pages/Chat.tsx`
- `web/src/components/ConversationView.tsx`
- `web/src/components/ToolCallInline.tsx`
- `web/src/lib/sse-llm.ts` — streaming response handler.

## Working Rules

**Local-first is the default.** Remote inference exists but is opt-in per conversation. The default model is whatever Ollama has pulled; the operator configures the model id in `config/system.yaml`.

**Tools are typed.** Every tool's input and output schema is declared in Go. The model receives JSON schemas; results pass back in the same shape. Do not let the model produce free-form text where structured data is expected.

**Grounded answers only.** The system prompt instructs the model to use tools rather than recall. If the model claims something not supported by a tool call, log it as a `model_unsupported_claim` event for the operator's review (rare; mostly a debugging aid).

**Read-only.** Phase 12 tools are read-only. The model cannot pause, delete, or change anything. If a user asks for an action, the model explains the action and points to the UI control that performs it.

**Streaming responses.** The chat UI shows the response token-by-token. SSE carries the stream.

**Redaction on remote path.** When the operator opts into remote inference, the redaction layer strips identifying tokens (tracker names, info hashes, torrent names beyond their first 12 chars) before forwarding. Document exactly what's stripped and what's preserved.

**Tool timeouts.** A tool that exceeds its budget (default 30s) is canceled and the orchestrator returns a structured error to the model. The model is instructed to retry once with simpler params, then give up gracefully.

## What "Phase 12 Complete" Looks Like

After Phase 12 ships, the operator can:

1. Install Ollama on the host, pull a model (`ollama pull llama3.1:8b`), confirm Ollama is reachable on `127.0.0.1:11434`.
2. Open `/chat`. Ask "what is hurting my ratio this week?" — watch the model call `get_tracker_ratio` and `get_filter_performance`, then produce an answer grounded in actual data: "Tracker B's ratio dropped 0.12 in the last 4 days. Filter F contributed 80% of grabs but only 8% of upload. Consider tightening F or pausing it."
3. Pin the conversation. It persists across restarts.
4. Install the bundled iOS Shortcut. Say "Hey Siri, ask Command Center what's hurting my ratio." Hear a short spoken answer.
5. Toggle "Remote inference" on a conversation; ask a question; observe via logs that identifying tokens were redacted before the outbound request.
6. The chat UI never claims an action ("I've deleted those torrents") — answers always end with a pointer to the UI control that would perform the action.

## Begin

Read `PROJECT.md §8.5` and Appendix F. Start with the Ollama client and a single tool (`get_tracker_ratio`) to validate the orchestrator loop end-to-end. Then add tools one at a time. Persistence and UI last. Stop at the end of Phase 12.
