tandem-editor 0.2.10 → 0.2.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +130 -98
- package/README.md +201 -201
- package/dist/channel/index.js +0 -0
- package/dist/channel/index.js.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/client/assets/{index-CfGlbY9B.js → index-R-RaIO5I.js} +54 -54
- package/dist/client/index.html +13 -13
- package/dist/server/index.js +291 -92
- package/dist/server/index.js.map +1 -1
- package/package.json +5 -1
- package/sample/demo-script.md +23 -23
- package/sample/welcome.md +21 -21
package/CHANGELOG.md
CHANGED
|
@@ -1,98 +1,130 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to Tandem will be documented in this file.
|
|
4
|
-
|
|
5
|
-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
-
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
-
|
|
8
|
-
## [0.2.
|
|
9
|
-
|
|
10
|
-
### Added
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
|
|
47
|
-
###
|
|
48
|
-
|
|
49
|
-
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to Tandem will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.2.12] - 2026-04-06
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Undo/redo toolbar buttons powered by Y.js UndoManager — tracks document edits with proper CRDT-aware undo scoping (#189, #210)
|
|
13
|
+
- Adjustable editor content width toggle — switch between comfortable and full-width layouts, preference persists in localStorage (#185, #205)
|
|
14
|
+
- SVG icons for unordered list, ordered list, and blockquote toolbar buttons, replacing plain text labels (#194)
|
|
15
|
+
- Automated npm publishing via GitHub Actions with OIDC trusted publisher (tokenless)
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Guard all localStorage access with try-catch for private/disabled browser storage modes; reset scroll position on annotation filter clear (#212, #202)
|
|
20
|
+
|
|
21
|
+
## [0.2.11] - 2026-04-06
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- Auto-reload documents when files change on disk — Tandem detects external edits (e.g., Claude's Edit tool) via `fs.watch`, reloads content, and preserves existing annotations (#175)
|
|
26
|
+
- File watcher module with 500ms debounce and self-write suppression (prevents reload loops when Tandem saves)
|
|
27
|
+
- Toast notification when a document is reloaded from disk
|
|
28
|
+
- Runtime warning when `onDocSwapped` callback is missing during Hocuspocus doc swap (defensive guard for #178 audit)
|
|
29
|
+
- 28 new tests: observer reattachment, CTRL_ROOM lifecycle, buffer cap, file watcher debounce/suppress, annotation-preserving reload
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- Dead CRDT `relRange` handling — `refreshRange` now strips broken CRDT anchors and re-anchors from flat offsets instead of leaving annotations permanently stuck with non-functional RelativePositions (#175)
|
|
34
|
+
- Buffer cap test was previously a no-op (empty loop body) — now actually exercises the event queue buffer (#178)
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
- CLAUDE.md gotcha for Hocuspocus doc replacement updated to document the automatic `onDocSwapped` callback lifecycle (#178)
|
|
39
|
+
|
|
40
|
+
## [0.2.10] - 2026-04-05
|
|
41
|
+
|
|
42
|
+
### Added
|
|
43
|
+
|
|
44
|
+
- Resizable side panel — drag to resize between 200–600px, width persists in localStorage
|
|
45
|
+
- Accessibility: ARIA labels on annotation highlights (type-specific), annotation cards (`role="listitem"`, `aria-current`), annotation list (`role="list"`), review mode button (`aria-pressed`), live region for pending count and review progress
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
|
|
49
|
+
- Flaky session tests — each test file now uses an isolated temp directory via `vi.mock`, eliminating cross-file race conditions (#177)
|
|
50
|
+
- Session file writes use atomic rename with retry on Windows EPERM/EACCES (#173)
|
|
51
|
+
|
|
52
|
+
### Changed
|
|
53
|
+
|
|
54
|
+
- `atomicWrite()` extracted as shared helper in session manager — consolidates duplicate write-tmp-rename logic with exponential backoff retry
|
|
55
|
+
|
|
56
|
+
## [0.2.9] - 2026-04-05
|
|
57
|
+
|
|
58
|
+
### Fixed
|
|
59
|
+
|
|
60
|
+
- Changelog tab no longer disappears after upgrade — version check and sample/welcome.md now open before servers start, preventing CRDT merge races with stale browser tabs
|
|
61
|
+
- Tutorial annotation injection errors now get their own log message instead of being misattributed as file-open failures
|
|
62
|
+
|
|
63
|
+
## [0.2.8] - 2026-04-05
|
|
64
|
+
|
|
65
|
+
### Added
|
|
66
|
+
|
|
67
|
+
- CHANGELOG.md opens as the active tab on first startup after an npm update
|
|
68
|
+
- `checkVersionChange` helper tracks version transitions via `last-seen-version` file
|
|
69
|
+
- CHANGELOG.md now ships in the npm package
|
|
70
|
+
|
|
71
|
+
## [0.2.7] - 2026-04-05
|
|
72
|
+
|
|
73
|
+
### Fixed
|
|
74
|
+
|
|
75
|
+
- Force-reload (`tandem_open` with `force: true`) now clears Y.Doc in-place instead of destroying the Hocuspocus room — sidebar, observers, and connections survive
|
|
76
|
+
- TOCTOU fix: session deletion moved after successful reload transaction
|
|
77
|
+
- Observer ownership table corrected in architecture docs
|
|
78
|
+
|
|
79
|
+
### Added
|
|
80
|
+
|
|
81
|
+
- 4 new tests for force-reload (annotation clearing, awareness clearing, .txt reload, metadata)
|
|
82
|
+
|
|
83
|
+
## [0.2.6] - 2026-04-05
|
|
84
|
+
|
|
85
|
+
### Fixed
|
|
86
|
+
|
|
87
|
+
- Demo script rewritten to be self-referential for recording
|
|
88
|
+
- Observer ownership documentation added to architecture.md
|
|
89
|
+
|
|
90
|
+
## [0.2.5] - 2026-04-05
|
|
91
|
+
|
|
92
|
+
### Fixed
|
|
93
|
+
|
|
94
|
+
- `tandem setup` Claude Code MCP config path updated
|
|
95
|
+
|
|
96
|
+
## [0.2.4] - 2026-04-05
|
|
97
|
+
|
|
98
|
+
### Fixed
|
|
99
|
+
|
|
100
|
+
- Security audit findings (DNS rebinding, CORS, input validation)
|
|
101
|
+
|
|
102
|
+
## [0.2.3] - 2026-04-05
|
|
103
|
+
|
|
104
|
+
### Fixed
|
|
105
|
+
|
|
106
|
+
- `tandem setup` now writes Claude Code MCP config to `~/.claude.json` instead of `~/.claude/mcp_settings.json`, which Claude Code no longer reads
|
|
107
|
+
|
|
108
|
+
## [0.2.2] - 2025-04-05
|
|
109
|
+
|
|
110
|
+
### Fixed
|
|
111
|
+
|
|
112
|
+
- Silent failure review findings
|
|
113
|
+
|
|
114
|
+
## [0.2.1] - 2025-04-05
|
|
115
|
+
|
|
116
|
+
### Fixed
|
|
117
|
+
|
|
118
|
+
- Full security audit — 25 findings across 7 categories (#172)
|
|
119
|
+
|
|
120
|
+
## [0.2.0] - 2025-04-04
|
|
121
|
+
|
|
122
|
+
### Added
|
|
123
|
+
|
|
124
|
+
- Initial public release on npm as `tandem-editor`
|
|
125
|
+
- 30 MCP tools for collaborative document editing
|
|
126
|
+
- Multi-document tabs with CRDT-anchored annotations
|
|
127
|
+
- Chat sidebar with real-time channel push
|
|
128
|
+
- Support for .md, .docx, .txt, .html files
|
|
129
|
+
- `tandem` CLI with `setup` and `start` commands
|
|
130
|
+
- Claude Code skill auto-installation
|
package/README.md
CHANGED
|
@@ -1,201 +1,201 @@
|
|
|
1
|
-
<p align="center">
|
|
2
|
-
<img src="docs/assets/banner.png" alt="Tandem — Collaborative AI-Human Document Editor" width="800">
|
|
3
|
-
</p>
|
|
4
|
-
|
|
5
|
-
An AI document reviewer — open a progress report, RFP, or compliance filing and Claude reviews it alongside you in real time. Highlights, comments, suggestions, and questions appear as first-class annotations you accept, dismiss, or discuss. The original file is never modified unless you save.
|
|
6
|
-
|
|
7
|
-

|
|
8
|
-
|
|
9
|
-
## Quick Start
|
|
10
|
-
|
|
11
|
-
### Prerequisites
|
|
12
|
-
|
|
13
|
-
- **Node.js 22+** ([download](https://nodejs.org))
|
|
14
|
-
- **Claude Code** (`irm https://claude.ai/install.ps1 | iex`)
|
|
15
|
-
|
|
16
|
-
### Install and Run
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
npm install -g tandem-editor
|
|
20
|
-
tandem setup # registers MCP tools + installs Claude Code skill
|
|
21
|
-
tandem # starts server + opens browser
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
`tandem setup` auto-detects Claude Code and Claude Desktop, writes MCP configuration, and installs a skill (`~/.claude/skills/tandem/SKILL.md`) that teaches Claude how to use Tandem's tools effectively. Re-run after upgrading (`npm update -g tandem-editor && tandem setup`).
|
|
25
|
-
|
|
26
|
-
### Connect Claude Code
|
|
27
|
-
|
|
28
|
-
Start Claude Code with channel push for real-time notifications:
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
claude --dangerously-load-development-channels server:tandem-channel
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Then try:
|
|
35
|
-
|
|
36
|
-
```
|
|
37
|
-
"Review the welcome document with me"
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
Claude calls `tandem_open`, the document appears in the browser, and annotations start flowing. Chat messages, annotation actions, and text selections push to Claude instantly.
|
|
41
|
-
|
|
42
|
-
**Without channels:** Use the `/loop` skill in Claude Code to poll:
|
|
43
|
-
|
|
44
|
-
```
|
|
45
|
-
/loop 30s check tandem inbox and respond to any new messages
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### Verify
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
npm run doctor # checks Node.js, MCP config, server health, ports
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
Or check the raw health endpoint:
|
|
55
|
-
|
|
56
|
-
```bash
|
|
57
|
-
curl http://localhost:3479/health
|
|
58
|
-
# → {"status":"ok","version":"0.1.2","transport":"http","hasSession":false}
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
`hasSession` becomes `true` once Claude Code connects.
|
|
62
|
-
|
|
63
|
-
<details>
|
|
64
|
-
<summary><strong>Development Setup</strong> (contributing / building from source)</summary>
|
|
65
|
-
|
|
66
|
-
```bash
|
|
67
|
-
git clone https://github.com/bloknayrb/tandem.git
|
|
68
|
-
cd tandem
|
|
69
|
-
npm install
|
|
70
|
-
npm run dev:standalone # starts server (:3478/:3479) + browser client (:5173)
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
Open http://localhost:5173 — you'll see `sample/welcome.md` loaded automatically on first run. The `.mcp.json` in the repo configures Claude Code automatically when run from this directory.
|
|
74
|
-
|
|
75
|
-
</details>
|
|
76
|
-
|
|
77
|
-
## Features
|
|
78
|
-
|
|
79
|
-
### Annotations
|
|
80
|
-
|
|
81
|
-

|
|
82
|
-
|
|
83
|
-
Claude adds highlights, comments, suggestions, and flags directly in the document. The side panel lists all annotations with filtering by type, author, and status. Accept, dismiss, or edit each one individually — or use bulk actions to process them in batches.
|
|
84
|
-
|
|
85
|
-
### Chat
|
|
86
|
-
|
|
87
|
-

|
|
88
|
-
|
|
89
|
-
Send freeform messages to Claude alongside annotation review. Select text before sending to attach it as a clickable anchor — clicking it later scrolls back to that passage.
|
|
90
|
-
|
|
91
|
-
### Review Mode
|
|
92
|
-
|
|
93
|
-

|
|
94
|
-
|
|
95
|
-
Press **Ctrl+Shift+R** to enter keyboard review mode. Navigate with **Tab**, accept with **Y**, dismiss with **N**, examine with **E**. A 10-second undo window lets you reverse accidental accepts. The side panel tracks your position.
|
|
96
|
-
|
|
97
|
-
### More
|
|
98
|
-
|
|
99
|
-
- **Multi-document tabs** — open `.md`, `.txt`, `.docx` files side by side; drag to reorder
|
|
100
|
-
- **.docx review-only mode** — open Word documents for annotation; imported Word comments appear alongside Claude's
|
|
101
|
-
- **Session persistence** — documents and annotations survive server restarts
|
|
102
|
-
- **Real-time channel push** — annotation actions, chat, and selections push to Claude instantly
|
|
103
|
-
- **Keyboard shortcuts** — press `?` for the full reference
|
|
104
|
-
- **Unsaved-changes indicator** — dot on tab title when a document has pending edits
|
|
105
|
-
- **Configurable display name** — set your name so Claude knows who's reviewing
|
|
106
|
-
- **Atomic file saves** — write to temp, then rename, preventing partial writes
|
|
107
|
-
- **E2E tested** — Playwright tests cover the annotation lifecycle end-to-end
|
|
108
|
-
|
|
109
|
-
## Documentation
|
|
110
|
-
|
|
111
|
-
- **[User Guide](docs/user-guide.md)** — How to use Tandem: browser UI, annotations, chat, review mode, keyboard shortcuts
|
|
112
|
-
- [MCP Tool Reference](docs/mcp-tools.md) — 30 MCP tools + channel API endpoints
|
|
113
|
-
- [Architecture](docs/architecture.md) — System design, data flows, coordinate systems, channel push
|
|
114
|
-
- [Workflows](docs/workflows.md) — Claude Code usage patterns: document review, cross-referencing, multi-model
|
|
115
|
-
- [Roadmap](docs/roadmap.md) — Phase 2+ roadmap, known issues, future extensions
|
|
116
|
-
- [Design Decisions](docs/decisions.md) — ADR-001 through ADR-021
|
|
117
|
-
- [Lessons Learned](docs/lessons-learned.md) — 31 implementation lessons
|
|
118
|
-
|
|
119
|
-
## CLI Commands
|
|
120
|
-
|
|
121
|
-
| Command | What it does |
|
|
122
|
-
|---------|-------------|
|
|
123
|
-
| `tandem` | Start server and open browser (global install) |
|
|
124
|
-
| `tandem setup` | Register MCP tools with Claude Code / Claude Desktop |
|
|
125
|
-
| `tandem setup --force` | Register to default paths regardless of auto-detection |
|
|
126
|
-
| `tandem --version` | Show installed version |
|
|
127
|
-
| `tandem --help` | Show usage |
|
|
128
|
-
|
|
129
|
-
## MCP Configuration
|
|
130
|
-
|
|
131
|
-
Tandem uses two MCP connections: **HTTP** for document tools (28 tools including annotation editing), and a **channel shim** for real-time push notifications.
|
|
132
|
-
|
|
133
|
-
**Global install** (`tandem setup`): Automatically writes both entries to `~/.claude/mcp_settings.json` (Claude Code) and/or `claude_desktop_config.json` (Claude Desktop) with absolute paths. No manual configuration needed.
|
|
134
|
-
|
|
135
|
-
**Development setup** (`.mcp.json`): The repo includes a `.mcp.json` that configures both entries automatically when Claude Code runs from the repo directory:
|
|
136
|
-
|
|
137
|
-
```json
|
|
138
|
-
{
|
|
139
|
-
"mcpServers": {
|
|
140
|
-
"tandem": {
|
|
141
|
-
"type": "http",
|
|
142
|
-
"url": "http://localhost:3479/mcp"
|
|
143
|
-
},
|
|
144
|
-
"tandem-channel": {
|
|
145
|
-
"command": "npx",
|
|
146
|
-
"args": ["tsx", "src/channel/index.ts"],
|
|
147
|
-
"env": { "TANDEM_URL": "http://localhost:3479" }
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
Both entries are cross-platform — no platform-specific configuration needed.
|
|
154
|
-
|
|
155
|
-
## Environment Variables
|
|
156
|
-
|
|
157
|
-
All optional — defaults work out of the box.
|
|
158
|
-
|
|
159
|
-
| Variable | Default | Description |
|
|
160
|
-
|----------|---------|-------------|
|
|
161
|
-
| `TANDEM_PORT` | `3478` | Hocuspocus WebSocket port |
|
|
162
|
-
| `TANDEM_MCP_PORT` | `3479` | MCP HTTP + REST API port |
|
|
163
|
-
| `TANDEM_URL` | `http://localhost:3479` | Channel shim server URL |
|
|
164
|
-
| `TANDEM_TRANSPORT` | `http` | Transport mode (`http` or `stdio`) |
|
|
165
|
-
| `TANDEM_NO_SAMPLE` | unset | Set to `1` to skip auto-opening `sample/welcome.md` |
|
|
166
|
-
| `TANDEM_CLAUDE_CMD` | `claude` | Claude Code executable name (for `tandem setup` auto-detection) |
|
|
167
|
-
|
|
168
|
-
See `.env.example` for a copy-paste template.
|
|
169
|
-
|
|
170
|
-
## Troubleshooting
|
|
171
|
-
|
|
172
|
-
Run `npm run doctor` for a quick diagnostic of your setup. It checks Node.js version, `.mcp.json` config, server health, and port status.
|
|
173
|
-
|
|
174
|
-
**Claude Code says "MCP failed to connect"**
|
|
175
|
-
Start the server first (`tandem` for global install, or `npm run dev:standalone` for dev setup), then open Claude Code. The server must be running before Claude Code probes the MCP URL. If you restart the server, run `/mcp` in Claude Code to reconnect.
|
|
176
|
-
|
|
177
|
-
**Port already in use**
|
|
178
|
-
Tandem kills stale processes on :3478/:3479 at startup. If another app uses those ports, set `TANDEM_PORT` / `TANDEM_MCP_PORT` to different values and update `TANDEM_URL` to match.
|
|
179
|
-
|
|
180
|
-
**Channel shim fails to start**
|
|
181
|
-
The `tandem-channel` entry spawns a subprocess. For global installs, `tandem setup` writes absolute paths to the bundled `dist/channel/index.js` — re-run `tandem setup` after upgrading. For dev setup, if you see `MODULE_NOT_FOUND` with a production config (`node dist/channel/index.js`), run `npm run build`. The default dev config uses `npx tsx` and doesn't require a build step.
|
|
182
|
-
|
|
183
|
-
**Browser shows "Cannot reach the Tandem server"**
|
|
184
|
-
The browser connects to the server via WebSocket. For global installs, run `tandem` to start the server. For dev setup, use `npm run dev:standalone` (or `npm run dev:server`). The message appears after 3 seconds of failed connection.
|
|
185
|
-
|
|
186
|
-
**Empty browser with no document**
|
|
187
|
-
On first run, `sample/welcome.md` auto-opens. If you've cleared sessions or deleted the sample file, click the **+** button in the tab bar or drop a file onto the editor.
|
|
188
|
-
|
|
189
|
-
## Development
|
|
190
|
-
|
|
191
|
-
| Command | What it does |
|
|
192
|
-
|---------|-------------|
|
|
193
|
-
| `npm run dev:standalone` | **Recommended** — both frontend + backend (via concurrently) |
|
|
194
|
-
| `npm run dev:server` | Backend only: Hocuspocus (:3478) + MCP HTTP (:3479) |
|
|
195
|
-
| `npm run dev:client` | Frontend only: Vite dev server (:5173) |
|
|
196
|
-
| `npm run build` | Production build (`dist/server/` + `dist/channel/` + `dist/cli/` + `dist/client/`) |
|
|
197
|
-
| `npm test` | Run vitest (unit tests) |
|
|
198
|
-
| `npm run test:e2e` | Run Playwright E2E tests |
|
|
199
|
-
| `npm run test:e2e:ui` | Playwright UI mode |
|
|
200
|
-
|
|
201
|
-
**Tech Stack:** React 19, Tiptap, Vite, TypeScript | Node.js, Hocuspocus (Yjs WebSocket), MCP SDK, Express | Yjs (CRDT), y-prosemirror | mammoth.js (.docx), unified/remark (.md)
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/assets/banner.png" alt="Tandem — Collaborative AI-Human Document Editor" width="800">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
An AI document reviewer — open a progress report, RFP, or compliance filing and Claude reviews it alongside you in real time. Highlights, comments, suggestions, and questions appear as first-class annotations you accept, dismiss, or discuss. The original file is never modified unless you save.
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
## Quick Start
|
|
10
|
+
|
|
11
|
+
### Prerequisites
|
|
12
|
+
|
|
13
|
+
- **Node.js 22+** ([download](https://nodejs.org))
|
|
14
|
+
- **Claude Code** (`irm https://claude.ai/install.ps1 | iex`)
|
|
15
|
+
|
|
16
|
+
### Install and Run
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install -g tandem-editor
|
|
20
|
+
tandem setup # registers MCP tools + installs Claude Code skill
|
|
21
|
+
tandem # starts server + opens browser
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`tandem setup` auto-detects Claude Code and Claude Desktop, writes MCP configuration, and installs a skill (`~/.claude/skills/tandem/SKILL.md`) that teaches Claude how to use Tandem's tools effectively. Re-run after upgrading (`npm update -g tandem-editor && tandem setup`).
|
|
25
|
+
|
|
26
|
+
### Connect Claude Code
|
|
27
|
+
|
|
28
|
+
Start Claude Code with channel push for real-time notifications:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
claude --dangerously-load-development-channels server:tandem-channel
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Then try:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
"Review the welcome document with me"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Claude calls `tandem_open`, the document appears in the browser, and annotations start flowing. Chat messages, annotation actions, and text selections push to Claude instantly.
|
|
41
|
+
|
|
42
|
+
**Without channels:** Use the `/loop` skill in Claude Code to poll:
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
/loop 30s check tandem inbox and respond to any new messages
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Verify
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm run doctor # checks Node.js, MCP config, server health, ports
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Or check the raw health endpoint:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
curl http://localhost:3479/health
|
|
58
|
+
# → {"status":"ok","version":"0.1.2","transport":"http","hasSession":false}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`hasSession` becomes `true` once Claude Code connects.
|
|
62
|
+
|
|
63
|
+
<details>
|
|
64
|
+
<summary><strong>Development Setup</strong> (contributing / building from source)</summary>
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
git clone https://github.com/bloknayrb/tandem.git
|
|
68
|
+
cd tandem
|
|
69
|
+
npm install
|
|
70
|
+
npm run dev:standalone # starts server (:3478/:3479) + browser client (:5173)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Open http://localhost:5173 — you'll see `sample/welcome.md` loaded automatically on first run. The `.mcp.json` in the repo configures Claude Code automatically when run from this directory.
|
|
74
|
+
|
|
75
|
+
</details>
|
|
76
|
+
|
|
77
|
+
## Features
|
|
78
|
+
|
|
79
|
+
### Annotations
|
|
80
|
+
|
|
81
|
+

|
|
82
|
+
|
|
83
|
+
Claude adds highlights, comments, suggestions, and flags directly in the document. The side panel lists all annotations with filtering by type, author, and status. Accept, dismiss, or edit each one individually — or use bulk actions to process them in batches.
|
|
84
|
+
|
|
85
|
+
### Chat
|
|
86
|
+
|
|
87
|
+

|
|
88
|
+
|
|
89
|
+
Send freeform messages to Claude alongside annotation review. Select text before sending to attach it as a clickable anchor — clicking it later scrolls back to that passage.
|
|
90
|
+
|
|
91
|
+
### Review Mode
|
|
92
|
+
|
|
93
|
+

|
|
94
|
+
|
|
95
|
+
Press **Ctrl+Shift+R** to enter keyboard review mode. Navigate with **Tab**, accept with **Y**, dismiss with **N**, examine with **E**. A 10-second undo window lets you reverse accidental accepts. The side panel tracks your position.
|
|
96
|
+
|
|
97
|
+
### More
|
|
98
|
+
|
|
99
|
+
- **Multi-document tabs** — open `.md`, `.txt`, `.docx` files side by side; drag to reorder
|
|
100
|
+
- **.docx review-only mode** — open Word documents for annotation; imported Word comments appear alongside Claude's
|
|
101
|
+
- **Session persistence** — documents and annotations survive server restarts
|
|
102
|
+
- **Real-time channel push** — annotation actions, chat, and selections push to Claude instantly
|
|
103
|
+
- **Keyboard shortcuts** — press `?` for the full reference
|
|
104
|
+
- **Unsaved-changes indicator** — dot on tab title when a document has pending edits
|
|
105
|
+
- **Configurable display name** — set your name so Claude knows who's reviewing
|
|
106
|
+
- **Atomic file saves** — write to temp, then rename, preventing partial writes
|
|
107
|
+
- **E2E tested** — Playwright tests cover the annotation lifecycle end-to-end
|
|
108
|
+
|
|
109
|
+
## Documentation
|
|
110
|
+
|
|
111
|
+
- **[User Guide](docs/user-guide.md)** — How to use Tandem: browser UI, annotations, chat, review mode, keyboard shortcuts
|
|
112
|
+
- [MCP Tool Reference](docs/mcp-tools.md) — 30 MCP tools + channel API endpoints
|
|
113
|
+
- [Architecture](docs/architecture.md) — System design, data flows, coordinate systems, channel push
|
|
114
|
+
- [Workflows](docs/workflows.md) — Claude Code usage patterns: document review, cross-referencing, multi-model
|
|
115
|
+
- [Roadmap](docs/roadmap.md) — Phase 2+ roadmap, known issues, future extensions
|
|
116
|
+
- [Design Decisions](docs/decisions.md) — ADR-001 through ADR-021
|
|
117
|
+
- [Lessons Learned](docs/lessons-learned.md) — 31 implementation lessons
|
|
118
|
+
|
|
119
|
+
## CLI Commands
|
|
120
|
+
|
|
121
|
+
| Command | What it does |
|
|
122
|
+
|---------|-------------|
|
|
123
|
+
| `tandem` | Start server and open browser (global install) |
|
|
124
|
+
| `tandem setup` | Register MCP tools with Claude Code / Claude Desktop |
|
|
125
|
+
| `tandem setup --force` | Register to default paths regardless of auto-detection |
|
|
126
|
+
| `tandem --version` | Show installed version |
|
|
127
|
+
| `tandem --help` | Show usage |
|
|
128
|
+
|
|
129
|
+
## MCP Configuration
|
|
130
|
+
|
|
131
|
+
Tandem uses two MCP connections: **HTTP** for document tools (28 tools including annotation editing), and a **channel shim** for real-time push notifications.
|
|
132
|
+
|
|
133
|
+
**Global install** (`tandem setup`): Automatically writes both entries to `~/.claude/mcp_settings.json` (Claude Code) and/or `claude_desktop_config.json` (Claude Desktop) with absolute paths. No manual configuration needed.
|
|
134
|
+
|
|
135
|
+
**Development setup** (`.mcp.json`): The repo includes a `.mcp.json` that configures both entries automatically when Claude Code runs from the repo directory:
|
|
136
|
+
|
|
137
|
+
```json
|
|
138
|
+
{
|
|
139
|
+
"mcpServers": {
|
|
140
|
+
"tandem": {
|
|
141
|
+
"type": "http",
|
|
142
|
+
"url": "http://localhost:3479/mcp"
|
|
143
|
+
},
|
|
144
|
+
"tandem-channel": {
|
|
145
|
+
"command": "npx",
|
|
146
|
+
"args": ["tsx", "src/channel/index.ts"],
|
|
147
|
+
"env": { "TANDEM_URL": "http://localhost:3479" }
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Both entries are cross-platform — no platform-specific configuration needed.
|
|
154
|
+
|
|
155
|
+
## Environment Variables
|
|
156
|
+
|
|
157
|
+
All optional — defaults work out of the box.
|
|
158
|
+
|
|
159
|
+
| Variable | Default | Description |
|
|
160
|
+
|----------|---------|-------------|
|
|
161
|
+
| `TANDEM_PORT` | `3478` | Hocuspocus WebSocket port |
|
|
162
|
+
| `TANDEM_MCP_PORT` | `3479` | MCP HTTP + REST API port |
|
|
163
|
+
| `TANDEM_URL` | `http://localhost:3479` | Channel shim server URL |
|
|
164
|
+
| `TANDEM_TRANSPORT` | `http` | Transport mode (`http` or `stdio`) |
|
|
165
|
+
| `TANDEM_NO_SAMPLE` | unset | Set to `1` to skip auto-opening `sample/welcome.md` |
|
|
166
|
+
| `TANDEM_CLAUDE_CMD` | `claude` | Claude Code executable name (for `tandem setup` auto-detection) |
|
|
167
|
+
|
|
168
|
+
See `.env.example` for a copy-paste template.
|
|
169
|
+
|
|
170
|
+
## Troubleshooting
|
|
171
|
+
|
|
172
|
+
Run `npm run doctor` for a quick diagnostic of your setup. It checks Node.js version, `.mcp.json` config, server health, and port status.
|
|
173
|
+
|
|
174
|
+
**Claude Code says "MCP failed to connect"**
|
|
175
|
+
Start the server first (`tandem` for global install, or `npm run dev:standalone` for dev setup), then open Claude Code. The server must be running before Claude Code probes the MCP URL. If you restart the server, run `/mcp` in Claude Code to reconnect.
|
|
176
|
+
|
|
177
|
+
**Port already in use**
|
|
178
|
+
Tandem kills stale processes on :3478/:3479 at startup. If another app uses those ports, set `TANDEM_PORT` / `TANDEM_MCP_PORT` to different values and update `TANDEM_URL` to match.
|
|
179
|
+
|
|
180
|
+
**Channel shim fails to start**
|
|
181
|
+
The `tandem-channel` entry spawns a subprocess. For global installs, `tandem setup` writes absolute paths to the bundled `dist/channel/index.js` — re-run `tandem setup` after upgrading. For dev setup, if you see `MODULE_NOT_FOUND` with a production config (`node dist/channel/index.js`), run `npm run build`. The default dev config uses `npx tsx` and doesn't require a build step.
|
|
182
|
+
|
|
183
|
+
**Browser shows "Cannot reach the Tandem server"**
|
|
184
|
+
The browser connects to the server via WebSocket. For global installs, run `tandem` to start the server. For dev setup, use `npm run dev:standalone` (or `npm run dev:server`). The message appears after 3 seconds of failed connection.
|
|
185
|
+
|
|
186
|
+
**Empty browser with no document**
|
|
187
|
+
On first run, `sample/welcome.md` auto-opens. If you've cleared sessions or deleted the sample file, click the **+** button in the tab bar or drop a file onto the editor.
|
|
188
|
+
|
|
189
|
+
## Development
|
|
190
|
+
|
|
191
|
+
| Command | What it does |
|
|
192
|
+
|---------|-------------|
|
|
193
|
+
| `npm run dev:standalone` | **Recommended** — both frontend + backend (via concurrently) |
|
|
194
|
+
| `npm run dev:server` | Backend only: Hocuspocus (:3478) + MCP HTTP (:3479) |
|
|
195
|
+
| `npm run dev:client` | Frontend only: Vite dev server (:5173) |
|
|
196
|
+
| `npm run build` | Production build (`dist/server/` + `dist/channel/` + `dist/cli/` + `dist/client/`) |
|
|
197
|
+
| `npm test` | Run vitest (unit tests) |
|
|
198
|
+
| `npm run test:e2e` | Run Playwright E2E tests |
|
|
199
|
+
| `npm run test:e2e:ui` | Playwright UI mode |
|
|
200
|
+
|
|
201
|
+
**Tech Stack:** React 19, Tiptap, Vite, TypeScript | Node.js, Hocuspocus (Yjs WebSocket), MCP SDK, Express | Yjs (CRDT), y-prosemirror | mammoth.js (.docx), unified/remark (.md)
|
package/dist/channel/index.js
CHANGED
|
File without changes
|