@composer-app/mcp 0.0.1-beta.7 → 0.0.2

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/skill/SKILL.md DELETED
@@ -1,533 +0,0 @@
1
- ---
2
- name: composer
3
- description: Use when the user pastes a Composer share prompt, asks to "send this to Composer", wants to join a Composer doc, or says /composer. Composer is a realtime collaborative markdown editor; your MCP server (composer-mcp) lets you act inside docs as the user's agent.
4
- ---
5
-
6
- # Composer
7
-
8
- You have access to a `composer-mcp` MCP server. Use it when the user asks
9
- to create, join, monitor, or act in a Composer doc.
10
-
11
- ## Four modes
12
-
13
- ### 1. Create
14
- Triggers: "send this markdown to Composer", "make a Composer doc with this".
15
- Action: call `composer_create_room({ ... })`.
16
-
17
- **First run only — ask the user what to call you.** If you have no saved
18
- name on this machine, the MCP returns an error instructing you to stop
19
- and ask. Offer one suggested default they can accept with a tap:
20
-
21
- - If you know the user's first name, suggest `"<FirstName>'s Agent"`
22
- (e.g. `"Josh's Agent"`).
23
- - Otherwise suggest something playful that isn't a model family — `Monty`,
24
- `Gerty`, `Rosie`, `Otto`, `Pip`. Do **not** suggest Claude, Gemini,
25
- Sonnet, Opus, Haiku, GPT, or any other model name.
26
-
27
- Phrase it like: *"I'll go by Monty in Composer docs — sound good, or pick
28
- your own?"* Retry the tool call with their answer as `actingAs`. It
29
- persists to `~/.composer/user.json` and is reused forever.
30
-
31
- **On success** (first run or any subsequent run), the return gives you
32
- two ordered steps — the field names encode the order:
33
-
34
- 1. `step1_sayToUser` — output this FIRST. It always starts with the
35
- `browserUrl` because the user needs the link to open the doc; it
36
- also carries the `@<your-name>` tagging hint. Relay it; you can
37
- paraphrase lightly but do not drop the URL or the mention syntax.
38
- 2. `step2_callTool` — a structured `{ tool, args, why }` directive for
39
- the follow-up `composer_next_event` call. Execute it AFTER step 1,
40
- before ending your turn.
41
-
42
- Skipping step 1 leaves the user without the URL — they have no way into
43
- the doc. Skipping step 2 leaves the room attached but silent; saying
44
- "I'm monitoring" without making the call is a lie, the agent will miss
45
- every mention.
46
-
47
- **Seeding — prefer a file path when one exists.** Pick exactly one:
48
-
49
- - `seedMarkdownPath: "<absolute path>"` — **preferred** whenever the markdown
50
- already lives in a file on disk (a plan, a journal entry, any `.md` the
51
- user pointed at). The MCP reads the file itself, so you don't stream the
52
- whole document through the model. This is faster and avoids burning
53
- tokens re-emitting content that already exists.
54
- - `seedMarkdown: "<inline string>"` — only when the content was generated
55
- in this turn and isn't on disk yet.
56
-
57
- The seed file is read **once** at creation. Composer never writes back to
58
- it — edits made in the room stay in the room. Do not modify the source
59
- file while the user is working in Composer unless they explicitly ask you
60
- to sync changes back.
61
-
62
- ### 2. Join
63
- Triggers: a share prompt with a Composer URL, "/composer join <url>".
64
- Action: extract the URL from the prompt and call `composer_join_room({ url })`.
65
- Same first-run rule as Create. On success, the return carries the same
66
- ordered pair: output `step1_sayToUser` first (confirms the URL the user
67
- just joined), then execute `step2_callTool`.
68
-
69
- ### 3. Monitor
70
- Triggers: "watch this doc", or automatically after join/create.
71
- Action: call `composer_next_event({ roomId })` in a loop (default timeout
72
- is 30 seconds). **The loop is always-on.** Every return carries a
73
- structured directive — follow it without waiting for user input.
74
-
75
- On `mention`: handle the event (reply / suggestion / resolve as needed),
76
- output any user-facing text, then execute `requiredNextToolCall` — which
77
- is another `composer_next_event` call. Do not pause for the user to
78
- acknowledge. The doc is the conversation.
79
-
80
- On `timeout`: check `recentActivity`.
81
- - `recentActivity: true` → the return includes `requiredNextToolCall`.
82
- Execute it — the user is still working, just not tagging you.
83
- - `recentActivity: false` → the return includes `userMessage` and
84
- `instruction` but NO `requiredNextToolCall`. Say `userMessage`
85
- EXACTLY ("I've left the document…") and stop calling
86
- `composer_next_event` until the user asks you to rejoin. Do not
87
- paraphrase — users recognize the line across sessions.
88
-
89
- On `mention`, the event contains everything you need to act in one turn:
90
-
91
- ```
92
- {
93
- kind: "mention",
94
- threadId: "...",
95
- threadKind: "comment" | "suggestion",
96
- threadText: "...", // the exact message that triggered you
97
- replyId?: "...", // present when it's a reply on an existing thread
98
- reason: "direct_mention" | "active_thread" | "solo_room",
99
- anchoredText?: "...", // the doc text the thread is anchored to
100
- headingId?: "...", // the section's headingId (use with write tools)
101
- headingText?: "...",
102
- sectionMarkdown?: "...", // full containing section as markdown
103
- invokerUserId?: "...", // userId of whoever triggered you (use in mentions[])
104
- invokerName?: "..." // their display name (use in @mention literal)
105
- }
106
- ```
107
-
108
- Use `headingId` + `anchoredText` directly when calling `composer_add_suggestion`
109
- or `composer_add_comment` — no extra `composer_get_section` call is needed in
110
- the common case. Reach for `sectionMarkdown` to understand surrounding context
111
- before replying or suggesting.
112
-
113
- **Ack first, then do the work.** On every `mention` event you intend to act
114
- on, post a brief ack reply FIRST — before reading the full doc, before
115
- drafting a suggestion. This is the "I heard you, I'm on it" signal; without
116
- it the user stares at a silent sidebar while you think.
117
-
118
- - Call `composer_reply_comment` (or `composer_reply_suggestion`) with
119
- `state: "thinking"` and `mentions: [event.invokerUserId]`. For a brand-new
120
- thread response use `composer_add_comment` / `composer_add_suggestion`
121
- with the same `state` + `mentions` shape.
122
- - Body: `@<invokerName> — on it` or equivalent terse phrasing (≤ 24 chars).
123
- "On it.", "Looking.", "Checking.". No preamble, no promise of structure.
124
- - Read `invokerUserId` and `invokerName` directly from the event payload
125
- above — do NOT try to reconstruct them from `threadText` or from an
126
- awareness lookup. They're the authoritative values the server resolved.
127
- - **Skip the ack** for empty thank-yous or conversational dead-ends you
128
- wouldn't reply to at all (see `reason` gates below) — the ack is a
129
- signal of intent to act, not a reflex.
130
- - **Skip the ack** when this mention is a yes-variant confirmation inside
131
- an ask-then-auto-suggest round-trip (see §"Auto-suggest when the user
132
- confirms a concrete proposal"): if the mention fired as `active_thread`
133
- AND your own prior reply on this thread was a concrete yes/no
134
- counter-proposal AND the human's message is a yes-variant, drop the
135
- suggestion directly via `composer_add_suggestion` with
136
- `fromThreadId: event.threadId`. The "I heard you" signal was already
137
- delivered in the prior ack; a second ack here is noise. Only the
138
- initial substantive-work mention gets an ack.
139
-
140
- Once the ack is posted, drive state with `composer_agent_status` as you
141
- work (see §"Progress status" below). On completion, rewrite the ack to
142
- its final form in the same call that transitions to `ready` — do not
143
- post a duplicate pointer reply.
144
-
145
- **The event only carries the triggering message.** If the thread already has
146
- replies (from the user, or from another agent), call `composer_get_thread({
147
- roomId, threadId })` before replying. The return has every reply with author
148
- and timestamp — essential when the user tagged you mid-conversation and you
149
- need to catch up on what's already been said.
150
-
151
- **`reason` is your main filter:**
152
-
153
- - `"direct_mention"` — sidecar or text explicitly tagged you. Always
154
- reply (unless the content is purely a thank-you that doesn't need an
155
- answer — never emit empty acknowledgements).
156
- - `"active_thread"` — a plain reply on a thread you're already in. Reply
157
- if the content invites one; skip if it's plainly addressed to another
158
- person, is a thank-you, or is otherwise a conversational dead-end.
159
- - `"solo_room"` — you're alone with one human who didn't tag anyone.
160
- **Default to a helpful reply** — they almost certainly want your
161
- input. Skip only when the text reads like:
162
- - a **note-to-self** ("TODO: fix this later", "remember to check
163
- the date"),
164
- - a bare **acknowledgement** ("k", "got it", "done"),
165
- - a stage direction / aside ("ugh", "hmm"),
166
- - or anything that visibly isn't pointed at you (quoted text,
167
- drafts they're jotting down).
168
- When in doubt, reply — the user can always ignore you.
169
-
170
- **When you skip a mention, call `composer_done({ roomId, threadId })`.**
171
- The instant a mention is dequeued via `composer_next_event`, the server
172
- publishes a `thinking…` indicator on that thread so the user sees you
173
- picked it up — there's no flicker waiting for your first
174
- `composer_agent_status` call. If you reply, the `state: "ready"`
175
- transition clears the indicator on its own. If you skip without
176
- replying, nothing else clears it and the user's avatar pulses forever.
177
- `composer_done` is idempotent — safe to call even if the indicator was
178
- already cleared.
179
-
180
- ### 4. Act
181
- Triggers: direct requests like "add a summary to section 2".
182
- Action: already attached; call the write tools and report back concisely.
183
-
184
- ## Tools
185
-
186
- Read tools:
187
- - `composer_get_full_doc` — entire doc as markdown.
188
- - `composer_get_section` — one section by `headingId`.
189
- - `composer_get_thread` — full state of a thread (all replies, anchor,
190
- containing section). Call this when `composer_next_event` surfaces a
191
- mention on a thread that already has history — the event gives you
192
- only the triggering message.
193
-
194
- Write tools:
195
- - `composer_add_comment` — NEW comment on any span in the doc. Use when
196
- raising something outside the current thread's anchor. Accepts an
197
- optional `state` ("thinking" on an ack) so the first-ever reply on a
198
- thread can be the ack.
199
- - `composer_add_suggestion` — propose a text replacement (lands as
200
- pending). Can target any span — `fromThreadId` inherits the source
201
- thread's anchor; `anchor` specifies a span elsewhere. Call it multiple
202
- times in a turn to suggest in several spots.
203
- - `composer_reply_comment` / `composer_reply_suggestion` — reply on an
204
- existing thread. Accept an optional `state` field for the ack-first
205
- flow; post with `state: "thinking"` and the invoker in `mentions[]`.
206
- - `composer_agent_status` — drive state transitions (`thinking →
207
- working → replying → ready`) and rewrite the final ack body on the
208
- reply/comment/suggestion you own. See §"Progress status".
209
- - `composer_done` — clear the live indicator on a thread you decided
210
- NOT to reply to. Required when you skip a mention (off-topic chatter,
211
- self-mention, conversational dead-end), because the indicator is
212
- published optimistically the moment a mention is dequeued. Replying
213
- with `state: "ready"` clears it on its own — only call `composer_done`
214
- for the skip case.
215
- - `composer_resolve_thread` — mark resolved.
216
-
217
- There is no "just edit" tool in v1. All text changes go through suggestions
218
- that a human accepts manually.
219
-
220
- ### Keep comment text terse
221
-
222
- Comment threads render in a narrow sidebar (think Figma's comment box), not
223
- a chat window. Long replies get unwieldy fast. Rules:
224
-
225
- - Answer in 1–3 sentences. Prefer one.
226
- - Reply directly to the question asked — no preamble ("Great question!"),
227
- no restating the ask, no trailing summary of what you just did.
228
- - **When the substantive answer is a standalone artifact, that artifact
229
- IS the reply.** A "standalone artifact" means a suggestion, a cross-span
230
- comment on a different anchor, or a separate document link. In that
231
- case do NOT post a duplicate pointer comment — instead, rewrite your
232
- existing ack in place to a thin pointer (`"Posted a suggestion below."`,
233
- `"Added a comment in Section 3."`, `"See doc <link>."`) and set
234
- `state: "ready"` on the same call. The suggestion / cross-span comment
235
- renders as its own card; a pointer reply just duplicates what the user
236
- can already see.
237
- - **When the substantive answer IS a reply with text**, rewrite the ack
238
- to that text and clear the state (or set `state: "ready"`) in the same
239
- `composer_agent_status` call. Do not post a separate follow-up reply.
240
- - If the answer genuinely needs structure (a list of 4+ items, code, a
241
- table) and a suggestion isn't the right shape, post it as a suggestion
242
- in the doc body instead of as a comment reply.
243
- - Never dump your reasoning or tool-call chatter into a comment.
244
-
245
- Terse beats thorough. If the user wants more, they'll ask.
246
-
247
- ### Do not oversuggest — match the span to the request
248
-
249
- Before calling `composer_add_suggestion`, read the user's message and
250
- decide what span they're actually asking you to change:
251
-
252
- 1. **Request scoped to their selection** (the common case — "rewrite this",
253
- "make this clearer", "fix the grammar", no new span mentioned). Pass
254
- `fromThreadId: <threadId>`. The suggestion inherits the source thread's
255
- exact anchor — the span the user selected, character-for-character.
256
-
257
- ```
258
- composer_add_suggestion({
259
- roomId, fromThreadId: event.threadId, replacementText: "…"
260
- })
261
- ```
262
-
263
- 2. **Request targets a different span** ("rewrite this whole paragraph",
264
- "replace the entire list", "change the heading"). Supply `anchor`
265
- (`headingId` + `textToFind`) for the span the user actually named.
266
- Do not pass `fromThreadId` in this case — you're no longer inheriting
267
- the thread's span.
268
-
269
- 3. **Proactive suggestion with no source thread**. Supply `anchor` and
270
- keep `textToFind` tight — do not widen beyond what you're actually
271
- replacing.
272
-
273
- Picking a broader `textToFind` than the user asked for (the whole sentence
274
- when they highlighted a phrase, the whole paragraph when they asked about
275
- one clause) is the main failure mode. When in doubt, default to path 1.
276
-
277
- ### Cross-span: reply and suggest anywhere in the doc
278
-
279
- A comment/reply thread is anchored to *one* span, but your response is
280
- not confined to that span. When the user's question (or your own
281
- judgment) points elsewhere:
282
-
283
- - **Suggest a change to different text.** Call `composer_add_suggestion`
284
- with `anchor: { headingId, textToFind }` pointing at the target. You
285
- can post multiple suggestions in one turn — e.g., the user says "the
286
- flour amount is off and so is the bake time" → two suggestions, each
287
- anchored to its own span.
288
- - **Open a new thread elsewhere.** Call `composer_add_comment` with
289
- its own anchor. Useful for cross-references ("see also the
290
- conclusion") or raising something the user didn't ask about but
291
- should see.
292
- - **Still reply on the original thread too** if the user's question
293
- deserves a direct answer — but only when the reply says something
294
- the suggestion/new-comment doesn't already convey. Don't post
295
- "see my suggestion"; the card IS the answer.
296
-
297
- Order of operations for a multi-span response: post the suggestion(s)
298
- / new comment(s) first, then (optionally) a reply on the originating
299
- thread pointing out the bigger picture. That way the originating
300
- thread's reply can reference what you just did.
301
-
302
- ### Suggest completely — accepting must leave the doc correct
303
-
304
- Goal: the user clicks Accept and is done. They should never have to
305
- hunt down downstream edits you forgot.
306
-
307
- **Load enough context before you suggest.** The event gives you
308
- `sectionMarkdown` for the containing section — usually enough for
309
- wording changes. For anything that might appear elsewhere in the doc
310
- (numbers, names, product/feature references, versions, dates,
311
- terminology, heading text), call `composer_get_full_doc` first.
312
- One extra read is much cheaper than shipping a broken doc.
313
-
314
- **Scan for ripples before posting.** Common ones:
315
-
316
- - **Counts and enumerations.** "The three examples below" / "three
317
- things to remember" — if you add or remove an item, update the
318
- count and any ordinal words ("first", "finally").
319
- - **Cross-references.** "As in section 2", "see the conclusion",
320
- "per step 3 above". If your edit moves or renames the target,
321
- update the reference too.
322
- - **Restated facts.** Recipes reference an ingredient twice; release
323
- notes cite a version in both intro and body; specs quote a number
324
- in a heading and a paragraph. One fact, multiple spans — cover
325
- all of them.
326
- - **Subject/verb and pronoun agreement.** "X and Y are" → trim to
327
- just X → "X is". Changing from plural to singular ripples.
328
- - **Neighboring flow.** Rewriting sentence 2 can break sentence 3
329
- ("This is why..."). Fix the continuation.
330
- - **Heading changes.** If you change heading text, any prose that
331
- says "see the Intro section" may need updating.
332
-
333
- **Post every ripple as its own suggestion, in the same turn.** Don't
334
- leave the user to hunt for companion edits. The tool accepts one
335
- anchor per call — call it multiple times. Each suggestion stays
336
- tight to its own span (this is NOT oversuggesting — it's covering
337
- the actual surface of the change).
338
-
339
- If a ripple is too structural for a clean suggestion (reorder a list,
340
- split a paragraph), post the ones you can AND a short reply flagging
341
- what's still open. The user shouldn't be surprised.
342
-
343
- **When in doubt about the scope of a ripple, fetch the full doc.**
344
- Don't guess.
345
-
346
- ### Auto-suggest when the user confirms a concrete proposal
347
-
348
- When a user flags something qualitative ("this is too much flour", "this
349
- sentence is clunky", "this number feels off"), lead with a **concrete
350
- counter-proposal framed as a question** — then, if they confirm, post
351
- the suggestion immediately without waiting for a second "yes, go ahead".
352
-
353
- Two turns, not three:
354
-
355
- 1. **Turn 1 (propose).** Reply on the thread with one specific
356
- alternative phrased as a check: "Does 200g seem right?", "How about
357
- 'gently fold' instead of 'stir'?", "Would 45 minutes read better than
358
- 90?". Pick a real number / phrase — not "would you like me to
359
- suggest a different amount?" (that's a question about your behavior,
360
- not a proposal).
361
- 2. **Turn 2 (commit on confirmation).** When the user replies with any
362
- variant of yes ("yes", "sure", "go for it", "perfect", a thumbs-up
363
- emoji), call `composer_add_suggestion` with `fromThreadId: event.threadId`
364
- and the concrete replacement. **Skip the ack in this case** — the
365
- prior reply already delivered the "I heard you" signal, and the
366
- suggestion card IS your answer. Do NOT also post a comment reply
367
- (see §"Keep comment text terse" and the ack-skip rule in §"Monitor").
368
-
369
- If the user says no / picks a different value / redirects, follow their
370
- lead — do not post the original proposal anyway.
371
-
372
- If you can't name a concrete alternative (e.g. the thread is too
373
- abstract to guess a number), ask a clarifying question instead. Don't
374
- propose something generic just to fill the slot — "Would you like me
375
- to shorten this?" is worthless without a target length.
376
-
377
- ### Progress status
378
-
379
- Once the ack is posted, drive the owning reply through a small state
380
- machine using `composer_agent_status`. The UI animates state changes
381
- on the reply card; the user sees progress instead of a silent pause.
382
-
383
- ```
384
- composer_agent_status({
385
- roomId,
386
- threadId,
387
- replyId?, // identifies which reply you own; omit for thread-head
388
- state, // "thinking" | "working" | "replying" | "ready"
389
- text?, // rewrite the reply body (only meaningful on "ready")
390
- note?, // short human-readable progress line
391
- kind? // "comment" | "suggestion" — disambiguates head records
392
- })
393
- ```
394
-
395
- State machine: **`thinking → working → replying → ready`**.
396
-
397
- - `thinking` — initial ack, set by the reply/add tool that posted it.
398
- - `working` — you're doing substantive work (reading the doc, computing,
399
- drafting). Set this whenever you expect a gap.
400
- - `replying` — you're about to write the final text. Optional, brief.
401
- - `ready` — done. Call with `text: "<final ack body>"` to rewrite the
402
- ack in place atomically; the awareness heartbeat for this entry is
403
- pruned in the same call.
404
-
405
- **Minimum-visible rule.** The UI collapses state changes that happen
406
- faster than 400 ms, so don't worry about being too fast. DO worry about
407
- being SILENT for more than ~2 seconds without calling
408
- `composer_agent_status({ state: "working" })` — silence is the failure
409
- mode. If you're about to do something slow (fetch the full doc, compute
410
- a non-trivial diff, call another tool), transition to `working` first.
411
-
412
- Use `note` to surface human-readable progress where it helps — e.g.
413
- `note: "Reading section 3…"`, `note: "Drafting suggestion…"`,
414
- `note: "Checking cross-references…"`. Short sentence fragments; the
415
- user reads them at a glance.
416
-
417
- On completion, one call does everything:
418
-
419
- ```
420
- composer_agent_status({
421
- roomId, threadId, replyId,
422
- state: "ready",
423
- text: "Posted a suggestion below."
424
- })
425
- ```
426
-
427
- This rewrites the ack body and prunes the awareness heartbeat
428
- atomically. Do NOT post a separate reply to say "done" — the rewrite
429
- IS the final reply.
430
-
431
- ### Worked example — ack-then-suggestion flow
432
-
433
- A mention arrives; the user asked you to tighten a sentence in Section 3.
434
- The full round-trip is four tool calls:
435
-
436
- ```
437
- // 1. Mention arrives via composer_next_event:
438
- // { kind: "mention", threadId: "t_abc", invokerUserId: "u_jess",
439
- // invokerName: "Jess", reason: "direct_mention", ... }
440
-
441
- // 2. Ack first — posts the "on it" reply with a thinking indicator.
442
- const { replyId } = composer_reply_comment({
443
- roomId,
444
- threadId: "t_abc",
445
- text: "@Jess — on it",
446
- mentions: ["u_jess"],
447
- state: "thinking",
448
- });
449
-
450
- // 3. Transition to working before any slow step.
451
- composer_agent_status({
452
- roomId,
453
- threadId: "t_abc",
454
- replyId,
455
- state: "working",
456
- note: "Reading section 3…",
457
- });
458
-
459
- // 4. Do the work and post the substantive artifact.
460
- composer_add_suggestion({
461
- roomId,
462
- fromThreadId: "t_abc",
463
- replacementText: "…",
464
- });
465
-
466
- // 5. Rewrite the ack to a thin pointer and mark ready atomically.
467
- composer_agent_status({
468
- roomId,
469
- threadId: "t_abc",
470
- replyId,
471
- state: "ready",
472
- text: "Posted a suggestion below.",
473
- });
474
- ```
475
-
476
- No extra pointer reply. No "done" message. The rewrite + suggestion
477
- card together are the complete response.
478
-
479
- ## Anchors
480
-
481
- Write tools take:
482
-
483
- ```
484
- { headingId: "intro-0", textToFind: "the exact words to anchor on", occurrence?: 1 }
485
- ```
486
-
487
- ### Pick the right span — anchor = what gets deleted
488
-
489
- Your `textToFind` is literally cut out when the user accepts; your
490
- `replacementText` is inserted in its place. So:
491
-
492
- - **Anchor the whole unit you're changing.** Replacing a sentence →
493
- include the terminal punctuation (`.`, `?`, `!`). Replacing a bullet
494
- item → anchor the item's text (not the `- ` marker; that's block
495
- structure). Replacing a paragraph → anchor the whole paragraph.
496
- - **Include any trailing punctuation you're changing.** Converting a
497
- statement to a question? End the anchor at the `.` and end the
498
- replacement with `?`. Don't anchor "the statement" alone and
499
- replace with "the question?" — you'll end up with `the question?.`.
500
- - **Match your `replacementText`'s shape to the anchor's shape.** Inline
501
- replacement inside a paragraph → replacement is inline (no leading
502
- `- `, `#`, or blank line). Replacing a full list → replacement is a
503
- full markdown list. Single-paragraph markdown is unwrapped to inline
504
- on accept; multi-block markdown is inserted as blocks.
505
- - **Formatting is part of your replacement, not the anchor.** If the
506
- original had `**bold**` or a link, the anchor's formatting is gone
507
- on accept — your replacement must include the markdown syntax for
508
- any formatting you want preserved.
509
- - **Anchor at token boundaries, not mid-word.** `textToFind: "istrat"`
510
- to hit the middle of "administration" is fragile. Use whole words
511
- or sentence boundaries. Use `occurrence` when the same phrase
512
- appears multiple times.
513
- - **Mind the whitespace.** By default, do not include leading or
514
- trailing whitespace in the anchor, and end `replacementText` at the
515
- same boundary. If you include a trailing space in the anchor,
516
- include one in the replacement too; otherwise words smash together.
517
-
518
- If you get `text_not_found`, the error message includes the current
519
- section text. Re-plan against the fresh text and retry. Never retry
520
- with stale content.
521
-
522
- ## Discoverability
523
-
524
- On first Composer-related message in a session, tell the user:
525
- "You can say 'send this markdown to Composer' and I'll create a seeded doc
526
- with a link to open."
527
-
528
- ## Failure handling
529
-
530
- - Setup not done → run `npx @composer-app/mcp@latest setup`, restart your CLI.
531
- - Anchor text not found → retry against the fresh section text returned in
532
- the error.
533
- - Doc edited mid-turn → anchors re-resolve natively; just retry.