A two-way sync engine that refuses to guess: fail-closed design for Google Tasks ↔ Microsoft To Do
tasks-todo-sync is a self-hosted, two-way sync between Google Tasks and Microsoft To Do, running in your own Google Apps Script project. v1.0.0, 549 tests passing, Windows one-click installer. No third-party server ever sees your task list — because there isn't one.
Two-way sync is a harder problem than it looks. Either side can change, edits can arrive out of order, and one API can be down while the other keeps accepting writes. The engine is built around one rule: when in doubt, stop — never guess.
Fail-closed writes
If a create's outcome is uncertain, the engine records it and halts instead of retrying blindly. A missed task is recoverable; a duplicated one corrupts everything downstream. Correlation markers track ambiguous creates so nothing is written twice.
Two-round deletion
Nothing is removed on a single observation. The first round records the disappearance; the second round revalidates against the live API before anything is retired. Deletion evidence is journaled, so an interrupted round resumes cleanly instead of leaving orphans.
Checksummed state with restore
Sync state carries checksums with previous-generation restore. A broken round can't poison the next one — the engine falls back to the last known-good state.
Time Bridge
Google Tasks stores dates only, no time-of-day. The engine treats [TTS-TIME:HH:mm] markers in notes as the canonical time record: it sets the Microsoft due time and reminder, then splices the marker out. Optional Calendar projection renders timed tasks as 30-minute events on a dedicated secondary calendar.
Recurrence stays with its owner
A Microsoft recurring series still syncs — it gets a plain Google counterpart, marked so the pair survives Microsoft's daily regeneration. What the engine never does is write into the recurrence itself: due and completion writes to a Microsoft-native recurring task are dropped, the time bridge leaves it alone, and it is never deleted — each of those once made Microsoft's engine re-anchor the series and duplicate tasks across rounds. If a task carries recurrence on both sides, the engine keeps its hands off and emails you to keep recurrence on one side only. Google-born recurring tasks sync as plain tasks — the engine implements no recurrence of its own and translates no rules.
Built for the Apps Script budget
The whole engine runs on a 10-minute trigger inside ~6 minutes of Apps Script execution budget. Everything is checkpointed and resumable, so a round that runs out of time picks up where it left off.
Verified, not just written
v1.0.0 went through a five-axis adversarial review: state machines, fuzzing, concurrency, mutation testing, static consistency. Every finding had to reproduce against shipped code; every fix ships with a regression test.
Repo: https://github.com/simonchai-tw/tasks-todo-sync
If you're running it, I'm collecting real-world data points: how many task pairs are you syncing, and which side do you edit more — Google or Microsoft? Answers here or on GitHub Issues genuinely shape what I build next.
Top comments (0)