---
name: tandem
description: >
  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.
---

# Tandem — Collaborative Document Editor

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.

## Hard Rules

These prevent the most common failures. Follow them always.

1. **Resolve before mutating.** Call `tandem_resolveRange` (or `tandem_search`) to get offsets before calling `tandem_edit` or `tandem_comment`. Never compute offsets by counting characters in previously-read text — they go stale when the user edits.
2. **Pass `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.
3. **Use `tandem_getTextContent` for document reads.** Use `getTextContent({ section: "Section Name" })` for targeted reads. The `section` parameter is case-insensitive.
4. **`tandem_edit` cannot create paragraphs.** Newlines become literal characters. For multi-paragraph changes, use multiple `tandem_edit` calls or `tandem_comment` with `suggestedText`.
5. **`.docx` files are read-only.** Use annotations instead of `tandem_edit`. Offer `tandem_convertToMarkdown` if the user wants an editable copy.

## Workflow

Standard workflow:

1. `tandem_status` — check for already-open documents (sessions restore automatically)
2. `tandem_getOutline` — understand document structure
3. `tandem_status({ text: "Working on [section]...", focusParagraph: N })` — show progress (use `index` from outline)
4. `tandem_getTextContent({ section: "..." })` — read one section at a time
5. Annotate or edit as needed (see annotation guide below)
6. `tandem_checkInbox` — check for user messages and actions
7. Repeat steps 3-6 for each section
8. `tandem_save` — persist edits to disk when done

## Annotation Guide

Choose the right type for each finding:

- **`tandem_comment`** — Observation or question. Use for any finding that needs explanation or a text replacement.
- **`tandem_comment` with `suggestedText`** — Specific text replacement. **Prefer when you can provide replacement text** — the user gets one-click accept/reject. Cannot create new paragraphs. Pass replacement text as `suggestedText`; the comment text explains the reason.

**Note annotations** (`type: "note"`) are user-personal — `tandem_checkInbox` does not surface them to you. Don't act on notes unless the user explicitly mentions one in chat. Highlights are also user-only; `tandem_highlight` is deprecated and returns an error.

**User comments.** When scanning `tandem_checkInbox` or `tandem_getAnnotations`, user-authored `type: "comment"` annotations are the ones you should respond to. Respond with `tandem_reply` for conversational answers, or a new `tandem_comment` on the same range for a textual annotation.

## Collaboration Mode

Check `mode` from `tandem_status` or `tandem_checkInbox` and adapt:

- **Tandem** (`"tandem"`, default) — Full collaboration. Annotate freely and react to selections and document changes.
- **Solo** (`"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.

## Reacting to Document Events

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.

## Collaboration Etiquette

- Check `tandem_getActivity()` before annotating near the user's cursor. If `isTyping` is true, wait for typing to stop before annotating that area.
- Use `tandem_status({ text: "..." })` to show what you're working on — the user sees it in the editor status bar.
- **Call `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.
- Reply to chat messages with `tandem_reply`, not annotations.

## .docx Review Workflow

1. `tandem_open` — opens in read-only mode (`readOnly: true`)
2. `tandem_getAnnotations({ author: "import" })` — check for imported Word comments; read and act on them
3. Annotate with findings (comment, comment with suggestedText)
4. `tandem_exportAnnotations` — generate a review summary the user can share
5. If the user wants editable text, offer `tandem_convertToMarkdown`

## Error Recovery

- **`RANGE_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.

## Session Handoff

When starting a new Claude session with Tandem already running:

1. `tandem_status()` — check `openDocuments` array for restored sessions
2. `tandem_listDocuments()` — see all open docs with details
3. `tandem_getOutline()` — orient on the active document
4. `tandem_getAnnotations()` — see what was already reviewed
5. Continue where the previous session left off

## Multi-Document

When 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.
