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 pairreturns both a QR image and a clickable HTTPSpair_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, thenpair-accept). Report success only whenpairedis 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.
| Agent | How |
|---|---|
| Codex | Install 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 Bot | Register 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. |
| Muse | Run 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.
| Output | Purpose |
|---|---|
qr_png | The QR image; its payload remains the existing custom scheme for older scanning builds. |
pair_link | https://mokutori.com/pair#v=1&g=...&b=...&k=...&i=...&s=...[&a=...] for a clickable phone link. |
pair_url | The 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.