I’ve been working on Tsunagi for the past few months and wanted to share it here, and give it a place for discussion.
It’s an Anki desktop add-on that lets other apps and scripts connect to your collection. It includes an AnkiConnect compatibility shim for existing tools, alongside a new HTTP API for developers building integrations.
I’ve been mining vocabulary daily with Tsunagi for a while now, using my own project, Yomine, alongside asbplayer and Yomitan. I haven’t run into any issues. Yomine initially used the AnkiConnect shim, and I’ve since switched it to the new API.
Using existing AnkiConnect tools
The shim handles requests through Tsunagi’s own logic, using Anki’s QueryOp and CollectionOp system for collection work. Existing tools get:
- Less UI blocking, with collection work running in the background.
- Undo for most collection changes through Edit > Undo.
- Per-app keys and permissions, so tools can have separate access limits.
- A request log showing what reached Anki and why anything was refused.
After installation, click Take over to import your AnkiConnect port, API key, and allowed websites. Yomitan, asbplayer, and other existing tools should generally keep working without reconfiguration.
All 122 AnkiConnect actions are implemented, with known differences documented here.
Live collection events
A live event stream lets apps follow changes to notes, cards, and reviews, including changes made inside Anki itself.
A vocabulary tool could update its known-word list after an edit, or a dashboard could update after a review, without repeatedly polling. The TypeScript client also supports watched queries, reporting results being added, changed, or removed.
Building an integration
The new API lets you request only the fields you need and fetch related data together. For example, you can get note types with their field names, or each card’s latest review without downloading its entire history. This means fewer requests, smaller responses, and less processing in your app.
Note creation supports media and duplicate handling together, and request keys let you retry writes without performing the same change twice.
The TypeScript client is available as tsunagi-client on npm, with autocomplete and type checking for queries, fields, and values.
For example, this watches a mining deck and reports changes, including edits made inside Anki:
const anki = new Tsunagi({ baseUrl: "http://127.0.0.1:7777" });
// returns a subscription
const sub = await anki.notes.search("deck:Mining").select("id", "firstField").watch({
added: notes => console.log("Added", notes),
updated: notes => console.log("Updated", notes),
removed: ids => console.log("Removed", ids),
});
// later you may want to stop watching:
// sub.stop();
The client handles keeping the query current, so your app doesn’t need its own polling loop.
A Rust client is in the works too.
Trying it out
Install from AnkiWeb using code 666370974. It’s still marked experimental and currently supports Anki 26.08 and 26.09.
GitHub and documentation · Interactive API reference
Questions, compatibility reports, and discussion about integrations are welcome here. If something behaves differently after switching, let me know which tool you’re using and what happened.
I’d also appreciate feedback from developers on the TypeScript client and upcoming Rust client, especially anything that feels awkward to use or takes more code than it should.