Let an agent ask "has anything changed?" and get an answer that costs one row, instead of re-listing the whole board to find out.
What it is like today. A browser on a board gets changes pushed (/b/:id/events); an agent has no stream — src/mcp.ts has list_boards, list_columns, list_cards, add_card and move_card, and nothing that says when. A Claude session working a board alongside two people can only poll list_cards, which reads and serialises every card on the board (up to 500 rows) just to discover that nothing moved. The database already keeps exactly the counter this needs: db.boardRevision(boardId), bumped inside every write's transaction and used by the terminal for the same purpose (src/watch.ts, src/tty.ts).
Done looks like
[ ] Every board-scoped MCP read returns the board's revision alongside its data: list_columns and list_cards answer { board_revision, columns | cards }, and the tools' descriptions say what the number is for in one sentence an agent can act on.
[ ] A new board_state tool (name it as you like, say why in the pull) answers { board_revision, name, column_count, card_count } from counts, not from listing rows — the cheap call an agent makes in a loop.
[ ] list_cards accepts an optional since_revision: when it is given and the board has not moved, the result is { board_revision, unchanged: true } and no card rows. When it has moved, the full list comes back as today. Nothing is diffed — this is a no-op check, not a change feed, and the pull says so.
[ ] The revision is read in the same call as the rows and is the value that was current for those rows (read it after, inside the same read, so an agent can never be handed rows newer than the number it is told).
[ ] Every writing tool returns the revision its write produced, so an agent knows its own change landed without asking again.
[ ] Tests that fail without the change: a read returns a revision; a write moves it; since_revision equal to the current one returns unchanged with no rows; a stale since_revision returns the rows; a rubbish since_revision is refused at the boundary like every other argument.
[ ] The README's agent section documents the loop: call board_state, and only list when the number moved.
Files I expect to change
src/mcp.ts, src/db.ts (a small boardCounts read, if counting rows in SQL is cheaper than listing them), src/mcp tests in src/server.test.ts, README.md.
Risks
Waits for #68, which adds the writing half of the agent seat to the same tool table; two runs rewriting tools at once is a needless conflict.
Do not invent a subscription: MCP over plain POST has no stream here, and a polling agent with a one-row check is the honest answer. Say that in the README rather than implying live updates.
boardRevision is bumped by undo too, which is correct for "something changed" and should be stated in the tool description.
Suggested: torque if the crew has an agent-side builder free, otherwise scout, reviewed by sentinel. Waits for #68.
Let an agent ask "has anything changed?" and get an answer that costs one row, instead of re-listing the whole board to find out.
What it is like today. A browser on a board gets changes pushed (
/b/:id/events); an agent has no stream —src/mcp.tshaslist_boards,list_columns,list_cards,add_cardandmove_card, and nothing that says when. A Claude session working a board alongside two people can only polllist_cards, which reads and serialises every card on the board (up to 500 rows) just to discover that nothing moved. The database already keeps exactly the counter this needs:db.boardRevision(boardId), bumped inside every write's transaction and used by the terminal for the same purpose (src/watch.ts,src/tty.ts).Done looks like
list_columnsandlist_cardsanswer{ board_revision, columns | cards }, and the tools' descriptions say what the number is for in one sentence an agent can act on.board_statetool (name it as you like, say why in the pull) answers{ board_revision, name, column_count, card_count }from counts, not from listing rows — the cheap call an agent makes in a loop.list_cardsaccepts an optionalsince_revision: when it is given and the board has not moved, the result is{ board_revision, unchanged: true }and no card rows. When it has moved, the full list comes back as today. Nothing is diffed — this is a no-op check, not a change feed, and the pull says so.since_revisionequal to the current one returnsunchangedwith no rows; a stalesince_revisionreturns the rows; a rubbishsince_revisionis refused at the boundary like every other argument.board_state, and only list when the number moved.Files I expect to change
src/mcp.ts,src/db.ts(a smallboardCountsread, if counting rows in SQL is cheaper than listing them),src/mcptests insrc/server.test.ts,README.md.Risks
toolsat once is a needless conflict.boardRevisionis bumped by undo too, which is correct for "something changed" and should be stated in the tool description.Suggested: torque if the crew has an agent-side builder free, otherwise scout, reviewed by sentinel. Waits for #68.