Build Hedy
KINDAreplaces $12.99/mosaves $155.88/yrback to the verdict
A local study companion whose hard problems are producing an end-of-session artefact that actually aids retention rather than one that feels productive, keeping a live panel quiet enough not to cost more attention than it returns, and decoding audio without inventing sentences over silence.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Runs the capture loop, the decoder and the server.
Get it python.org or your package manager. open ↗
Verify
python3 --version prints 3.12 or higher - installfree, after the download
Why Everything else in this build assumes the audio never leaves the machine, and a hosted transcription service would make that untrue.
Get it Install the runtime and download a small English model on first run.
Verify
A one minute recording transcribes faster than real time on your machine - installfree
Why Without one you capture only your own microphone, which is half a conversation and makes the transcript useless for a call.
Get it A virtual audio device for your platform, installed and selected as an input.
Verify
It appears in the device list and a played recording produces segments - API keypay per call; the rate cap keeps it small
Why The panel and the question generation are model calls, and they are the only networked part.
Get it Create a key with your preferred provider and set a spend limit in their console.
Verify
Ending a test session produces questions that cite real segments - decidefree
Why Recording a lecture is not only a question between you and the lecturer, and finding out afterwards is the wrong order.
Get it Read the recording policy where you study and write down what it permits.
Verify
A note in the README states the policy you checked and the date
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- sessions(id, kind, started_at, ended_at, brief, consent_note, device, model_id) · kind is lecture, seminar, meeting or call, and it changes the defaults rather than just a label - segments(id, session_id, t_start, t_end, text, avg_logprob, no_speech_prob) · one per decoded chunk, keeping whatever confidence the decoder reported - cards(id, session_id, at, kind, text, source_segment_ids_json, shown_at, dismissed_at) · a live prompt, with the transcript it was built from - questions(id, session_id, text, answer, source_segment_ids_json, created_at) · the artefact that matters, answers stored separately from the question text - attempts(id, question_id, at, self_rating, next_due_at) · retrieval practice needs a record of the attempt, not a record of the reading - settings(panel_updates_per_minute, lecture_panel_default_off, audio_retention_days, interval_schedule_json) - There is no streak table, no score and no notification queue. A study tool that nags is a study tool uninstalled in week three.
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
MODEL_API_KEYsecret | optional | sk-...redacted | The panel and question generation. Absent means local transcription only. |
MODEL_ID | optional | a text model identifier | Stored on the session, because questions differ by model. |
SPEECH_MODEL | required | small.en | The local decoder. Larger is slower and the panel cap assumes it keeps up. |
DATABASE_PATH | required | ./data/study.db | Sessions, segments, questions and attempts. The attempts are the irreplaceable part. |
SESSIONS_DIR | required | ./sessions | One markdown file per session. These are meant to outlive the application. |
AUDIO_RETENTION_DAYS | required | 7 | How long recordings of other people stay on your disk. Short is the right default. |
PANEL_UPDATES_PER_MINUTE | required | 3 | Hard cap enforced in the scheduler. Lower it before you raise it. |
MONTHLY_COST_CEILING | required | 3.00 | Assistance stops at this figure and transcription carries on. |
The build, in order
Capture, and a transcript that never invents
Audio is captured from a device you chose and decoded only where somebody is actually speaking.
Capturing the other side of a call is a routing problem, not a code problem.
Files
app/audio.pyREADME.mdSilence in, invented sentences out.
Files
app/vad.pytests/test_vad.pyOtherwise you lose a word every boundary and never notice.
Files
app/transcribe.pytests/test_overlap.py
done when · tick each as it passeswatch out- Decoding fixed chunks with no overlap chops a word at every boundary, so the panel reasons over a transcript that is missing a word every few seconds and you will blame the model for it. Overlap the chunks by a second and merge on the overlap, and drop non-speech before it reaches the decoder rather than after, because long silences are exactly the input that produces fluent sentences nobody said.
A panel that does as little as possible
The live assistance costs less attention than it returns, and in a lecture it is closed.
A cap in the renderer is not a cap.
Files
app/assist.pytests/test_rate.pyThe session kind is a design decision, not a label.
Files
app/sessions.pyweb/panel.jsA prompt you cannot trace is a prompt you cannot check.
Files
app/assist.py
done when · tick each as it passeswatch out- Rendering a card whenever the model returns turns the session into the laptop multitasking condition that Sana and colleagues measured a cost for, both for the person with the laptop and for whoever can see the screen, and the cost lands on the lecture you are attending rather than the transcript you will read later. Cap the rate in the scheduler so the cap holds when the model is fast, default the panel closed for lectures, and time how long you actually spend looking at it before deciding the cap is too low.
The session ends in questions
Finishing a session produces short-answer questions with the answers hidden, and the summary is secondary.
The default view is the design decision here.
Files
web/session_end.jsapp/questions.pySo the interface cannot accidentally show both.
Files
app/db.pytests/test_questions.pyA question about something nobody said is worse than no question.
Files
app/questions.pytests/test_citation.py
done when · tick each as it passeswatch out- Generating a tidy summary and calling it revision optimises the condition that lost by fourteen points at one week in Roediger and Karpicke, and it will feel like the better product because rereading feels fluent and recall does not. Make the question list the page you land on, keep answers collapsed until an attempt has been recorded, and let the summary exist as the second tab rather than the first.
Bringing them back, without nagging
Questions come due on a schedule you can read, and nothing chases you.
With the reasoning next to them, not in a commit message.
Files
config/intervals.jsonapp/review.pyA stored queue drifts from the attempts that produced it.
Files
app/review.pytests/test_review.pyThe absence of a notification path is the feature.
Files
tests/test_no_notifications.py
done when · tick each as it passeswatch out- A review queue that sends a notification is the feature that gets a study app deleted in the second week, and an interval schedule hidden in code is one you cannot argue with when it feels wrong. Keep the intervals in a configuration file with the reasoning written beside them, show the next due date after every attempt, and leave the reminding to the person.
Leaving, and forgettingproduct builder
Everything exports as plain files, the audio expires, and the whole thing runs with no network.
The notes should outlive the application that made them.
Files
app/export.pyShort by default, because it is a recording of other people.
Files
app/retention.pytests/test_retention.pyLocal decoding is the whole reason to run this yourself.
Files
tests/test_offline.pyREADME.md
done when · tick each as it passeswatch out- Keeping the audio indefinitely because disk is cheap leaves a year of other people's voices on a laptop that travels, and the audio stops being useful long before the questions do. Set the retention short by default, make audio deletion keep the segments and questions intact, and make a full session delete remove the markdown file as well as the rows.
That is the whole plan for Hedy. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Mobile background recording.
- Speaker separation.
- Anything that assists during an assessed exercise.
- Calendar and conferencing integrations.
- Mobile apps that keep recording reliably when the screen is off, which is where most of these sessions actually happen
- Tuned latency: your DIY suggestions arrive a beat late, and a beat late is useless in conversation
- Speaker diarization and meeting-type presets that shape the assistant for a sales call vs a lecture vs a doctor visit
- Calendar and conferencing integrations that join and label sessions for you
- Hosted, searchable history across every session with no laptop babysitting
- A second question type that asks you to explain rather than recall, generated from the same segments
- A weekly view of what you failed to recall, which is the only honest measure of whether this is working
- Importing a slide deck as session context, so the questions use the lecturer's own terms
Need the files? The project pack on the verdict page hands your agent the whole brief · more meeting notes.