@rubytech/create-maxy-code 0.1.183 → 0.1.185

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.
Files changed (72) hide show
  1. package/dist/__tests__/platform-port-stamp.test.js +4 -0
  2. package/dist/index.js +1 -0
  3. package/dist/port-resolution.js +1 -0
  4. package/package.json +1 -1
  5. package/payload/platform/config/brand.json +1 -1
  6. package/payload/platform/package-lock.json +178 -0
  7. package/payload/platform/plugins/.claude-plugin/marketplace.json +15 -0
  8. package/payload/platform/plugins/admin/PLUGIN.md +0 -1
  9. package/payload/platform/plugins/browser/.claude-plugin/plugin.json +17 -0
  10. package/payload/platform/plugins/browser/PLUGIN.md +44 -0
  11. package/payload/platform/plugins/browser/mcp/dist/index.d.ts +2 -0
  12. package/payload/platform/plugins/browser/mcp/dist/index.d.ts.map +1 -0
  13. package/payload/platform/plugins/browser/mcp/dist/index.js +61 -0
  14. package/payload/platform/plugins/browser/mcp/dist/index.js.map +1 -0
  15. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-render.d.ts +66 -0
  16. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-render.d.ts.map +1 -0
  17. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-render.js +248 -0
  18. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-render.js.map +1 -0
  19. package/payload/platform/plugins/browser/mcp/package.json +19 -0
  20. package/payload/platform/plugins/docs/references/internals.md +1 -1
  21. package/payload/platform/plugins/docs/references/plugins-guide.md +3 -0
  22. package/payload/platform/plugins/docs/references/troubleshooting.md +4 -4
  23. package/payload/platform/plugins/memory/PLUGIN.md +1 -0
  24. package/payload/platform/plugins/memory/mcp/dist/index.js +20 -10
  25. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
  26. package/payload/platform/plugins/prompt-optimiser/.claude-plugin/plugin.json +8 -0
  27. package/payload/platform/plugins/prompt-optimiser/PLUGIN.md +14 -0
  28. package/payload/platform/plugins/prompt-optimiser/skills/prompt-optimiser/SKILL.md +301 -0
  29. package/payload/platform/plugins/url-get/.claude-plugin/plugin.json +17 -0
  30. package/payload/platform/plugins/url-get/PLUGIN.md +86 -0
  31. package/payload/platform/plugins/url-get/mcp/dist/index.d.ts +9 -0
  32. package/payload/platform/plugins/url-get/mcp/dist/index.d.ts.map +1 -0
  33. package/payload/platform/plugins/url-get/mcp/dist/index.js +53 -0
  34. package/payload/platform/plugins/url-get/mcp/dist/index.js.map +1 -0
  35. package/payload/platform/plugins/url-get/mcp/dist/lib/summarise.d.ts +8 -0
  36. package/payload/platform/plugins/url-get/mcp/dist/lib/summarise.d.ts.map +1 -0
  37. package/payload/platform/plugins/url-get/mcp/dist/lib/summarise.js +83 -0
  38. package/payload/platform/plugins/url-get/mcp/dist/lib/summarise.js.map +1 -0
  39. package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.d.ts +21 -0
  40. package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.d.ts.map +1 -0
  41. package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.js +147 -0
  42. package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.js.map +1 -0
  43. package/payload/platform/plugins/url-get/mcp/package.json +22 -0
  44. package/payload/platform/scripts/setup-account.sh +0 -6
  45. package/payload/platform/scripts/vnc.sh +1 -1
  46. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  47. package/payload/platform/services/claude-session-manager/dist/http-server.js +46 -0
  48. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  49. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +17 -8
  50. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  51. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +40 -14
  52. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  53. package/payload/platform/services/claude-session-manager/dist/specialist-drift.js +2 -2
  54. package/payload/platform/services/claude-session-manager/dist/specialist-drift.js.map +1 -1
  55. package/payload/platform/templates/specialists/agents/content-producer.md +3 -3
  56. package/payload/platform/templates/specialists/agents/librarian.md +1 -1
  57. package/payload/platform/templates/specialists/agents/personal-assistant.md +3 -3
  58. package/payload/platform/templates/specialists/agents/research-assistant.md +3 -3
  59. package/payload/premium-plugins/writer-craft/mcp/dist/index.d.ts.map +1 -1
  60. package/payload/premium-plugins/writer-craft/mcp/dist/index.js +20 -6
  61. package/payload/premium-plugins/writer-craft/mcp/dist/index.js.map +1 -1
  62. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.d.ts +14 -0
  63. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.d.ts.map +1 -1
  64. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.js +28 -34
  65. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.js.map +1 -1
  66. package/payload/premium-plugins/writer-craft/mcp/scripts/smoke.mjs +43 -8
  67. package/payload/premium-plugins/writer-craft/mcp/src/index.ts +20 -8
  68. package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-retrieve-conditioning.ts +51 -12
  69. package/payload/premium-plugins/writer-craft/skills/voice-mirror/SKILL.md +7 -1
  70. package/payload/server/server.js +222 -126
  71. package/payload/platform/plugins/admin/hooks/__tests__/playwright-file-guard.test.sh +0 -278
  72. package/payload/platform/plugins/admin/hooks/playwright-file-guard.sh +0 -214
