openwriter 0.5.2 → 0.5.4
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/dist/bin/pad.js +66 -9
- package/dist/client/assets/index-BAbqg4Q8.js +210 -0
- package/dist/client/assets/index-BR_sMmFf.css +1 -0
- package/dist/client/index.html +2 -2
- package/dist/server/compact.js +30 -1
- package/dist/server/documents.js +266 -1
- package/dist/server/index.js +62 -21
- package/dist/server/mcp.js +213 -57
- package/dist/server/state.js +4 -1
- package/package.json +2 -1
- package/skill/SKILL.md +61 -40
- package/dist/client/assets/index-BEDioWIU.js +0 -208
- package/dist/client/assets/index-BsHE9tXC.css +0 -1
package/skill/SKILL.md
CHANGED
|
@@ -14,7 +14,7 @@ description: |
|
|
|
14
14
|
Requires: OpenWriter MCP server configured. Browser UI at localhost:5050.
|
|
15
15
|
metadata:
|
|
16
16
|
author: travsteward
|
|
17
|
-
version: "0.
|
|
17
|
+
version: "0.1.0"
|
|
18
18
|
repository: https://github.com/travsteward/openwriter
|
|
19
19
|
license: MIT
|
|
20
20
|
---
|
|
@@ -23,6 +23,12 @@ license: MIT
|
|
|
23
23
|
|
|
24
24
|
You are a writing collaborator. You read documents and make edits **exclusively via MCP tools**. Edits appear as pending decorations (colored highlights) in the user's browser that they accept or reject.
|
|
25
25
|
|
|
26
|
+
## FIRM RULES
|
|
27
|
+
|
|
28
|
+
1. **ALWAYS write content in the editor, never in the terminal.** OpenWriter is a collaborative writing surface. All content — drafts, rewrites, brainstorms, outlines — goes on the pad via `write_to_pad` or `populate_document`. Dumping content into the chat/terminal is bad UX: it's hard to read, ugly, and the user can't accept/reject or iterate on it. If you're generating text the user will read, it goes in the editor.
|
|
29
|
+
2. **The terminal is for discussion only.** Use chat messages to explain your edits, ask questions, discuss direction, or summarize what you changed. Never use it as the writing surface.
|
|
30
|
+
3. **Name every document.** When you encounter a generically named doc ("Quote Tweet", "Article", "Untitled", etc.), rename it based on its content before proceeding. Titles are the human scanning layer — a sidebar full of "Quote Tweet" is useless. Use `rename_item` with the docId. Short, descriptive titles: "Venezuela Proxy States QT", "Feature Blindness Article".
|
|
31
|
+
|
|
26
32
|
## Setup — Which Path?
|
|
27
33
|
|
|
28
34
|
Check whether the `openwriter` MCP tools are available (e.g. `read_pad`, `write_to_pad`). This determines setup state:
|
|
@@ -73,29 +79,37 @@ After editing, tell the user:
|
|
|
73
79
|
|
|
74
80
|
**Note:** You cannot run `claude mcp add` from inside a session (nested session error). That's why we edit the JSON directly when configuring from within Claude Code. Also, `claude mcp add` appends to the end — always verify the entry is first after adding.
|
|
75
81
|
|
|
82
|
+
## Document Identity: Titles vs DocIds
|
|
83
|
+
|
|
84
|
+
Every document has an immutable **docId** (8-char hex, e.g. `a1b2c3d4`) in its YAML frontmatter. Titles are for human communication and agent reasoning. DocIds are for agent action.
|
|
85
|
+
|
|
86
|
+
- `list_documents` and `read_pad` always show both title and docId
|
|
87
|
+
- All doc-targeting tools take `docId` as their parameter (not filename)
|
|
88
|
+
- Two documents can have the same title — the docId disambiguates
|
|
89
|
+
|
|
76
90
|
## MCP Tools Reference (32 tools)
|
|
77
91
|
|
|
78
92
|
### Document Operations
|
|
79
93
|
|
|
80
|
-
| Tool | Description |
|
|
81
|
-
|
|
82
|
-
| `read_pad` | Read the current document (compact tagged-line format) |
|
|
83
|
-
| `write_to_pad` | Apply edits as pending decorations (rewrite, insert, delete) |
|
|
84
|
-
| `populate_document` | Populate an empty doc with content (two-step creation flow) |
|
|
85
|
-
| `get_pad_status` | Lightweight poll: word count, pending changes, userSignaledReview |
|
|
86
|
-
| `get_nodes` | Fetch specific nodes by ID |
|
|
87
|
-
| `get_metadata` | Get frontmatter metadata for the active document |
|
|
88
|
-
| `set_metadata` | Update frontmatter metadata (merge, set key to null to remove) |
|
|
94
|
+
| Tool | Key Params | Description |
|
|
95
|
+
|------|-----------|-------------|
|
|
96
|
+
| `read_pad` | — | Read the current document (compact tagged-line format with `id:` in header) |
|
|
97
|
+
| `write_to_pad` | `docId`, `changes` | Apply edits as pending decorations (rewrite, insert, delete) |
|
|
98
|
+
| `populate_document` | `docId?`, `content` | Populate an empty doc with content (two-step creation flow) |
|
|
99
|
+
| `get_pad_status` | — | Lightweight poll: word count, pending changes, userSignaledReview |
|
|
100
|
+
| `get_nodes` | `nodeIds` | Fetch specific nodes by ID |
|
|
101
|
+
| `get_metadata` | — | Get frontmatter metadata for the active document |
|
|
102
|
+
| `set_metadata` | `metadata` | Update frontmatter metadata (merge, set key to null to remove) |
|
|
89
103
|
|
|
90
104
|
### Document Lifecycle
|
|
91
105
|
|
|
92
|
-
| Tool | Description |
|
|
93
|
-
|
|
94
|
-
| `list_documents` | List all documents with
|
|
95
|
-
| `switch_document` | Switch to a different document by
|
|
96
|
-
| `create_document` | Create a new empty document
|
|
97
|
-
| `open_file` | Open an existing .md file from any location on disk |
|
|
98
|
-
| `delete_document` | Delete a document file (moves to OS trash, recoverable) |
|
|
106
|
+
| Tool | Key Params | Description |
|
|
107
|
+
|------|-----------|-------------|
|
|
108
|
+
| `list_documents` | — | List all documents with title, docId, word count, active status |
|
|
109
|
+
| `switch_document` | `docId` | Switch to a different document by docId |
|
|
110
|
+
| `create_document` | `title?`, ... | Create a new empty document — response includes docId |
|
|
111
|
+
| `open_file` | `path` | Open an existing .md file from any location on disk |
|
|
112
|
+
| `delete_document` | `docId` | Delete a document file (moves to OS trash, recoverable) |
|
|
99
113
|
|
|
100
114
|
### Import
|
|
101
115
|
|
|
@@ -127,16 +141,16 @@ After editing, tell the user:
|
|
|
127
141
|
|
|
128
142
|
### Agent Marks
|
|
129
143
|
|
|
130
|
-
| Tool | Description |
|
|
131
|
-
|
|
132
|
-
| `get_agent_marks` | Get inline feedback marks left by the user (optional
|
|
133
|
-
| `resolve_agent_marks` | Remove marks after addressing feedback (pass mark IDs) |
|
|
144
|
+
| Tool | Key Params | Description |
|
|
145
|
+
|------|-----------|-------------|
|
|
146
|
+
| `get_agent_marks` | `docId?` | Get inline feedback marks left by the user (optional docId — omit for all docs) |
|
|
147
|
+
| `resolve_agent_marks` | `mark_ids` | Remove marks after addressing feedback (pass mark IDs) |
|
|
134
148
|
|
|
135
149
|
### Text Operations
|
|
136
150
|
|
|
137
|
-
| Tool | Description |
|
|
138
|
-
|
|
139
|
-
| `edit_text` | Fine-grained text edits within a node (find/replace, add/remove marks) |
|
|
151
|
+
| Tool | Key Params | Description |
|
|
152
|
+
|------|-----------|-------------|
|
|
153
|
+
| `edit_text` | `docId`, `nodeId`, `edits` | Fine-grained text edits within a node (find/replace, add/remove marks) |
|
|
140
154
|
|
|
141
155
|
### Image Generation
|
|
142
156
|
|
|
@@ -161,7 +175,7 @@ OpenWriter has two distinct modes: **editing** existing documents and **creating
|
|
|
161
175
|
|
|
162
176
|
For making changes to existing documents — rewrites, insertions, deletions:
|
|
163
177
|
|
|
164
|
-
- Use `write_to_pad` for all edits — **`
|
|
178
|
+
- Use `write_to_pad` for all edits — **`docId` is required** (8-char hex from `list_documents` or `read_pad`)
|
|
165
179
|
- Send **3-8 changes per call** for a responsive, streaming feel
|
|
166
180
|
- Always `read_pad` before editing to get fresh node IDs
|
|
167
181
|
- Respect `pendingChanges > 0` — wait for the user to accept/reject before sending more
|
|
@@ -209,39 +223,42 @@ This eliminates the need for separate `create_workspace`, `create_container`, an
|
|
|
209
223
|
|
|
210
224
|
```
|
|
211
225
|
1. get_pad_status → check pendingChanges and userSignaledReview
|
|
212
|
-
2. read_pad → get full document with node IDs
|
|
213
|
-
3. write_to_pad({
|
|
226
|
+
2. read_pad → get full document with node IDs + docId
|
|
227
|
+
3. write_to_pad({ docId: "a1b2c3d4", changes: [...] })
|
|
214
228
|
4. Wait → user accepts/rejects in browser
|
|
215
229
|
```
|
|
216
230
|
|
|
217
231
|
### Multi-document
|
|
218
232
|
|
|
219
233
|
```
|
|
220
|
-
1. list_documents → see all docs
|
|
221
|
-
2. read_pad → read active doc (or switch_document first)
|
|
222
|
-
3. write_to_pad({
|
|
223
|
-
→ edits go to the
|
|
234
|
+
1. list_documents → see all docs with title + [docId]
|
|
235
|
+
2. read_pad → read active doc (or switch_document({ docId }) first)
|
|
236
|
+
3. write_to_pad({ docId: "e5f6a7b8", changes: [...] })
|
|
237
|
+
→ edits go to the identified doc, no view switch needed
|
|
224
238
|
```
|
|
225
239
|
|
|
226
240
|
### Creating new content (two-step)
|
|
227
241
|
|
|
228
242
|
```
|
|
229
243
|
1. create_document({ title: "My Doc", workspace: "Project", container: "Chapters" })
|
|
230
|
-
→
|
|
231
|
-
2. populate_document({ content: "# ..." })
|
|
232
|
-
|
|
233
|
-
|
|
244
|
+
→ returns docId "a1b2c3d4", spinner appears
|
|
245
|
+
2. populate_document({ docId: "a1b2c3d4", content: "# ..." })
|
|
246
|
+
→ content delivered, spinner clears
|
|
247
|
+
3. read_pad → get node IDs + docId if further edits needed
|
|
248
|
+
4. write_to_pad({ docId: "a1b2c3d4", ... }) → refine with edits
|
|
234
249
|
```
|
|
235
250
|
|
|
236
251
|
### Building a workspace (multiple docs)
|
|
237
252
|
|
|
238
253
|
```
|
|
239
254
|
1. create_document({ title: "Ch 1", workspace: "My Book", container: "Chapters" })
|
|
240
|
-
|
|
255
|
+
→ returns docId "ch1docid"
|
|
256
|
+
2. populate_document({ docId: "ch1docid", content: "..." })
|
|
241
257
|
3. create_document({ title: "Ch 2", workspace: "My Book", container: "Chapters" })
|
|
242
|
-
|
|
258
|
+
→ returns docId "ch2docid"
|
|
259
|
+
4. populate_document({ docId: "ch2docid", content: "..." })
|
|
243
260
|
5. create_document({ title: "Character Bible", workspace: "My Book", container: "References" })
|
|
244
|
-
6. populate_document({ content: "..." })
|
|
261
|
+
6. populate_document({ docId: "<from step 5>", content: "..." })
|
|
245
262
|
7. tag_doc + update_workspace_context → organize and add context
|
|
246
263
|
```
|
|
247
264
|
|
|
@@ -253,8 +270,8 @@ Users can select text in the browser, right-click, and leave an "Agent Mark" —
|
|
|
253
270
|
|
|
254
271
|
```
|
|
255
272
|
1. User says "check my marks" (or you see the hint in read_pad output)
|
|
256
|
-
2. get_agent_marks → all marks across all docs, grouped by
|
|
257
|
-
3. Address each mark → rewrite, insert, delete via write_to_pad
|
|
273
|
+
2. get_agent_marks → all marks across all docs, grouped by document
|
|
274
|
+
3. Address each mark → rewrite, insert, delete via write_to_pad (use docId)
|
|
258
275
|
4. resolve_agent_marks([ids]) → clears decorations in browser
|
|
259
276
|
```
|
|
260
277
|
|
|
@@ -357,6 +374,8 @@ Users set their X handle by clicking the avatar circle in the compose area. The
|
|
|
357
374
|
|
|
358
375
|
**MCP tools not available** — The OpenWriter MCP server isn't configured yet. Follow the [setup instructions](#mcp-tools-are-not-available-skill-first-install) above. After adding the MCP config, the user must restart their Claude Code session.
|
|
359
376
|
|
|
377
|
+
**Browser dies mid-session** — The MCP stdio pipe can break during context compaction or session resets. The HTTP server survives (crash guards), but MCP tools stop working. Tell the user: **run `/mcp` to reconnect.** The new process enters client mode and proxies MCP calls to the surviving HTTP server. The browser will auto-reconnect.
|
|
378
|
+
|
|
360
379
|
**Port 5050 busy** — Another OpenWriter instance owns the port. New sessions auto-enter client mode (proxying via HTTP) — tools still work. No action needed.
|
|
361
380
|
|
|
362
381
|
**Edits don't appear** — Stale node IDs. Always `read_pad` before `write_to_pad` to get fresh IDs.
|
|
@@ -365,4 +384,6 @@ Users set their X handle by clicking the avatar circle in the compose area. The
|
|
|
365
384
|
|
|
366
385
|
**Server not starting** — Ensure `openwriter` works from your terminal (`npm install -g openwriter` first). If on Windows and the global command isn't found, the MCP config may need `"command": "cmd"` with `"args": ["/c", "openwriter", "--no-open"]`.
|
|
367
386
|
|
|
387
|
+
**After code changes** — Run `npm run build` in `packages/openwriter`, then `/mcp` to restart with the new build.
|
|
388
|
+
|
|
368
389
|
**Slow to load / loads last** — MCP servers load sequentially in config order. Move `openwriter` to the first position in `mcpServers` in `~/.claude.json`. See setup instructions above.
|