What the films say, and where it is true
Every claim in the technical walkthrough, with the code it rests on and the test that checks it. Run the tests with cd apprentice && npm test: the file is test/claims.test.mjs.
| The film says | Where it is true | Checked by |
|---|---|---|
| Events, not pixels. A native Mac app; Accessibility gives the app, the window title and the prompt. 0 screenshots, 0 keystrokes. | The reader is native/ApprenticeReader.swift: it asks macOS Accessibility and nothing else. Each change is stored as an event marked event-not-image in src/collector.mjs. No screen-capture or keyboard API is linked anywhere in native/ or src/. | events, not pixels |
| Refused before it is written. Private apps are refused. | The list of refused apps and title words is at the top of src/collector.mjs. The reader turns a refused app away before it looks at the window, and a private title before anything is returned. The count on screen ("refused today") is privateRefusals: counted, never named. Since the films, chat and mail can be kept by name and time when that is switched on in Settings; it is off until asked for, and password managers, banking, health and private windows are never named. | refused before it is written; chat and mail are named only when that is switched on in chats.test.mjs |
| Secrets are redacted. | src/redact.mjs runs before an excerpt is stored: mail addresses, passwords, keys, tokens. | redacts local secrets before persistence in core.test.mjs |
| The memory is stored on this Mac. | Everything is written under apprentice/data/, set in src/store.mjs, which is not in this repository. The same memory is written as plain Markdown notes in apprentice/wiki/ (src/wiki.mjs), which opens as an Obsidian vault. The server listens on 127.0.0.1 only. | the memory is served to this Mac only, and the memory is also a folder of linked Markdown notes in vault.test.mjs |
| He decides what I see. | Go private stops all capture at once (/api/control in src/server.mjs); the island's eye closes. Sound, summaries, the ElevenLabs voice and the name are under Settings (src/settings.mjs). | a setting is kept in settings.test.mjs |
| It waits for the pause. Six seconds still, then ninety seconds quiet. | limits() in src/question-engine.mjs: pause 6000 ms, cooldown 90 000 ms, five questions at most in a session. | it waits for the pause, and asks a guardrail question only after a pause in core.test.mjs |
| One memory, every agent. The rules come out of the agent logs. | src/projects.mjs reads the Claude Code logs; src/memory.mjs turns a correction given twice into a rule, and keeps it only when the quote is really something that was said. | the rules come out of the agent logs |
| Three ElevenLabs agents. | Debrief, tutor and recall in src/agent.mjs, each with its own prompt and tools. | three ElevenLabs agents |
| MCP. | src/mcp-handler.mjs: eight tools, among them how_was_it_built, guardrails_for_agents and check_decision. | mcp.test.mjs, three tests |
| Work today in per cent. | aggregateActivity in src/activity.mjs: work, social and other always sum to 100; idle time over a minute is left out; time inside a project counts as work. | The activity tests in core.test.mjs |
What it cannot do yet
The film says these too. They are true.
| The film says | In the code |
|---|---|
| Mac only. | The reader and the island are Swift, AppKit and macOS Accessibility. |
| Claude Code logs only. | src/projects.mjs reads ~/.claude/projects. Cursor gives a project its time, not its memory. Chats in ChatGPT or on claude.ai are not on disk and are not read. |
| The voice is in the cloud. | Speech, the calls and dictation go to ElevenLabs (src/voice.mjs, src/agent.mjs). Summaries go through the Claude CLI on your own login (src/llm.mjs). The memory itself stays on the Mac. Both can be switched off in Settings (src/settings.mjs); then nothing leaves it. |
| It does not ask in the background yet. | Off by default in src/store.mjs: questions are asked only inside a capture session. |
Every jump, every decision
| Today | Next | |
|---|---|---|
| Every jump between apps | Each change of app, window and project is an event, and moves between projects are counted (src/projects.mjs). In a session a move can be asked about (rankSwitch). | The same in the background, at a real pause. |
| Every decision | Decisions and rules are kept from the debrief call, from live answers and from corrections repeated to agents. | A decision it has not seen before is noticed and asked about once. |
| Saying how it was built | The recall call asks what you remember and fills in what you left out; how_was_it_built gives the same memory to any agent. | The memory follows the project, not the Mac. |
Since the films
Added after the submission, which is the tag hack-nation-7.
| What | Where | Checked by |
|---|---|---|
| Built. Mason asks its owner about their own projects, one question at a time, and holds the answer: how it is put together, what was decided, what was built last, where it was left. | src/built.mjs, from what is remembered of each project; the memory now also keeps the decisions that were made (src/memory.mjs). No model is asked when a question is shown. | built.test.mjs, two tests |
| The look back. After three days of real work, how it was done: what followed a prompt, how long finished answers waited, the pace. Nothing is asked for and no aim is declared. | lookBack in src/coach.mjs, written by src/days.mjs and kept as it was. An answer is finished when the agent's log says the turn ended (absorb in src/projects.mjs); it waits until an app where answers are read is in front again. | coach.test.mjs, three tests; turns.test.mjs; a look back is due after three finished days in days.test.mjs |
| Proposals. A rule said in several projects is proposed for every agent, with the words it rests on. | src/suggest.mjs. The model only says which rules belong together; the evidence is the quotes themselves. Mason writes the rule nowhere: it hands it to an agent as a prompt its owner reads and sends, and a rule about publishing or deleting without asking is never proposed. | suggest.test.mjs, four tests |
| Flow. How a day moved between tools: the jumps, the habits between two tools, the longest unbroken stretch. | src/flow.mjs. A glance under five seconds, a pause in the same tool and a break of fifteen minutes are not jumps. A tool in a browser is known by the site of the front tab: the reader gives its host and nothing more of the address (native/ApprenticeReader.swift). | flow.test.mjs, five tests; a browser tab is kept with the host of its site in chats.test.mjs |
| A picture to share. The flow of a day or a week as one picture, with only the names of tools on it. | Drawn in the window, written by src/share.mjs beside the memory. Mason posts nothing. | share.test.mjs |
| Logos from the web. A site's own icon, asked for once, only when switched on. | src/site-icons.mjs: public names over https only, redirects followed by hand, pictures only. | site-icons.test.mjs, seventeen tests; site-logos.test.mjs |
| Days. Every day worked and its projects, back to the first day of each. | src/days.mjs, from the agents' logs, kept in data/days.json so the days outlast the logs. | days.test.mjs, three tests |
| Any model. The summaries can be written by any model, one on the Mac included. | src/llm.mjs | llm.test.mjs, two tests |
| A switch on everything read and sent. | Agent logs, chat and mail by name, summaries and ElevenLabs in src/settings.mjs. | settings.test.mjs, three tests |
| The tools' own icons. | native/MasonIcons.swift asks macOS for an app's icon by its name and reads nothing else. |
The numbers on screen in the film (87% work, 50 refused) were read from the running app on 4 October 2026 at 14:35. They are that day's own data and are not in this repository.
Edit this page on GitHub
10 Oct 2026
