Voice-first learning companion (single user, local-first). The full spec and phase plan is in CLAUDE.md; deviations are logged in DECISIONS.md.
Watch the 81 second demo with voiceover:
recall-demo.mp4
(the app running on the built-in test model, so Aria's replies are canned; the music is synthesised by
docs/demo/make_music.py).
| Phase | State |
|---|---|
| 0 Skeleton | done |
| 1 Capture to notes | done (fakes verified; real voice/LLM keys untested) |
| 2 Diagrams and memory map | done (verified with fakes) |
| 2.5 Hosted backend + installable PWA | built; tested locally, not yet on a real VM or iOS device |
| 3 Recall engine | done (verified with fakes only) |
| 4 Ingestion and n8n | done (fake LLM; real extraction quality unmeasured) |
| 5 Daily brief and stats | done (verified with fakes) |
| 6 More tracks, articulation scoring | done (fakes only; realtime provider not built) |
Run one always-on copy on a cloud VM and open it from every device: see DEPLOY.md.
make dev # copies .env.example to .env if missing, then docker compose up --build| Service | URL |
|---|---|
| Frontend | http://localhost:3000 |
| Backend / OpenAPI docs | http://localhost:8000/docs |
| n8n | http://localhost:5678 |
| Postgres | 127.0.0.1:5433 |
make install # uv sync + npm install
make migrate # alembic upgrade head (needs the db container running)
make test # backend pytest (needs db) + frontend vitest
make lint # ruff, mypy, eslint, tsc
make gen-api # regenerate frontend/lib/api-types.ts from FastAPI's OpenAPI schema
make e2e # Playwright smoke test (needs `make dev` and `npx playwright install chromium`)make dev, wait for the backend log lineApplication startup complete.curl localhost:8000/healthzreturns{"status":"ok","db":"up","voice_provider":"fake"}.- Open http://localhost:3000, confirm the header says Connected, type a message, press Enter.
- You see your message and the fake assistant's reply in the transcript.
- Confirm it is stored: open the session id shown top-right at
http://localhost:8000/api/sessions/<session id>; both utterances are listed.
Everything works typed with the fakes. For real speech and note extraction, set these in .env
and restart (docker compose up -d --build backend):
VOICE_PROVIDER=pipeline
ELEVENLABS_API_KEY=... # speech-to-text (Scribe) and the voice
STT_PROVIDER=elevenlabs # default; "deepgram" also needs DEEPGRAM_API_KEY
ELEVENLABS_VOICE_ID=...
LLM_PROVIDER=anthropic
ANTHROPIC_API_KEY=... # LLM_FAST_MODEL / LLM_DEEP_MODEL are preset in .env.example
EMBEDDING_PROVIDER=voyage
EMBEDDING_API_KEY=...Then on http://localhost:3000/session use Open mic (use headphones) or hold Hold to talk. The Debug panel shows speech end to first audio for each turn; the target is under 800 ms.
make dev, open http://localhost:3000/session.- Type:
RAG retrieves relevant documents before generation. Chunk size trades recall against precision.Two atomic notes appear on the right, marked New note. - Type
RAG retrieves relevant documents before generation.again. No duplicate: the note shows Merged into existing note with a Show previous toggle. - Click Undo on either to revert it. Reload the page: remaining notes persist.
- On http://localhost:3000/session type
RAG retrieves relevant documents using embeddings. The model then answers from those documents.Each new note gets a diagram in the right-hand pane (click a note to switch). - Type another note that shares wording with an earlier one. A dashed amber related (unconfirmed) link appears under both notes.
- Open Memory map. Notes are nodes, the unconfirmed link is a dashed amber edge. Click a node for its note, diagram and links, then Confirm (edge turns solid) or Remove. Grey nodes have no review history yet; strength colours and the red fragile marker arrive with Phase 3.
- On /session capture two or three ideas ("Reranking reorders retrieved chunks by relevance before generation. Chunk overlap keeps context across boundaries."). Each note gets a cloze and a question.
- Quiz me (or say it) asks what is due. Answer wrongly or press I forgot to climb the ladder: nudge, partial, then the answer with an explanation and a diagram. The grade follows how much help you needed. Doing a full reveal twice in a row marks the note fragile and brings it back within a day.
- Type
explain reranking: you get a short spoken explanation, a diagram and Save as note. Then typeI don't get it: the note is marked fragile and explained again in simpler words. - Type
read me my notes on reranking; use next, repeat, slower, faster, stop. - On Memory map, notes you have reviewed take a red to green strength colour, fragile ones get a red border, and Quiz me on this practises that one note.
- Open Sources, paste a link (or text), press Add source. It moves through fetching, chunking and
extracting, then shows
Filed N notes under AI Engineering, linked M.Each note is dashed (From source, unconfirmed) with its citation: the verbatim quote and chunk. - Undo any item, then Approve all. Approved notes count and are quizzed.
- Add the same link again (even with
?utm_source=...): it is recognised, not added twice. - By voice: say
what did you file?, thenyesto approve ornoto remove it all.
make dev # starts n8n at http://localhost:5678 too
make n8n-import # loads the three workflows and activates them| Workflow | What it does |
|---|---|
ingest-url |
POST /webhook/ingest-url with {"url": "...", "track": "ai-eng"} and header X-Recall-Secret |
ingest-inbox |
watches n8n/inbox/: drop a PDF, or a .txt/.md file with links |
sync-export |
nightly, writes every note as Markdown into n8n/exports/ |
curl -X POST http://localhost:5678/webhook/ingest-url \
-H "Content-Type: application/json" -H "X-Recall-Secret: $RECALL_SHARED_SECRET" \
-d '{"url": "https://example.com/some-article"}'make n8n-import # also loads daily-brief-cron and review-nudge
curl -X POST localhost:8000/api/sessions/daily-brief -H "X-Recall-Secret: $RECALL_SHARED_SECRET"- Open any page: Your brief is ready. Press Start brief. You hear a greeting, then one question on each of your three weakest notes (hint ladder as usual), then "N reviews are due today".
- Stats shows due today, streak, 7 and 30 day retention, the retention curve (hover it, or open the table), and your weakest notes with a Quiz me link each.
- Set
USER_TIMEZONEin.env(e.g.Asia/Kolkata) so "today" and the 07:30 / 18:00 schedules are yours. - Evening nudge: set
NUDGE_URLto an ntfy topic URL andNUDGE_THRESHOLD; only the count of waiting reviews is sent.
Use the Track menu in the top bar; the choice is remembered on this device.
| Track | Try saying | What differs |
|---|---|---|
dsa |
"Two pointers walks a left and a right pointer inward over a sorted array to find a pair." | Pattern/complexity notes; the diagram is a step-by-step walkthrough (Back/Next, arrow keys) |
solutions |
"The problem is slow search. I tried a linear scan, then an index. The tradeoff is write cost. I chose the index." | Notes follow Problem / Approach / Tradeoff / Decision |
english |
Start a teach-back (below) | Waits longer before cutting you off; teach-back is the focus |
Teach-back (any track): in Teach-back type a topic (or leave it empty for a suggestion) and press Start, or say "let me teach it back". Explain it, then press I'm done or say "I'm done". You get pace, fillers per 100 words, long pauses, sentence length, the what/how/why/impact checklist, clarity, one thing done well, one thing to fix, and one weak sentence rewritten. Stats charts the trend. With the mic on (real speech-to-text) pace and pauses are measured; typed text shows "–" for pace.
On the Session page (or say these out loud; they also work with the mic):
| Say | What happens |
|---|---|
| "Create a new notes file for binary search under dsa" | Moves to the dsa track, makes the notebook, and files everything you say next into it |
| "Create notes files for binary and hashmap under dsa" | Makes both; opens the first. "Open hashmap notes" switches |
| "Create new notes for system design where we discuss and solve the question" | Starts a discussion in the solutions track: it asks the problem, then evaluates what you propose, suggests alternatives and asks the next question. "Wrap up" saves an evaluation note and an architecture diagram |
| "Let's discuss designing a URL shortener" | Same, with the problem named |
| Recite a design aloud, then "draw the architecture" | One overview diagram of the whole open notebook |
| "Start reciting my binary search notes" | Reads each note, explains it, then asks a question about it before moving on. "Stop" ends it |
| Upload a PDF (Session page) | It is read and filed into a notebook named after it; the assistant summarises. Say "recite" to keep the notes and hear them explained |
| "Stop" or "end the session" | Says goodbye and closes the mic |
The Notebooks page lists each notebook's notes, with Add notes, Recite, rename and delete.
The assistant is Aria. Ask her "what can you do?", "who are you?" or "what's in my notes?" and she answers from what she can actually do and what is in your notebooks right now. Start a command with her name if you like ("Aria, open my hash map notes"). When a new notes file appears (from an upload or another device) she mentions it and offers to recite it.
- "Under dsa put binary search as the topic" makes the notebook; add "and create notes on that" (or say "write the notes") and Aria also writes 4 to 7 starter notes, marked as hers until you confirm them. Repeat for hash maps, two pointers, and so on.
- "Write notes on hash maps" does the same in the current track. "Create a notes file for X" only makes the empty notebook.
Say "evaluate me on binary search" (or tick "Also check it against my notes or PDF" in Teach-back). Explain it out loud and say "I'm done". Aria checks what you said against your own notes, and the PDF if the notebook came from one: what you covered, what you didn't mention, and anything that conflicts.
