Skip to content

chekusu/mokutori

v0.3.6

Receive pages scanned with the Mokutori app for iPhone and iPad straight in this agent: pair with a QR code, then read each batch of corrected page images and OCR text.

Mokutori for agents

Pages scanned with Mokutori, the free document scanner and OCR app for iPhone and iPad (App Store), arrive directly in your own agent: Grok Bot, Codex, Claude Code or any agent that can run a shell command. Muse connects through the included optional MCP bridge. No computer or desktop app is needed on the scanning side: scan book pages, documents or receipts on the phone or tablet, and the agent receives corrected page images plus on-device OCR text (Japanese, including vertical text, Chinese and English).

Current plugin version: 0.3.6

Website · Source · Releases · MIT license · Security policy

Mokutori (iPhone / iPad) ──sealed chat (pages + OCR)──> Friends gateway ──> this agent's bot ──> `mokutori inbox`
     ▲                                        (bots.yobiru.com)
     └── scans the one-time QR code from `mokutori pair`
  • Pairing by QR code or a phone link. mokutori pair returns both a QR image and a clickable HTTPS pair_link. Send both to the owner. They can scan the image with Mokutori, or tap the link on the phone where the app is installed. Both carry the same end-to-end key and one-time secret. The owner taps Connect in the app, which sends this bot a pairing request; the app shows "Pairing" until the owner confirms that request here (pair-requests, then pair-accept). Report success only when paired is nonempty.
  • End-to-end encrypted. Each batch is sealed on the iPad for the agent's key and the iPad's own key (X25519, ChaCha20-Poly1305). The gateway stores ciphertext plus routing metadata and attachment sizes.
  • Batches. Up to five pages per message: corrected JPEGs plus OCR markdown, within the gateway's limits (8 files, 8 MiB). Pages are queued on the iPad and retried until they are stored.

Install

Clone the complete package into a persistent location on the agent's host:

git clone https://github.com/chekusu/mokutori-agent-plugin.git
cd mokutori-agent-plugin
sh scripts/mokutori status

Keep scripts/, skills/, the plugin manifests and the optional muse_connector.py together. The skill resolves the launcher relative to its own path, so copying only SKILL.md or the skill directory breaks its commands. If a host supports loading a skill by path, point it at /absolute/path/mokutori-agent-plugin/skills/mokutori-scans/SKILL.md in this checkout.

AgentHow
CodexInstall the complete folder as a plugin; its manifest is .codex-plugin/plugin.json.
Claude Code/plugin install mokutori --marketplace chekusu/mokutori-agent-plugin (Claude Code 2.1.275 or later), or /plugin marketplace add chekusu/mokutori-agent-plugin then /plugin install mokutori@mokutori. A local checkout also works as a plugin folder (.claude-plugin/plugin.json); the skill is discovered from skills/.
Grok BotRegister the skill with the owner's permission and keep the folder under /workspace. If Grok still has the older Mitori plugin, follow the upgrade note below before pairing.
MuseRun the included MCP bridge on your own host and connect Muse to its HTTPS /mcp endpoint with that installation's API key.

Then tell the agent: “连接我的 Mokutori iPad”. The skill walks through setup (one email code), pairing and reading pages. Requires Python 3.8+ (standard library only).

The Muse bridge gives one API key access to one private library. It is a self-hosted integration; publishing this source package does not provide a shared hosted library or imply marketplace approval.

Upgrade an older Grok Bot plugin

Version 0.2.0 is the first public plugin release using the renamed Mokutori pairing protocol. Replace the old plugin files in Grok's workspace with this release, then reload the skill. Keep the existing $MOKUTORI_AGENT_HOME directory: it contains the bot credentials, paired-device records, inbox and receipts, and an upgrade must not delete it.

