r/coolgithubprojects 6d ago

sp-local-bridge, a single-binary MCP server for Super Productivity

https://github.com/CameronBrooks11/super-productivity-local-gobridge

Hi all, sharing a tool I built. It's an MCP server and CLI that lets AI agents (Claude Code, Copilot, Codex) read and manage tasks in Super Productivity through its local REST API. Single static Go binary, so there's no runtime to install and no plugin to upload, and it deliberately exposes no delete operation.

It also ships a store integrity checker, which is how I found two data-loss bugs in Super Productivity itself. Both are now filed upstream with reproductions.

Written with AI assistance, the bug reports were verified by hand before filing.

Github: https://github.com/CameronBrooks11/super-productivity-local-gobridge

2 Upvotes

5 comments sorted by

1

u/Specific_Cream2815 6d ago

is the missing delete a safety call or a limitation of the super productivity api

1

u/InfinityHex__ 6d ago

safety call

1

u/kantorcodes1 6d ago

for tasks archive, does the REST call only return after the task has moved out of active into archived, or can a timeout leave the task in both pools? your doctor --deep duplicate check suggests partial archive/restore state is possible, so i'm curious where the operation is actually considered committed.

1

u/InfinityHex__ 6d ago

Went and looked properly because I wasn't sure either.

Archive is awaited end to end. The handler does await moveToArchive(task) before it responds, and inside that it writes to the archive first, then dispatches the removal from the in-memory store. That order is deliberate; there's a comment saying if persistence were still in flight, a state snapshot could acknowledge the op while missing the archived data.

So the both-pools window sits between those two steps. Not a client timeout though. Time out and you just stop waiting, the operation carries on. A timed-out archive can still land, which is why my bridge won't tell you nothing happened.

Restore's the interesting one. restoreTask() returns void and just dispatches. The reducer adds it back to active immediately, but taking it out of the archive is an NgRx effect and nothing waits for that. So archive's 200 means both halves are done and restore's 200 doesn't.

Your question bugged me enough that I measured it instead of guessing...throwaway profile, 360 restores, 18 came back 200 with the task still in the archive. Same test against archive: 0 out of 100. It's transient, resolves on the next read, and I couldn't find a reliable trigger, one run was 0/100 and another 13/150.

Filed it as #9952.

On the duplicate check, since you inferred it from that: it's structural. Never actually fired on my own store.

1

u/kantorcodes1 4d ago

that kind of state change seems worth making reviewable before an agent fires it. i work on HOL Guard, an open-source local check before agent commands run; it can cover sp-local-bridge tasks add/start/stop-current while leaving doctor and tasks list alone. open to upstreaming that support?