@@ -0,0 +1,301 @@
1
+ ---
2
+ name: prompt-optimiser
3
+ description: Turn any rough prompt, half-formed idea, or task description into a finished, ready-to-send prompt optimized for Opus 4.7 (with adaptive thinking) inside the chat app — claude.ai, the Mac app, the iOS app — NOT the API. Use this skill whenever the user wants to write, rewrite, optimize, improve, sharpen, or polish a prompt for the chat app. Trigger phrases include "rewrite this prompt", "make this a better prompt", "optimize this prompt", "turn this into a prompt", "help me prompt this", "draft a prompt that...", "I want to ask...", or whenever the user pastes a draft prompt and asks for improvements. Also trigger when the user describes a task they plan to send into the chat app and clearly wants a reusable, well-structured prompt rather than a direct answer. The output is always a single, copy-pasteable prompt in a code block that the user sends as-is — never a template with placeholders.
4
+ ---
5
+
6
+ # Prompt optimiser
7
+
8
+ You turn whatever the user gives you — a rough draft, a vague idea, a task description, a paragraph of context — into a single high-quality prompt designed to run inside the chat app on Opus 4.7 with adaptive thinking.
9
+
10
+ This is for the **chat app** (claude.ai, Mac, iOS), not the API. The user is going to paste a single message into chat. There is no system prompt, no `effort` parameter, no tool config to tune. The prompt itself has to do all the work.
11
+
12
+ ## Two hard rules
13
+
14
+ These two rules override everything else in this skill. Read them, then re-read them.
15
+
16
+ ### Rule 1 — No placeholders. Ever.
17
+
18
+ Never produce a prompt that contains `[paste X here]`, `[your content]`, `{topic}`, `<your_input_here>`, `[INSERT Y]`, `___`, or any other template variable the user is expected to fill in. The user must be able to copy your output, paste it into chat, hit send, and have a working interaction. If the prompt requires content the user hasn't provided yet, the prompt itself must handle that — see Rule 2.
19
+
20
+ If you catch yourself typing square brackets around a noun, stop. That's a placeholder. Rewrite.
21
+
22
+ ### Rule 2 — Ship a finished prompt no matter what the user gave you.
23
+
24
+ Two cases:
25
+
26
+ **Case A — the user gave you real content** (a draft they wrote, code, a document, a list of items, a specific question, an actual product description). Bake that content directly into the optimized prompt. The whole thing — content and instructions — goes inside the code block. The user copies, pastes, sends. Done.
27
+
28
+ **Case B — the user only described a class of task** ("I want a prompt to triage my emails", "help me prompt Claude to review my code", "give me a prompt for writing LinkedIn posts about my launches"). Write the prompt as a complete, self-contained instruction that works on its own. End the instruction by either:
29
+ - Asking Claude to ask the user for the specific inputs it needs ("Before drafting, ask me to share the product name, audience, and a link."), or
30
+ - Phrasing the task so the user will naturally provide the input in their next chat turn ("I'm going to paste a batch of emails next. For each one, do the following...").
31
+
32
+ Either way: no brackets, no fill-in-the-blank, no template syntax. The prompt is final.
33
+
34
+ ## What you output
35
+
36
+ A single fenced code block containing the optimized prompt. Nothing else. No preamble like "Here's your prompt:". No trailing explanation of what you changed.
37
+
38
+ The prompt must end with this exact line as its final line:
39
+
40
+ ```
41
+ Think before answering
42
+ ```
43
+
44
+ That line is non-negotiable. It is the user's signal to push Opus 4.7's adaptive thinking toward deeper reasoning inside the chat app, where API-side `effort` controls aren't available.
45
+
46
+ ## Why these principles work
47
+
48
+ Opus 4.7 reads prompts more literally than older models, calibrates its own thinking and length to perceived complexity, and rewards prompts that are specific, structured, and motivated. The cookbook below is distilled from Anthropic's own Opus 4.7 prompting guidance. Each rule has a reason. Treat the reasons as the point — apply them with judgment, don't paste them mechanically.
49
+
50
+ ## The rewrite workflow
51
+
52
+ Work through these in your head before writing the prompt. You don't need to surface them.
53
+
54
+ 1. **Identify the goal.** What does the user actually want produced? A document? A decision? Code? A list? An analysis? Name it concretely.
55
+ 2. **Identify the audience and use.** Who reads the output, and what will they do with it? This drives tone and format.
56
+ 3. **Decide: Case A or Case B.** Did the user provide the actual content, or just describe a class of task? This decides whether you bake content in or write a self-contained instruction (see Rule 2).
57
+ 4. **Spot the gaps.** Audience, format, length, constraints, examples, edge cases — note which are missing.
58
+ 5. **Fill the gaps with reasonable assumptions.** The user told you not to ask questions. Make the most useful, most defensible assumption and move on. Keep it grounded in what they wrote.
59
+ 6. **Pick a structure.** Single-paragraph instruction for simple tasks. XML tags for anything with multiple sections.
60
+ 7. **Write the prompt.** Apply the principles below.
61
+ 8. **End with the closing line.**
62
+ 9. **Scan for brackets.** Before you finalize, re-read your output looking for `[`, `{`, or `<...your...>`-style placeholders. Kill any you find.
63
+
64
+ ## Core principles to apply
65
+
66
+ ### Be clear and direct
67
+ State the task explicitly. Specify the desired output format and any hard constraints up front. If you want above-and-beyond effort, say so — Opus 4.7 won't infer it from a vague brief. "Create an analytics dashboard" is weaker than "Create an analytics dashboard with as many relevant features and interactions as possible — go beyond the basics for a fully-featured implementation."
68
+
69
+ ### Cap the length explicitly
70
+ Opus 4.7 sizes its answer to whatever it infers the task needs, so an uncapped instruction produces unpredictable length. When the user has any length preference — or when a tight output is plainly better — name a hard cap, and a unit where one helps. "Summarize this report" drifts; "Summarize this in exactly 5 bullets, each under 15 words, each starting with an action verb" lands. Choose the cap that serves the goal; don't impose one where length should float (a short story, an open-ended analysis).
71
+
72
+ ### Explain the why
73
+ When you give an instruction, briefly explain the reason. "Avoid ellipses, because the output will be read aloud by a TTS engine that mispronounces them" lands far better than "Never use ellipses." Opus 4.7 generalizes well from explanations and follows reasoned instructions more faithfully.
74
+
75
+ ### Tell Claude what to do, not what to avoid
76
+ Positive framing outperforms negative framing. "Write in flowing prose paragraphs" beats "don't use bullet points."
77
+
78
+ ### Match prompt style to desired output style
79
+ If you want prose, write the prompt in prose. If you want minimal markdown in the output, use minimal markdown in the prompt. Style leaks through.
80
+
81
+ ### Use XML tags when sections multiply
82
+ When the prompt mixes instructions, context, examples, and input, wrap each in its own descriptive tag — `<instructions>`, `<context>`, `<examples>`, `<input>`. Nest naturally where there's hierarchy. This is the single highest-leverage structuring move for complex prompts. For simple one-shot prompts, skip it; XML on a haiku request is overkill.
83
+
84
+ ### Give Claude a role when it sharpens behavior
85
+ A one-line role assignment ("You are a senior product strategist at a B2B SaaS company") tightens tone and frame. Don't force a role onto every prompt — only when it meaningfully steers the output.
86
+
87
+ ### Use examples for format, tone, or structure
88
+ If the user has any preference about *how* the output should look, include 2–4 examples in `<example>` tags (or wrap multiple in `<examples>`). Examples beat description for steering format. Make them relevant, diverse, and structured. Skip examples when the task is so generic that examples would over-constrain.
89
+
90
+ ### Put long inputs on top, the question on the bottom
91
+ If the prompt includes a long document, transcript, or data dump that the user provided, place it at the top. Anthropic's own testing shows up to ~30% quality lift from this ordering on long-context tasks.
92
+
93
+ ### Ask for grounding in long-document tasks
94
+ For analysis or Q&A over long inputs, instruct Claude to first pull relevant quotes into `<quotes>` tags, then answer based on those quotes. This dramatically reduces drift and hallucination.
95
+
96
+ ### Be literal about scope
97
+ Opus 4.7 doesn't silently generalize. If you want an instruction applied broadly, say "apply this to every section, not just the first one." If you want Claude to take action rather than suggest, use imperative verbs ("Edit the function to..." not "Could you suggest improvements to..."). Suggestion-flavored phrasing produces suggestions.
98
+
99
+ ### Self-check for high-stakes outputs
100
+ For code, math, claims, or anything where errors matter, append a verification instruction near the end: "Before you finish, re-read your answer and check it against the criteria above." This catches errors reliably.
101
+
102
+ ## Domain-specific moves
103
+
104
+ These are sharp tools for specific task types. Apply only when relevant.
105
+
106
+ **Frontend / design.** Opus 4.7 has a strong default house style (warm cream backgrounds, serif type, terracotta accents) that's wrong for most products. If the user is asking for a design, either (a) specify a concrete alternative palette, type system, and structure in detail, or (b) instruct the model to propose 3–4 distinct visual directions before building, so the user picks one. Generic instructions like "make it clean and minimal" don't break the default.
107
+
108
+ **Code review.** Tell the model its job at the finding stage is coverage, not filtering: "Report every issue you find, including ones you're uncertain about or consider low-severity. Include confidence and severity for each finding so a downstream filter can rank them." Avoid soft language like "only flag important issues" — Opus 4.7 takes that literally and under-reports.
109
+
110
+ **Research / analysis.** Encourage hypothesis-tracking: "Develop several competing hypotheses as you gather information. Track confidence levels in your notes. Self-critique your approach periodically." This produces more rigorous synthesis than a flat "research X" prompt.
111
+
112
+ **Creative writing.** Specify voice, audience, length, constraints, and provide one or two example sentences in the target voice if the user has them. Generic "write a blog post" yields generic prose.
113
+
114
+ **Document creation (slides, reports).** Ask for design intentionality: "Include thoughtful visual hierarchy, considered typography, and engaging structure." Opus 4.7 produces strong first-pass document design when invited to.
115
+
116
+ ## Output format
117
+
118
+ Always exactly this:
119
+
120
+ ````
121
+ ```
122
+ [the optimized prompt — final, no placeholders, content baked in if provided
123
+ or self-contained with an explicit "ask me for X" close if not]
124
+
125
+ Think before answering
126
+ ```
127
+ ````
128
+
129
+ No text before the code block. No text after. No "here you go." No "I added X and Y." Just the prompt.
130
+
131
+ If the user explicitly asks "what did you change?" *after* they have the prompt, then explain in a follow-up turn. Until they ask, stay silent.
132
+
133
+ ## Examples
134
+
135
+ These show the no-placeholder rule in action. Notice none of them contain `[paste X here]` or any other template variable.
136
+
137
+ ### Example 1 — Case B (user described a task class, no content given)
138
+
139
+ **User input:**
140
+ > I want a prompt to summarize my emails
141
+
142
+ **Your output:**
143
+
144
+ ````
145
+ ```
146
+ You are an executive assistant helping me triage email. I'm about to share a batch of emails with you in my next message.
147
+
148
+ For each email, produce:
149
+ - **Sender + subject** in one line
150
+ - **Summary** — 1-2 sentences, neutral tone, no fluff
151
+ - **Action required** — one of: reply needed, FYI only, schedule, delegate, ignore
152
+ - **Priority** — high / medium / low, based on sender importance and urgency cues
153
+
154
+ Group the output into three sections in this order: high priority, medium priority, low priority. Within each section, sort by action-required first (reply needed → schedule → delegate → FYI → ignore).
155
+
156
+ Skip any email that's clearly automated marketing or notification spam — list its sender and subject under a final "Filtered out" section so I can verify.
157
+
158
+ When you're ready, ask me to paste the emails.
159
+
160
+ Think before answering
161
+ ```
162
+ ````
163
+
164
+ The prompt ends by inviting the user to paste content in the next turn. No `[paste emails here]` block. The user sends this as-is and Claude responds with "Ready when you are — paste the batch."
165
+
166
+ ### Example 2 — Case B (rough draft prompt, no product details given)
167
+
168
+ **User input:**
169
+ > can you fix this prompt: "write a linkedin post about my new product launch, make it engaging and not too salesy"
170
+
171
+ **Your output:**
172
+
173
+ ````
174
+ ```
175
+ You are writing a LinkedIn post for me announcing a product launch. The audience is mid-to-senior B2B operators on LinkedIn — they've seen every launch post template and are skeptical of marketing language.
176
+
177
+ Before you draft, ask me for:
178
+ - The product's name
179
+ - What it does, in plain language
180
+ - Who it's for
181
+ - The 1-2 reasons I built it that aren't obvious from the description
182
+ - A link or destination for the call to action
183
+
184
+ Once I've answered, write one post that:
185
+ - Opens with a concrete hook in the first 2 lines (a tension, a number, or an unexpected observation — not "I'm excited to announce").
186
+ - Tells a short story or shares a specific insight that led to the product, before naming it.
187
+ - Names what the product does in one plain sentence. No adjectives like "revolutionary", "game-changing", or "powerful".
188
+ - Closes with one clear next step (link, DM, comment) — not a generic "let me know what you think".
189
+ - Sits between 150 and 220 words. Short paragraphs, one idea per line break. No emojis. No hashtags except up to two at the very end if they're genuinely relevant.
190
+
191
+ Match the voice of someone who's built the thing themselves and is talking to peers, not pitching to strangers.
192
+
193
+ Think before answering
194
+ ```
195
+ ````
196
+
197
+ Instead of a `<product_details>` block with `[paste details here]`, the prompt explicitly tells Claude to gather the details by asking. Self-contained, ready to send.
198
+
199
+ ### Example 3 — Case B (technical task, no code given)
200
+
201
+ **User input:**
202
+ > I need claude to review my python code for bugs
203
+
204
+ **Your output:**
205
+
206
+ ````
207
+ ```
208
+ You're going to review Python code I share with you. Your job at the finding stage is coverage, not filtering — assume a separate pass will rank findings later.
209
+
210
+ When I paste the code, report every issue you find, including ones you're uncertain about or consider low-severity. For each finding, include:
211
+ - **Location** — file and line number(s)
212
+ - **Issue** — what's wrong, in one sentence
213
+ - **Why it matters** — the concrete failure mode (incorrect output, crash, security risk, race condition, etc.)
214
+ - **Confidence** — high / medium / low
215
+ - **Severity** — high / medium / low
216
+ - **Suggested fix** — a minimal change that addresses the issue
217
+
218
+ Cover at minimum: logic errors, off-by-one and boundary issues, mutable default arguments, exception handling gaps, race conditions and concurrency issues, resource leaks (files, connections, locks), input validation at trust boundaries, and any deviation from the code's apparent intent.
219
+
220
+ Do not filter for importance at this stage. It's better to surface a finding that gets filtered out later than to silently drop a real bug.
221
+
222
+ After listing findings, end with a single-paragraph overall assessment of code quality and the top 3 highest-severity issues to fix first.
223
+
224
+ Ask me to paste the code when you're ready.
225
+
226
+ Think before answering
227
+ ```
228
+ ````
229
+
230
+ ### Example 4 — Case A (real content provided, no follow-up needed)
231
+
232
+ **User input:**
233
+ > rewrite this so it's clearer: "Hey can you help me figure out whether to take the offer from Stripe vs the one from Anthropic. Stripe is paying 280k base + 60k bonus + 100k stock per year vesting over 4. Anthropic is 250k base + 0 bonus but 800k stock vesting over 4 with 1yr cliff. I care most about long term equity upside, work I'd be excited about, and not having to relocate. Stripe wants me in SF 3 days a week, Anthropic is fully remote."
234
+
235
+ **Your output:**
236
+
237
+ ````
238
+ ```
239
+ I'm deciding between two job offers and want your help thinking it through carefully.
240
+
241
+ **My priorities, in order:**
242
+ 1. Long-term equity upside
243
+ 2. Work I'd be excited about
244
+ 3. Avoiding relocation
245
+
246
+ **Offer A — Stripe**
247
+ - $280k base
248
+ - $60k annual bonus
249
+ - $100k/year stock, vesting over 4 years
250
+ - Hybrid: in SF 3 days a week
251
+
252
+ **Offer B — Anthropic**
253
+ - $250k base
254
+ - No annual bonus
255
+ - $800k stock, vesting over 4 years with a 1-year cliff
256
+ - Fully remote
257
+
258
+ Walk me through:
259
+ 1. The total expected compensation under each, year-by-year over 4 years, including a sensitivity range on equity outcomes (say: bear / base / bull cases for each company).
260
+ 2. How each offer scores against my three priorities, ranked.
261
+ 3. The non-obvious risks of each (what each offer's structure says about the company's confidence, how cliffs and vesting interact with my optionality, what the relocation requirement implies about future flexibility).
262
+ 4. Your overall recommendation and the single biggest reason it could be wrong.
263
+
264
+ Be direct. Don't hedge with "it depends on what you value" — I told you what I value.
265
+
266
+ Think before answering
267
+ ```
268
+ ````
269
+
270
+ The user gave the actual numbers and constraints. They're baked in. No `[insert offer details]` block. The prompt is done.
271
+
272
+ ### Example 5 — simple task
273
+
274
+ **User input:**
275
+ > write me a haiku about coffee
276
+
277
+ **Your output:**
278
+
279
+ ````
280
+ ```
281
+ Write a haiku about coffee. Follow the traditional 5-7-5 syllable structure. Aim for a single concrete image rather than a general statement about coffee — something a reader could picture. Avoid clichés like "morning steam" and "liquid gold".
282
+
283
+ Think before answering
284
+ ```
285
+ ````
286
+
287
+ Notice the simple task doesn't get XML tags, a role, or a sectioning — and there's nothing to bake in. Apply structure proportional to the task; over-engineering a haiku prompt is its own failure mode.
288
+
289
+ ## Edge cases
290
+
291
+ **The user pastes a prompt and asks "is this good?"** They want it rewritten regardless. Treat it as a rewrite request and return the optimized version in a code block. No commentary.
292
+
293
+ **The user gives you a Claude system prompt or API-style prompt with parameters.** Strip out API-only mechanics (effort levels, thinking config, tool definitions), translate the intent into a single user-message prompt for the chat app, and end with the closing line.
294
+
295
+ **The user wants the prompt to ask Claude to do many small things.** Combine into a single coherent prompt with clear sections rather than a numbered list of micro-tasks. Opus 4.7 handles long, well-structured asks well.
296
+
297
+ **The user's input is already excellent.** Tighten where you can, add the closing line, return it. Don't add ceremony for its own sake.
298
+
299
+ **The user input is in a language other than English.** Write the optimized prompt in the same language. Keep the closing line in English exactly as specified — that wording is what triggers the desired behavior in the chat app.
300
+
301
+ **You're tempted to write a `<context>` or `<input>` block expecting the user to fill it.** Don't. That's Rule 1. Either bake the actual content in (Case A) or tell Claude to ask the user for it (Case B).
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "url-get",
3
+ "description": "Faithful page retrieval. Provides url-get — fetches a server-rendered web page over HTTP, cleans the HTML to markdown with no model in the path (so there is nothing to refuse on copyright), and writes that verbatim copy to an account-scoped reference file. Separately produces a transformative summary via a short Claude subprocess. Returns { summary, referencePath } only — the verbatim markdown is never injected wholesale; the agent greps the reference file for passages and librarian reads it directly to ingest. This is the tool to use instead of native WebFetch when a faithful copy of a page is needed (e.g. ingesting the operator's own published writing): WebFetch refuses to reproduce copyrighted text and returns only a summary. Server-rendered HTML only — no JavaScript execution (JS-rendered pages use the browser MCP). A bot-challenge or empty page fails with an explicit error and writes no reference file.",
4
+ "version": "0.1.0",
5
+ "author": {
6
+ "name": "Rubytech LLC"
7
+ },
8
+ "mcpServers": {
9
+ "url-get": {
10
+ "type": "stdio",
11
+ "command": "node",
12
+ "args": [
13
+ "${CLAUDE_PLUGIN_ROOT}/mcp/dist/index.js"
14
+ ]
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,86 @@
1
+ ---
2
+ name: url-get
3
+ mcp:
4
+ command: node
5
+ args:
6
+ - ${PLATFORM_ROOT}/lib/mcp-spawn-tee/dist/index.js
7
+ - ${PLATFORM_ROOT}/plugins/url-get/mcp/dist/index.js
8
+ env:
9
+ MCP_SPAWN_TEE_NAME: url-get
10
+ LOG_DIR: ${LOG_DIR}
11
+ PLATFORM_ROOT: ${PLATFORM_ROOT}
12
+ ACCOUNT_ID: ${ACCOUNT_ID}
13
+ SESSION_ID: ${SESSION_ID}
14
+ mcp-manifest: auto
15
+ description: "Faithful page retrieval. Provides url-get — fetches a server-rendered web page over HTTP, cleans the HTML to markdown with no model in the path (so there is nothing to refuse on copyright), and writes that verbatim copy to an account-scoped reference file. Separately produces a transformative summary via a short Claude subprocess. Returns { summary, referencePath } only — the verbatim markdown is never injected wholesale; the agent greps the reference file for passages and librarian reads it directly to ingest. This is the tool to use instead of native WebFetch when a faithful copy of a page is needed (e.g. ingesting the operator's own published writing): WebFetch refuses to reproduce copyrighted text and returns only a summary. Server-rendered HTML only — no JavaScript execution (JS-rendered pages use the browser MCP). A bot-challenge or empty page fails with an explicit error and writes no reference file."
16
+ tools:
17
+ - name: url-get
18
+ publicAllowlist: false
19
+ adminAllowlist: true
20
+ always: true
21
+ embed: false
22
+ ---
23
+
24
+ # url-get
25
+
26
+ ## What it does
27
+
28
+ A single MCP tool, `url-get`, takes a URL and returns two artefacts produced by
29
+ two different mechanisms:
30
+
31
+ - **Verbatim** — an HTTP GET followed by HTML→markdown cleanup, written to an
32
+ account-scoped reference file at `$ACCOUNT_DIR/url-get/<url-hash>.md`. No model
33
+ sits in this path, so there is nothing for a copyright refusal to act on. This
34
+ file is the ground truth.
35
+ - **Summary** — a transformative summary of the cleaned text, produced by a
36
+ short `claude --print` subprocess. Being transformative, it does not trip the
37
+ copyright refusal either.
38
+
39
+ Only `{ summary, referencePath }` returns to the conversation. The verbatim
40
+ markdown is never injected wholesale: the agent greps the reference file when it
41
+ needs a specific passage, and `librarian` reads the file directly when the
42
+ operator chooses to ingest it.
43
+
44
+ ## Why it exists
45
+
46
+ The only built-in page-retrieval tool is Claude's native WebFetch, whose refusal
47
+ to reproduce copyrighted text lives in an internal post-fetch model — not in the
48
+ source site and not in the outer prompt, so reframing cannot move it. A knowledge
49
+ worker ingesting their own published writing (e.g. a Substack post) hits the same
50
+ wall, because WebFetch cannot verify authorship. WebFetch is also structurally
51
+ wrong for ingestion even when it does not refuse: it returns only a summary, never
52
+ the verbatim source. `url-get` keeps WebFetch's two useful behaviours (HTML
53
+ cleanup and a summary), adds the verbatim artefact, and removes the model from the
54
+ verbatim path entirely.
55
+
56
+ ## Surface boundaries
57
+
58
+ - **Server-rendered HTML only.** `url-get` does not execute JavaScript — the same
59
+ coverage limit as a plain fetch. JS-rendered pages are handled by the
60
+ pre-installed browser MCP (Task 492).
61
+ - **No graph write.** `url-get` writes a reference file and returns a summary; it
62
+ never touches Neo4j. Ingestion is `librarian`'s job, reading the reference file.
63
+ - **Verbatim is not size-capped** — it never enters the conversation, so there is
64
+ nothing to cap. The summary input is capped only to bound subprocess cost.
65
+ - **No caching.** Every call fetches fresh.
66
+ - A page that returns a bot-challenge interstitial or an empty body fails with an
67
+ explicit error (`challenge` / `empty`) and writes no reference file — never a
68
+ reference file full of challenge-page HTML.
69
+
70
+ ## Failure modes
71
+
72
+ `url-get` returns an error envelope (never throws to the caller) for: `fetch`
73
+ (network/DNS/TLS/timeout), `http` (non-2xx status), `non-html` (unsupported
74
+ content-type), `challenge` (bot interstitial), `empty` (no readable text), and
75
+ `no-account-dir` (storage unresolvable). The summary is best-effort: if the
76
+ subprocess fails, the call still succeeds with `summarized: false` and the
77
+ reference file intact — the verbatim artefact is the contract, the summary is
78
+ derived.
79
+
80
+ ## Enabling
81
+
82
+ `always: true` — the plugin auto-installs on every brand and is reachable by the
83
+ spawned PTY agent on device; it is never pulled mid-session. The tool is
84
+ admin-allowlisted (`adminAllowlist: true`) and is on the `tools:` list of the
85
+ `research-assistant`, `librarian`, and `personal-assistant` specialists. It is
86
+ not exposed to public agents (`publicAllowlist: false`).
@@ -0,0 +1,9 @@
1
+ /**
2
+ * MCP server entrypoint for the url-get plugin. Registers one tool, `url-get`,
3
+ * on the standard stdio transport. Module init must never throw on missing
4
+ * per-account env — plugin-system spawn enumerates tools/list with empty env,
5
+ * and any boot throw empties the registry. The tool reads ACCOUNT_DIR at call
6
+ * time and returns an error envelope when storage cannot be resolved.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * MCP server entrypoint for the url-get plugin. Registers one tool, `url-get`,
3
+ * on the standard stdio transport. Module init must never throw on missing
4
+ * per-account env — plugin-system spawn enumerates tools/list with empty env,
5
+ * and any boot throw empties the registry. The tool reads ACCOUNT_DIR at call
6
+ * time and returns an error envelope when storage cannot be resolved.
7
+ */
8
+ import { initStderrTee } from "../../../../lib/mcp-stderr-tee/dist/index.js";
9
+ initStderrTee("url-get");
10
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
11
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
12
+ import { eagerTool } from "../../../../lib/mcp-eager/dist/index.js";
13
+ import { z } from "zod";
14
+ import { urlGet } from "./tools/url-get.js";
15
+ const server = new McpServer({
16
+ name: "url-get",
17
+ version: "0.1.0",
18
+ });
19
+ eagerTool(server, "url-get", "Fetch a server-rendered web page and produce two artefacts. (1) VERBATIM: the page is fetched over HTTP and cleaned to markdown with no model in the path, then written to an account-scoped reference file — this is the faithful ground-truth copy, never returned inline. (2) SUMMARY: a transformative summary of that text. Returns { summary, referencePath } — grep the reference file for specific passages rather than asking for the whole page; librarian reads it directly to ingest. Use this instead of WebFetch when you need a faithful copy of a page (e.g. ingesting the operator's own writing) — WebFetch refuses to reproduce copyrighted text and only ever returns a summary. Handles server-rendered HTML only (no JavaScript execution). A page that returns a bot-challenge or empty body fails with an explicit error and writes no file.", {
20
+ url: z.string().url().describe("Absolute http(s) URL of the page to fetch."),
21
+ }, async (args) => {
22
+ const result = await urlGet(args);
23
+ if (!result.ok) {
24
+ return {
25
+ isError: true,
26
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
27
+ };
28
+ }
29
+ return {
30
+ content: [
31
+ {
32
+ type: "text",
33
+ text: JSON.stringify({
34
+ summary: result.summary,
35
+ referencePath: result.referencePath,
36
+ url: result.url,
37
+ httpStatus: result.httpStatus,
38
+ bytes: result.bytes,
39
+ summarized: result.summarized,
40
+ }, null, 2),
41
+ },
42
+ ],
43
+ };
44
+ });
45
+ async function main() {
46
+ const transport = new StdioServerTransport();
47
+ await server.connect(transport);
48
+ }
49
+ main().catch((err) => {
50
+ console.error("[url-get] fatal:", err);
51
+ process.exit(1);
52
+ });
53
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,8CAA8C,CAAC;AAC7E,aAAa,CAAC,SAAS,CAAC,CAAC;AAEzB,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,SAAS,CACP,MAAM,EACN,SAAS,EACT,s0BAAs0B,EACt0B;IACE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,4CAA4C,CAAC;CAC7E,EACD,KAAK,EAAE,IAAqB,EAAE,EAAE;IAC9B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACf,OAAO;YACL,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SAC5E,CAAC;IACJ,CAAC;IACD,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAClB;oBACE,OAAO,EAAE,MAAM,CAAC,OAAO;oBACvB,aAAa,EAAE,MAAM,CAAC,aAAa;oBACnC,GAAG,EAAE,MAAM,CAAC,GAAG;oBACf,UAAU,EAAE,MAAM,CAAC,UAAU;oBAC7B,KAAK,EAAE,MAAM,CAAC,KAAK;oBACnB,UAAU,EAAE,MAAM,CAAC,UAAU;iBAC9B,EACD,IAAI,EACJ,CAAC,CACF;aACF;SACF;KACF,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;IACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { spawn as realSpawn } from "node:child_process";
2
+ type SpawnFn = typeof realSpawn;
3
+ /** Run the summary. Throws on every failure mode (the caller decides whether a
4
+ * summary failure should degrade gracefully — the verbatim file is already on
5
+ * disk by the time this runs). */
6
+ export declare function summarise(url: string, text: string, _spawn?: SpawnFn): Promise<string>;
7
+ export {};
8
+ //# sourceMappingURL=summarise.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summarise.d.ts","sourceRoot":"","sources":["../../src/lib/summarise.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAQxD,KAAK,OAAO,GAAG,OAAO,SAAS,CAAC;AAchC;;mCAEmC;AACnC,wBAAsB,SAAS,CAC7B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,OAAmB,GAC1B,OAAO,CAAC,MAAM,CAAC,CAkDjB"}
@@ -0,0 +1,83 @@
1
+ // Transformative summary of fetched page text via a Claude Code subprocess.
2
+ //
3
+ // VALIDATE TEXT ──▶ SPAWN claude --print --model <haiku> --max-turns 1 ──▶ STDOUT
4
+ // │ │ │
5
+ // ├─ empty → throw ├─ ENOENT (claude not in PATH) → throw │
6
+ // │ ├─ non-zero exit → throw (stderr + stdout) │
7
+ // │ ├─ timeout → SIGTERM → throw │
8
+ // │ └─ empty stdout → throw │
9
+ // └───────────────────────────────────────────────────────────▶ return text
10
+ //
11
+ // Claude Code handles its own OAuth internally — no API key, no SDK. This is
12
+ // the same mechanism the workflows plugin uses for LLM steps. The summary is
13
+ // transformative, so it does not trip WebFetch's copyright refusal; the
14
+ // verbatim path keeps the model out entirely.
15
+ import { spawn as realSpawn } from "node:child_process";
16
+ /** Haiku is the right tier for a one-shot summary (cheap, fast). Overridable
17
+ * via env for forward-compat with model id changes. */
18
+ const SUMMARY_MODEL = process.env.URL_GET_SUMMARY_MODEL ?? "claude-haiku-4-5";
19
+ const SUMMARY_TIMEOUT_MS = 60_000;
20
+ const MAX_STDERR_BYTES = 4096;
21
+ /** Builds the summarisation prompt. A single principled instruction, not a
22
+ * checklist of conditions — per the project's LLM-classification doctrine,
23
+ * a prescriptive rule list turns the model into a brittle pattern matcher. */
24
+ function buildPrompt(url, text) {
25
+ return (`Summarise the page below for a reader deciding whether to open the full text. ` +
26
+ `Capture what the page is, its main claims, and anything that would matter to ` +
27
+ `someone searching for it later. Write only the summary — no preamble.\n\n` +
28
+ `Source: ${url}\n\n---\n${text}`);
29
+ }
30
+ /** Run the summary. Throws on every failure mode (the caller decides whether a
31
+ * summary failure should degrade gracefully — the verbatim file is already on
32
+ * disk by the time this runs). */
33
+ export async function summarise(url, text, _spawn = realSpawn) {
34
+ if (!text.trim()) {
35
+ throw new Error("nothing to summarise — cleaned text is empty");
36
+ }
37
+ const prompt = buildPrompt(url, text);
38
+ const args = [
39
+ "--print",
40
+ "--model",
41
+ SUMMARY_MODEL,
42
+ "--max-turns",
43
+ "1",
44
+ "--permission-mode",
45
+ "dontAsk",
46
+ prompt,
47
+ ];
48
+ return new Promise((resolve, reject) => {
49
+ const proc = _spawn("claude", args, { stdio: ["ignore", "pipe", "pipe"] });
50
+ let stdout = "";
51
+ let stderr = "";
52
+ proc.stdout?.on("data", (chunk) => {
53
+ stdout += chunk.toString("utf-8");
54
+ });
55
+ proc.stderr?.on("data", (chunk) => {
56
+ if (stderr.length < MAX_STDERR_BYTES) {
57
+ stderr += chunk.toString("utf-8").slice(0, MAX_STDERR_BYTES - stderr.length);
58
+ }
59
+ });
60
+ const timer = setTimeout(() => {
61
+ proc.kill("SIGTERM");
62
+ reject(new Error(`summary timed out after ${SUMMARY_TIMEOUT_MS}ms`));
63
+ }, SUMMARY_TIMEOUT_MS);
64
+ proc.on("close", (code) => {
65
+ clearTimeout(timer);
66
+ if (code !== 0) {
67
+ const tail = stderr.trim() ? ` stderr: ${stderr.trim()}` : "";
68
+ reject(new Error(`claude exited ${code}${tail}`));
69
+ return;
70
+ }
71
+ if (!stdout.trim()) {
72
+ reject(new Error("claude returned an empty summary"));
73
+ return;
74
+ }
75
+ resolve(stdout.trim());
76
+ });
77
+ proc.on("error", (err) => {
78
+ clearTimeout(timer);
79
+ reject(new Error(`failed to spawn claude: ${err.message}`));
80
+ });
81
+ });
82
+ }
83
+ //# sourceMappingURL=summarise.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summarise.js","sourceRoot":"","sources":["../../src/lib/summarise.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export interface UrlGetParams {
2
+ url: string;
3
+ }
4
+ export type UrlGetError = "fetch" | "http" | "non-html" | "challenge" | "empty" | "no-account-dir";
5
+ export type UrlGetResult = {
6
+ ok: true;
7
+ url: string;
8
+ httpStatus: number;
9
+ bytes: number;
10
+ referencePath: string;
11
+ summary: string;
12
+ summarized: boolean;
13
+ } | {
14
+ ok: false;
15
+ url: string;
16
+ error: UrlGetError;
17
+ message: string;
18
+ httpStatus?: number;
19
+ };
20
+ export declare function urlGet(params: UrlGetParams): Promise<UrlGetResult>;
21
+ //# sourceMappingURL=url-get.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url-get.d.ts","sourceRoot":"","sources":["../../src/tools/url-get.ts"],"names":[],"mappings":"AAsBA,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,OAAO,GAAG,gBAAgB,CAAC;AAEnG,MAAM,MAAM,YAAY,GACpB;IACE,EAAE,EAAE,IAAI,CAAC;IACT,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;CACrB,GACD;IACE,EAAE,EAAE,KAAK,CAAC;IACV,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAyCN,wBAAsB,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAqGxE"}