From tandem
Use when tandem_* MCP tools are available, the user asks about Tandem document editing, or iterating on text collaboratively. Provides workflow guidance, annotation strategy, and tool usage patterns for the Tandem collaborative editor.
npx claudepluginhub bloknayrb/tandem --plugin tandemThis skill uses the workspace's default tool permissions.
Tandem lets you annotate and edit documents alongside the user in real time. The user sees your changes in the editor; you interact via the tandem_* MCP tool suite.
Guides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Guides building MCP servers enabling LLMs to interact with external services via tools. Covers best practices, TypeScript/Node (MCP SDK), Python (FastMCP).
Generates original PNG/PDF visual art via design philosophy manifestos for posters, graphics, and static designs on user request.
Tandem lets you annotate and edit documents alongside the user in real time. The user sees your changes in the editor; you interact via the tandem_* MCP tool suite.
These prevent the most common failures. Follow them always.
tandem_resolveRange (or tandem_search) to get offsets before calling tandem_edit, tandem_highlight, tandem_comment, tandem_suggest, or tandem_flag. Never compute offsets by counting characters in previously-read text — they go stale when the user edits.textSnapshot. Include the matched text as textSnapshot on mutations and annotations. If the text moved, the server returns RANGE_MOVED with relocated coordinates instead of corrupting the document.tandem_getTextContent, not tandem_getContent. getContent returns ProseMirror JSON and burns tokens. Use getTextContent({ section: "Section Name" }) for targeted reads. The section parameter is case-insensitive.tandem_edit cannot create paragraphs. Newlines become literal characters. For multi-paragraph changes, use multiple tandem_edit calls or tandem_suggest..docx files are read-only. Use annotations instead of tandem_edit. Offer tandem_convertToMarkdown if the user wants an editable copy.Standard workflow:
tandem_status — check for already-open documents (sessions restore automatically)tandem_getOutline — understand document structuretandem_setStatus("Working on [section]...", { focusParagraph: N }) — show progress (use index from outline)tandem_getTextContent({ section: "..." }) — read one section at a timetandem_checkInbox — check for user messages and actionstandem_save — persist edits to disk when doneChoose the right type for each finding:
tandem_highlight — Visual marker with a short note. Colors (full set): green (verified/good), red (problem), yellow (needs attention), blue (informational), purple (style/tone). Prefer the first three for review work; blue/purple are available when a fourth/fifth category is meaningful. Use when the finding is self-evident from the color and a brief note.tandem_comment — Observation requiring explanation. Use when you need more than one sentence to convey reasoning.tandem_suggest — Specific text replacement. Prefer over comment when you can provide replacement text — the user gets one-click accept/reject. Cannot create new paragraphs.tandem_flag — Factual errors, compliance risks, missing required content. Signals a blocking issue the user must address before the document ships.User questions to Claude. Users can author a "question" annotation in the UI. The server normalizes it to type: "comment" with directedAt: "claude" before returning it — so when scanning tandem_checkInbox or tandem_getAnnotations, match on type === "comment" && directedAt === "claude" && author === "user", not type === "question". Respond with tandem_reply for conversational answers, or a new tandem_comment on the same range for a textual annotation.
Check mode from tandem_status or tandem_checkInbox and adapt:
"tandem", default) — Full collaboration. Annotate freely and react to selections and document changes."solo") — The user wants to write undisturbed. Only respond when the user sends a chat message. Do not proactively annotate or react to document activity.Selections are not sent as standalone events. Instead, when the user sends a chat message, any buffered selection is attached as a selection field on the chat:message payload. This gives you context about what text the user was looking at when they wrote their message. When polling via tandem_checkInbox, the current selection shows up under activity.selectedText. Use tandem_reply for any document-context reaction (chat messages, question annotations); reserve terminal output for non-document work the user explicitly requests. In Solo mode, hold reactions until the user sends a chat message.
tandem_getActivity() before annotating near the user's cursor. If isTyping is true, wait for typing to stop before annotating that area.tandem_setStatus to show what you're working on — the user sees it in the editor status bar.tandem_checkInbox every 2-3 tool calls, not just at the end of a task. The real-time channel is often not connected; polling is the reliable path.tandem_reply, not annotations.tandem_open — opens in read-only mode (readOnly: true)tandem_getAnnotations({ author: "import" }) — check for imported Word comments; read and act on themtandem_exportAnnotations — generate a review summary the user can sharetandem_convertToMarkdownRANGE_MOVED — Text shifted since you read it. The response includes resolvedFrom/resolvedTo — use those coordinates for your next call.RANGE_GONE — The text was deleted. Re-read the section with tandem_getTextContent and re-assess.INVALID_RANGE — You hit heading markup (e.g., ## ). Target text content only, not the heading prefix.FORMAT_ERROR — Attempted tandem_edit on a read-only .docx. Use annotations instead.When starting a new Claude session with Tandem already running:
tandem_status() — check openDocuments array for restored sessionstandem_listDocuments() — see all open docs with detailstandem_getOutline() — orient on the active documenttandem_getAnnotations() — see what was already reviewedWhen multiple documents are open, always pass documentId explicitly — omitting it targets the active document, which may have changed since your last call. Use tandem_listDocuments to see what's available. Cross-reference by reading both docs via tandem_getTextContent({ documentId: "..." }) and annotating the relevant one.