{"id":"47599af4-4d95-4ff3-92f8-47b0924ddba6","slug":"ozu","kind":"mcp","name":"ozu","summary":"Write on e-paper. Claude does the rest. Handwritten Kindle Scribe pages become a Markdown vault Claude can query over MCP, and twice a day an edition comes back to the tablet. You answer in ink: a tic","owner":"apexclawding","repoUrl":"https://github.com/apexclawding/ozu","license":"MIT","licenseTier":"permissive","trust":"community","stars":2,"match":null,"fewStars":true,"format":"mcp","createdAt":"2026-10-19T19:16:05.000Z","addedAt":"2026-10-29T08:55:44.758Z","logoUrl":"https://avatars.githubusercontent.com/u/269000333?v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["files-documents","memory-knowledge","productivity"],"tags":["ai-agents","claude","e-ink","handwriting-recognition","kindle-scribe","knowledge-graph","markdown","personal-knowledge-management"],"runtime":"python","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-29T09:23:17.713Z","sample":false,"url":"https://conduits.dev/tools/ozu","language":"Python","transports":["stdio"],"install":{"pypi":"ozu"},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"# Ozu\n\n**Write on e-paper. Claude does the rest, and if your input is needed, write it again.**\n\nOzu turns handwritten pages from an e-ink tablet into a Markdown knowledge\nvault that Claude can read from anywhere, and then writes back to you on\npaper. Twice a day a typeset *edition* lands on the tablet: what your ink\nbecame, tasks it closed, research it did overnight, and code it proposes to\nwrite. You answer in ink. A tick closes a task. `@approved`, written by hand,\nruns a code change on a branch and opens a pull request.\n\nMost \"second brain\" tools are one-way: notes go in and nothing comes back.\nIn Ozu the paper is both the input and the control surface, so nothing an\nagent does to your code happens without a page you read and a pen stroke\nyou made.\n\n```\n you write             Ozu reads                  you get back\n ─────────             ─────────                  ────────────\n a notebook page  ──►  vision model ──► vault/  ──► Ozu Morning / Evening (PDF)\n (PDF export)          (one call per     *.md        what your ink became\n                        new page)        + SQLite     ☐ open actions, receipts\n                                         + MCP        research briefs\n                                                      Build proposals\n ink on an edition ──► annotation pass ──► ticks close actions\n                                          @input revises a Build\n                                          @approved runs it → branch → PR\n```\n\nIt has run every day through 2026 for one person, one Kindle Scribe\nColorsoft and a 4-core VPS: SQLite and files, no Redis, no queue, no JVM.\n\n## The ink language when color is available\n\nFour colours and one tag character. Everything downstream comes from these\nmarks (full reference: [`CONVENTIONS.md`](CONVENTIONS.md)).\n\n| Ink | Means | What happens |\n|---|---|---|\n| **Black** | capture | becomes note text |\n| **Red** | action | the *only* thing that creates a task |\n| **Blue** | an idea worth developing | linked to older thinking and resurfaced |\n| **Green** | personal | routes to `people/` |\n| `@garden` | a project tag | files the content under that project |\n| `✓` on a printed `☐` | done | closes the action; receipt in the next edition |\n| `@research` | a question | an overnight brief that cites your own notes |\n| `@claude` | build this | opens a **Build**: a plan comes back on paper |\n| a video saved to a playlist | learn this | a brief on the evening sheet, back again after 2, 7 and 30 days ([`capture/`](capture)) |\n| `ozu learn add <link or PDF>` | learn this | the same, for an article, a post or a document — figures included |\n\nRed is exclusive on purpose. If anything task-shaped became a task, red would\nstop meaning anything.\n\n## The Build loop: approving pull requests with a pen\n\n1. Write an idea, tag it `@kettle @claude`, and export the page.\n2. Within five minutes a document called `Ozu Build r1 - <your idea>` lands\n   on the tablet: what Claude understood, a precise requirement, a\n   step-by-step plan, the risks, what it will *not* do, and its open\n   questions. It was written by a read-only run that can see the repo and\n   your vault but cannot change anything.\n3. Answer in ink. `@input` plus your words produces revision `r2`.\n   `@approved` (optionally `@opus`, `@sonnet` or `@fable`) runs it once, in a\n   fresh clone, on branch `build/<id>`, and opens a PR. `@drop` closes it.\n4. The result arrives in the next edition with the agent's report and a\n   printed `☐ Review PR #12` line. Tick it when you have.\n\nWhat executes is always text you read. The agent's tools are scoped per run\n(file access pinned to its own clone, an explicit Bash allowlist, `git push`\ndenied, no installs), and every Build carries a lifetime attempt budget\nwritten *before* it launches. That last rule exists because one Build once\nrelaunched itself 116 times overnight: [`docs/build-attempts.md`](docs/build-attempts.md).\n\nSet `OZU_ISA_TOPICS` for a project and its proposals take a different shape:\nthe ideal state, the decisions, and numbered steps that each name the check\nthat proves them. The result then reports every step as pass, fail or not\nverified, so the plan you approved is also the test it is graded against.\n\n## A wiki that argues back\n\nLearning briefs say what one video said. The wiki says what you know about a\nsubject across every video, page of ink, voice memo and research brief that\ntouched it. Every two-hourly cycle a read-only run folds a few new notes into\nconcept pages in `topics/wiki/`: each claim cites the notes it came from,\ndisagreements between sources are kept and named, and a page says how the\nsubject touches your own projects.\n\nOn Sundays the evening edition carries a *Wiki this week* sheet with what\nchanged. Write beside a claim to correct it, or strike a line through it to\ndrop it; your ink outranks every brief, and the next cycle applies it.\n\n## What it measures instead of assuming\n\nThe design decisions were made against real pages, and the numbers are in the\nrepo.\n\n- **67 % of returning pages carried no new ink.** They are now compared with\n  the copy that was sent and never read by the model (`ink.py`, D-09).\n- **A cheaper model reads returning documents.** On ticks it found 27 of 27,\n  none invented; the strongest model is kept for notebook pages, the\n  irreplaceable capture (D-10).\n- **Lowering reasoning effort invents ticks.** At `low`, the model read a\n  *printed* receipt line as a fresh handwritten tick. Both calls stay at\n  `high`, at under two cents a page ([`docs/effort-sweep.md`](docs/effort-sweep.md)).\n- **14 characters lost across 16 documents** (`€`, `②③④`, `≤`) led to a\n  renderer rewrite with a round-trip gate on every printed character\n  ([`docs/glyph-loss.md`](docs/glyph-loss.md)).\n\nThe rules these produced, and the incidents behind them, are in\n[`DESIGN.md`](DESIGN.md).\n\n## Set it up with Claude Code\n\nOn the Linux machine Ozu will run on, open Claude Code and paste:\n\n```\nSet up Ozu for me. Clone https://github.com/apexclawding/ozu to ~/ozu if it\nis not there yet, then read ~/ozu/docs/setup-with-claude.md and follow it\nwith me step by step.\n```\n\nClaude checks the machine, installs, and walks you through the accounts one\nat a time: the API key, your tablet's export folder, a first test page, and\nthen, if you want them, paper back on the tablet, Builds, a vault backup and\nClaude access. You type every secret yourself, in your own terminal; the\nrunbook forbids Claude from reading them. About an hour, most of it waiting\non accounts. The runbook is [`docs/setup-with-claude.md`](docs/setup-with-claude.md);\nthe manual steps are below.\n\n## Install\n\nYou need Linux with systemd, Python 3.12, an\n[Anthropic API key](https://console.anthropic.com), and a folder your tablet\nexports PDFs into that `rclone` can read (the Kindle Scribe exports to Google\nDrive). Optional: a Send-to-Kindle address and SMTP account for delivery\nback to the device, the [`claude` CLI](https://docs.claude.com/en/docs/claude-code)\nfor `@claude` and `@research`, and a GitHub token for pull requests.\n\n```bash\ngit clone https://github.com/<you>/ozu ~/ozu\n~/ozu/deploy/install.sh          # venv, ~/ozu-data/.env, vault, systemd timers\nnano ~/ozu-data/.env             # ANTHROPIC_API_KEY, OZU_RCLONE_REMOTE, …\n~/ozu/.venv/bin/ozu run          # first run by hand: pull → read → vault\n~/ozu/.venv/bin/ozu status\n```\n\nEvery setting is documented in [`.env.example`](.env.example). Then write one\npage in black, red and blue with an `@tag` and a small sketch, export it in\ncolour, and run `ozu run` again.\n\nDocuments arrive named \"Ozu Morning …\", \"Ozu Build r2 - …\" and so on. The\nname is configuration: `OZU_BRAND` sets what goes out, and\n`OZU_DIGEST_PREFIXES` lists every name a returning document is recognised by,\ncase-insensitively. If your device already holds documents sent under another\nname, list it there too, so ink written on them still routes home.\n\n### Commands\n\n```\nozu run                  the 2-hourly cycle: pull, read, vault, research, wiki\nozu tick                 the 5-minute paper loop: pull, read, Builds\nozu edition morning      build and send an edition now (also evening | extra)\nozu learn                brief the videos and articles waiting in the vault now\nozu learn add <url|file> read an article, an X/Threads/LinkedIn post or a PDF into the queue\nozu learn probe <list>   can this server read these links? (reads, writes nothing)\nozu wiki                 wiki status; `wiki run` now; `wiki requeue [--all]`\nozu builds               list Builds; `builds split|reset|simulate`\nozu index                rebuild the database from the Markdown, any time\nozu requeue error        re-read pages that failed\nozu okf check            vault conformance gate (Open Knowledge Format)\nozu lint [folder]        read-only lint of the learning loop (default topics/learning)\nozu mcp [--http]         MCP server for Claude Code / Claude.ai\n```\n\n## One more thing: talk to it, and learn from what you watch\n\nPaper is one front door. [`capture/`](capture) adds two more to the same\nvault, and neither sends your audio anywhere:\n\n- **Voice memos.** Record on your phone, drop the file in a NAS folder, and a\n  Mac transcribes it on-device ([`transcribe/`](transcribe), Whisper on\n  Apple Silicon) and pushes a note into the vault. It is searchable over MCP\n  like any handwritten page.\n- **Learn from YouTube.** Save a video to a playlist. A small container on\n  the NAS fetches its captions, and the brief Ozu writes from them lands on\n  the evening edition's Learn sheet, then comes back after 2, 7 and 30 days.\n- **Learn from what you read.** `ozu learn add <link>` does the same for a\n  blog post, a news article, a Substack, an X, Threads or LinkedIn post, or\n  a PDF. The server reads it — text through trafilatura, figures (charts,\n  diagrams, screenshots, a post's image) saved as images beside the note,\n  a PDF's figure pages rendered — and the brief run opens the figures with\n  the same read-only, vault-only permission it uses for transcripts. Figures\n  are git-ignored (`assets/learning/`), so the vault does not grow by a\n  gigabyte a year. Anything it cannot read (a paywall, a bot wall) comes\n  back on the sheet as \"could not be read\", not silence. Fetching is\n  guarded: public addresses only, checked at every redirect and pinned for\n  the connection, so a link can never reach a service on the server's\n  loopback. Run `ozu learn probe` on a list of links you read to see what\n  your server can reach before relying on it.\n\n```\nozu/\n├── src/ozu/      the core: paper → vault → Claude → paper   (Linux server)\n├── capture/      voice memos + learn from YouTube            (Mac + NAS)\n└── transcribe/   on-device audio → Markdown                  (Apple Silicon)\n```\n\nEach part has its own README, `pyproject.toml` and tests, and CI runs each\non the machine it needs.\n\n## Use your vault from Claude\n\nThe vault is plain Markdown in git, an [Open Knowledge Format](docs/okf.md)\nbundle you can open in Obsidian. Over MCP, Claude gets `search_notes`,\n`get_note`, `graph_neighbors`, `timeline`, `open_actions` and `capture`\n(writing a note back from any conversation).\n\n```json\n{\"mcpServers\": {\"ozu\": {\"command\": \"ssh\", \"args\": [\"your-server\",\n  \"cd ~/ozu && exec .venv/bin/ozu mcp\"]}}}\n```\n\nOver ssh, the key is the auth and no port is exposed. For Claude.ai, `ozu mcp\n--http` serves on loopback behind a bearer token. Put a TLS proxy in front\n(`deploy/caddy-mcp.conf`).\n\n## Costs\n\n- **Vision:** about $0.065 per page read (input is mostly the page image).\n  Unchanged pages are deduplicated by image hash, so re-exporting a notebook\n  costs only its new pages, and returning pages with no ink cost nothing.\n- **Builds, research and learning briefs** run on the `claude` CLI's own\n  login, not the API key.\n\n## Limits, honestly\n\n- **One person, one device, one box.** Ozu is a working personal system, not\n  a product. Expect to read code.\n- **Colour matters.** Actions come only from red ink, so on a monochrome\n  tablet everything works except creating actions by colour.\n- **Delivery is Send-to-Kindle.** Other tablets can sync the PDFs in\n  `~/ozu-data/editions` some other way, but that path is not built.\n- **The work wall is post-API** (see invariant 2). If a notebook must never\n  leave the device, do not export it.\n\n## Development\n\n```bash\npip install -e \".[dev]\"\npytest -q                          # hermetic: the vision call is mocked\npython tools/render_sample.py      # every document type → build/sample/\n```\n\n`render_sample.py` builds every document from synthetic fixtures and checks\nthat every printed character survives the round trip. Look at the pages, not\njust the numbers: covers are also written at library-thumbnail scale.\n\n## Roadmap\n\nOpen items, and why each waits: [`ROADMAP.md`](ROADMAP.md).\n\n## License\n\nMIT. See [`LICENSE`](LICENSE). To contribute, see [`CONTRIBUTING.md`](CONTRIBUTING.md); to report a vulnerability, see [`SECURITY.md`](SECURITY.md).\n"}