# persian tasks

Priority order set in agent's outbox.md 2026-06-22 (post-bootstrap assessment).

## Active

- [ ] **Auth** — TBD with Cameron. Mirror notes-page `X-Notes-Auth` header in `serve.py` for free-rider protection.

## Roadmap (priority order)

- [ ] **Vocab + SRS**: `db.py` with SQLite `vocab(id, persian, transliteration, english, first_seen, last_reviewed, ease, due)`. "Save to vocab" button, SM-2 daily quiz.
- [ ] **Glasses integration** — coordinate with glasses agent. Voice in (Whisper) → POST `/persian/api/ask` → response on HUD + audio in earbud. Reuse glasses' chat/feed pattern.
- [ ] **Proactive mode** — context-triggered ("getting coffee" → quick Persian phrase). Hook into life_manager daily log / glasses NOW-task captures / `events.json`.
- [ ] **Khanega integration** — producer now exists: `sufi_lectures` agent (forked from life_manager 2026-07-06) downloads lectures, runs Persian Whisper ASR, and writes transcripts to `/data/cameron/life/projects/khanega/transcripts/`. It pings `agents/persian/inbox.md` per batch (path + rough count of SRS-worthy phrases); I consume into the vocab layer at my own pace. **Depends on the Vocab + SRS layer existing first** (see above) — that's the real blocker now, not the transcripts. To request specific lectures (e.g. "anything on taarof?"), ping `agents/sufi_lectures/inbox.md`. Boundary: I don't touch `agents/sufi_lectures/*` or `/data/cameron/life/projects/khanega/*`; it doesn't touch mine.

## Done

- [x] 2026-06-22 — Bootstrap pass: read full scaffold, exercised live app
- [x] 2026-06-22 — Fixed cached-audio 404 bug on public site (`app.py:77` cache-hit path was missing `/persian` prefix)
- [x] 2026-06-23 — **Persistence**: app moved to dedicated `srv_persian` tmux window (mirrors `srv_omidlab`), launched via `bash run.sh 2>&1 | tee app.log` with `debug=False`. `run.sh` fixed to use the venv python + `exec`. (Reboot-survival via systemd still deferred — manager confirmed tmux is the call for now.)
- [x] 2026-06-23 — **Chat persistence across refreshes**: transcript + Claude context stored in `localStorage` (`chat.js`), replayed on load; "Clear" button in header; context sent to Claude capped to last ~30 turns to bound token cost.
- [x] 2026-06-23 — **Voice upgrade done**: Cameron upgraded to ElevenLabs Starter; swapped `ELEVENLABS_VOICE_ID` to Nazy Entezari (`WwAjIyMBDBNl1dvId9Xe`), cleared George cache (10 mp3s), restarted. Verified Nazy synthesizes (was 402 on free tier) + serves publicly.
- [x] 2026-06-23 — **Lessons mode (v1)**: 11 curated conversational lessons (132 phrases), transliteration-first, casual register. Clickable library → lesson detail (phrases + sample dialogue + per-phrase on-demand audio + ask-a-question box that reuses the tutor with lesson context). New files: `lessons/specs.json`, `lessons.py`, `gen_lessons.py`, `templates/lessons.html`, `static/lessons.js`; new routes `/persian/lessons`, `/api/lessons`, `/api/lessons/<id>`, `/api/tts`.

## Known issues / debt

- Swallowed audio errors in `api_ask` (catches all into `audio_error`, returns 200). Deliberate UX call — text answer survives TTS hiccup — but flags against fleet "fail loud" guidance
- **Lessons UI duplicates a small answer-renderer** from `chat.js` (structured/markdown render + escapeHtml). Acceptable for v1; factor a shared `static/render.js` when touching either next (per fleet no-copy-paste rule).
- Occasional model typo in generated lesson content (e.g. `ghaaabel` for `ghaabel` in taarof). Easy fix: hand-edit the JSON or `gen_lessons.py taarof --force`.
- No vocab DB / SRS yet; lesson phrases are a natural seed for it.
