DEV Community

simonchai-tw
simonchai-tw

Posted on Edited on

Google Tasks ↔ Microsoft To Do, two-way sync: self-hosted

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)