Repository navigation
Description
Split out of #228, which conflated two features under one title. #228 now covers the one-time deck importer; this issue tracks live, bidirectional sync, which is a much larger and later piece of work.
Why this is deferred, not just unscheduled
A server cannot reach AnkiConnect. AnkiConnect binds to 127.0.0.1 by default and gates browser callers through webCorsOriginList. An LWT server — self-hosted on a VPS, or lwt-online.org — has no route to a user's localhost. Telling users to rebind it to 0.0.0.0 and expose it to the network is not something we should ship.
The only viable architecture is client-side: browser JS running on the user's own machine talks to localhost:8765, with the LWT origin added to AnkiConnect's webCorsOriginList by the user. That means it is a frontend feature gated on a manual config step, not a server feature.
AnkiWeb has no public API, so syncing through Anki's own cloud is not an option.
Bidirectional sync is the conflict-resolution problem. The roadmap deliberately quarantines this to Phase 4: "Spike conflict resolution FIRST (the Anki problem) — it looks easy and isn't. Decide last-writer-wins+tombstones vs CRDT before committing." Two systems both mutating term state, both offline-capable, is exactly that problem.
Prerequisites
- The scheduling half is now partly in place: Term status model: single source of truth + Anki/FSRS-aligned scheduling #238 phase 2a added FSRS-6 memory state (
term_schedule) and an append-onlyreview_log, with states matching Anki'scards.type. Phase 2b would populatecards.data+revlogin the.apkgexporter, which gets scheduling round-tripping by file — likely enough for most users who think they want sync. - Do the Phase 4 conflict-resolution spike before writing any sync code.
Recommendation
Ship the file-based path first (#228 importer + #238 phase 2b scheduling round-trip) and see whether real demand for live sync survives it. File round-trip covers the common case without owning a sync protocol.
Activity
feat(vocabulary): replay Anki's reviews back into LWT's schedule
[-]Live Anki sync (AnkiConnect / AnkiWeb) — deferred[/-][+]Live Anki sync (AnkiConnect / AnkiWeb)[/+]Merge pull request #326 from HugoFara/docs/264-sync-conflict-spike
HugoFara commentedon Nov 3, 2026
The conflict-resolution spike this issue asked for is in
develop(#326):docs-src/developer/anki-sync-conflicts.md. Decision: neither plain last-writer-wins nor a CRDT. Reviews merge as the union of both logs folded through LWT's scheduler; fields, tags, flags and existence merge three-way against a stored sync base, with newest-wins only as the tie-break for a true conflict. It ends with a three-step build order, of which step 1 (pull Anki reviews over AnkiConnect) is useful on its own. Phase 2b of #238 is complete (#325), so the file round-trip prerequisite is met.Merge pull request #327 from HugoFara/feat/264-anki-review-pull
HugoFara commentedon Nov 3, 2026
Step 1 of the build order is in
develop(#327):/vocabulary/anki/syncpulls reviews from Anki over AnkiConnect and merges them into each term's history; the.apkgimporter now merges the same way, so an Anki review older than LWT's latest is fitted in rather than skipped. Not yet run against a real AnkiConnect (worth one manual check before release). Remaining: step 2 (push LWT reviews to Anki, after checking whether Anki recomputescards.datafrom inserted revlog) and step 3 (fields, tags, flags, existence via the sync base).Merge pull request #328 from HugoFara/test/264-anki-container
feat(anki): sync fields, tags, suspension and existence with Anki (#264)
Merge pull request #329 from HugoFara/feat/264-note-sync
HugoFara commentedon Nov 3, 2026
Done in
develop./vocabulary/anki/synckeeps LWT and Anki in step over AnkiConnect, following the spike indocs-src/developer/anki-sync-conflicts.md:Tested against a real headless Anki (
scripts/anki/container,npm run anki:up,cypress/e2e/24-anki-live.cy.ts), FSRS on and off.