Version 0.2.3 also restores older installations that stored setup.owner_home in state.json to reuse an existing Yobiru owner. That exact directory continues to hold the owner credential; the plugin does not copy it or create a credential symlink. status reports both home (Mokutori's receiver data) and owner_home (the credential location), so verify both paths and the unchanged bot_id after upgrading. Keep using --home "EXISTING_MOKUTORI_HOME" before every command when the original receiver used a custom path. If owner_home is unavailable, restore access to that original directory; do not reset setup or substitute another owner's credential. Credential files must still be private regular files, not symlinks.

Old pairing records may contain only used_by, without the proof/job fields required by the current recovery path. Version 0.2.3 preserves these records and existing devices/receipts, and reports pairing_warnings instead of replaying permissions or claiming that an old unfinished request succeeded. Do not manually mark a pairing accepted or replace the whole state from a backup to clear this warning. If that device still needs pairing, generate a fresh code. Keep any pre-upgrade backups intact.

Generate a fresh QR code after upgrading:

sh scripts/mokutori status
sh scripts/mokutori pair --png /tmp/mokutori-pair.png --minutes 30
sh scripts/mokutori pair-check --wait 600
sh scripts/mokutori pair-accept PAIRING_ID     # after the owner confirms the request

Version 0.2.4 adds a clickable HTTPS link alongside the image. Show the owner both qr_png and pair_link, formatted as a clickable “Open Mokutori to pair” link, rather than only showing a QR code on the phone they need to pair.

OutputPurpose
qr_pngThe QR image; its payload remains the existing custom scheme for older scanning builds.
pair_linkhttps://mokutori.com/pair#v=1&g=...&b=...&k=...&i=...&s=...[&a=...] for a clickable phone link.
pair_urlThe existing mokutori://pair?... URL, retained for compatible clients and the QR payload.

The HTTPS URL puts all pairing parameters after #, with no query string. Browsers do not send this fragment in the HTTP request for /pair. Do not move the secret into a query/path, use a URL shortener, or publish the full link. With a supporting app and Universal Link association, tapping opens the app's receiver confirmation. Otherwise /pair provides installation and app-opening guidance. Installing the app does not preserve an expired code: return to the original link or request a fresh one after installation.

New pairings use mokutori://pair and the mokutori-pair/1 proof prefix. A QR generated by an older Mitori plugin (mitori://pair) is not compatible with this protocol; do not reuse it. Pairing codes are one-time secrets and expire, so show the new image only to the owner and remove the temporary image after scanning.

An owner often runs several agents (a Grok Bot, then Muse, each on its own cloud computer), and the official gateway lets one email register one owner. Setting up a second agent with the same email therefore adds its bot to that owner (Yobiru 0.7.20 join): setup --email and setup --email-code as usual, with the same single code. That agent's data home then holds a manager credential for its own bot only (status shows "credential": "manager"), never the owner credential, and cannot reach the owner's other bots. pair-accept, pair-decline, rename, wake, unpair and recovery use it as they would an owner credential. The gateway emails the owner, who sees the bot and can revoke it from a device with the owner credential (yobiru public owner managers BOT, owner revoke-manager BOT ID).

setup --owner-home /absolute/YOBIRU_HOME --name "YOUR NAME" --agent grok creates a new Mokutori receiver under an existing owner directory on the same machine. Do not copy an owner directory to another machine for it: that credential administers every bot of the owner. Set up with the email instead. An existing installation needs only the plugin upgrade; do not rerun a full setup or use setup --force to repair it.

Bot name and agent mark

setup requires --name: the bot's display name on the gateway, which Mokutori shows when the owner confirms pairing and in its connected agents list (at most 80 characters). Use the name the owner knows the agent by, such as its role, because one owner may pair several bots; "Mokutori" is refused. Earlier versions silently named every bot "Mokutori", so an existing bot showing that name should run rename --name "NEW NAME", which updates the gateway card and keeps pairings and pages.

Pairing links for --agent grok and --agent muse end with &a=grok-bot or &a=muse, so Mokutori can show that agent's mark in colour once paired; other agents omit a. Setups from before this change did not record the agent: run setup --agent grok (or muse) once on the existing installation to record it locally. This does not change the gateway or create another bot.

Commands

sh scripts/mokutori setup --email you@example.com --name "Research assistant" --agent codex   # step one: a code is emailed
sh scripts/mokutori setup --email-code 123456 --name "Research assistant" --agent codex       # step two
sh scripts/mokutori rename --name "账本管家"                        # change the name Mokutori shows
sh scripts/mokutori pair --terminal                                  # one-time QR code
sh scripts/mokutori pair-check --wait 120                            # find the device's pairing request
sh scripts/mokutori pair-requests                                    # requests waiting for the owner
sh scripts/mokutori pair-accept PAIRING_ID                           # the owner confirmed: admit it
sh scripts/mokutori pair-decline PAIRING_ID                          # the owner declined
sh scripts/mokutori inbox                                            # save and show new pages
sh scripts/mokutori inbox --ack MESSAGE_ID ...                       # clear the unread markers of batches you read
sh scripts/mokutori inbox --ack                                      # ... or of every batch inbox showed before
sh scripts/mokutori recover --check                                  # what the iPads sent vs. what is here
sh scripts/mokutori recover                                          # save batches the gateway kept but this folder lacks
sh scripts/mokutori devices
sh scripts/mokutori unpair ACTOR_ID
sh scripts/mokutori status

Under the hood

The transport is the Yobiru Friends jobs protocol (engine 0.7.20), pinned to the exact official source revision in scripts/engine/SOURCE.json. This plugin does not use the retired notice inbox. scripts/engine/ is an unmodified copy of the Yobiru public-bot client (MIT, see scripts/engine/LICENSE and scripts/engine/SOURCE.json); scripts/third_party/qrcodegen.py is Project Nayuki's QR Code generator (MIT). The agent owns a bot on the gateway with two local identities: an administration credential (accepts paired iPads: the owner credential, or for a bot added to an existing owner, a manager credential for that bot only) and a native reader binding (claims and reads jobs). The iPad is a pseudonymous caller; after pairing it is a trusted contact allowed to send files.

Pairings use the mokutori-pair/1 proof prefix. mokutori://pair?... and the HTTPS fragment link carry the same parameters and consume the same one-time pairing; the HTTPS link does not create another pairing.

The plugin has no trusted real-time agent presence field. The gateway's agent_connected and binding_configured describe configuration, and pairing describes permission. Neither proves that a Grok, Muse or other personal agent is currently online. Consumers should keep online status unknown unless they have separate reliable presence evidence.

The iPad app is maintained separately. tests/app_protocol_reference.py is a self-contained Python reference of its pairing and delivery protocol, and tests/test_mokutori_plugin.py runs the whole flow (setup, QR pairing, a forged and a replayed pairing, a sealed three-page batch, inbox, acknowledgement, unpair) against a real local gateway. The runner archives the pinned commit from an existing local Yobiru Git repository and uses fresh temporary gateway and identity folders. The same runner includes the Muse connector tests and a CLI-to-MCP scan retrieval round trip. It does not contact a production gateway:

python3 tests/run_e2e.py /path/to/yobiru

Receiving claims a job, verifies its sender and encryption binding, saves its files and a private local receipt, then finishes it with outcome: read without sending a reply. inbox keeps showing the saved batch until inbox --ack clears its local unread marker; acknowledgement never deletes the files. --ack clears only the batches it names, or with none named the batches an earlier inbox printed: a batch that arrives between an agent's inbox and its --ack is shown in the --ack output and stays unread. inbox prints at most --limit batches (default 20) and about 20,000 characters of them, oldest first, and says how many more wait in remaining. Repeated sends and repeated inbox reads reuse the same message receipt. An interrupted saved claim resumes its own lease with /start. The gateway builds each claimed job's conversation transcript from every earlier message, which can take long in a long scan, so a claim waits up to 170 seconds; when its answer is still lost, inbox saves that batch from the gateway's copy of the message (owner credential, same checks) and lets the gateway's claim run out. inbox claims for about 90 seconds per run and reports what still waits in waiting_at_gateway. Yobiru 0.7.14 can mark an accepted sender's expired claim read; the plugin verifies gateway metadata and recovers its own authenticated local cache, including pairing proofs. Before renewing a claim, it saves an independent private encrypted snapshot so the official client cannot delete the only copy when the lease expires between listing and renewal. The snapshot is removed only after the local receipt is saved. Truly uncertain claims include an owner-only retry command. They are retried only after that explicit resolution, with the same message and files checked again. Existing local acknowledgement is retained in that same atomic receipt update. A lost finish response is reconciled against gateway metadata. Disconnecting a device blocks future sends and stops new receipts from that device; previously saved pages remain available.

recover reads the owner's view of each paired device's conversations at the gateway (read-only), opens the batches this folder does not hold with the bot's key, verifies them as inbox verifies a job, and saves them as unread batches. It covers a batch that was marked read by another run or host whose files did not survive, one that ended at the gateway before it was read, and files lost here. recover MESSAGE_ID ... saves named batches again. The gateway reads every kept body of a conversation before it returns that history, which can take far longer than an ordinary request, so recover allows 170 seconds per history, checks for about --seconds (default 40, at least one conversation) and keeps its place in state.json; run it again until remaining_conversations is 0. Conversations that were open while a gap in the local page numbers opened are checked first. It also lists the page numbers no batch carries (pages the app never delivered) and the messages inbox ignores because their sender is not paired.

Limits: an agent learns about new pages only when it runs inbox (or a scheduled task does); waking an idle hosted agent is not automatic. The official gateway stores sealed messages for up to 30 days.

Test image: tests/synthetic-page.jpg is a 32×32 downsample of the iPad project's generated synthetic-flat.png fixture. It contains no user scan or personal metadata. tests/seal_vectors.json uses fixed, synthetic keys and identifiers for protocol tests; those keys must never be used with real documents.

License

Mokutori plugin code is released under the MIT License. The bundled Yobiru engine retains its MIT license, and Project Nayuki's QR generator retains its MIT notice in qrcodegen.py. Agent names and trademarks belong to their respective owners; compatibility does not imply endorsement.