@mindstudio-ai/remy 0.1.201 → 0.1.203

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/headless.js CHANGED
@@ -313,6 +313,10 @@ Current date: ${now}
313
313
  {{compiled/agent-interfaces.md}}
314
314
  </building_agent_interfaces>
315
315
 
316
+ <building_mcp_interfaces>
317
+ {{compiled/mcp-interfaces.md}}
318
+ </building_mcp_interfaces>
319
+
316
320
  <media_cdn>
317
321
  {{compiled/media-cdn.md}}
318
322
  </media_cdn>
@@ -3576,6 +3580,13 @@ var MODEL_SURFACES = {
3576
3580
  modelType: "text",
3577
3581
  userPickable: true
3578
3582
  },
3583
+ copyEditor: {
3584
+ default: "claude-4-6-sonnet",
3585
+ label: "Copy Agent",
3586
+ description: "Tightens prose and copy across your app and its launch materials so it reads sharp and human, never machine-made.",
3587
+ modelType: "text",
3588
+ userPickable: true
3589
+ },
3579
3590
  imageGeneration: {
3580
3591
  default: "seedream-4.5",
3581
3592
  label: "Image Generation",
@@ -4541,28 +4552,12 @@ async function execute7(input, onLog, context) {
4541
4552
  });
4542
4553
  }
4543
4554
 
4544
- // src/subagents/designExpert/tools/index.ts
4545
- var tools = {
4546
- searchGoogle: searchGoogle_exports,
4547
- scrapeWebUrl: scrapeWebUrl_exports,
4548
- analyzeDesign: analyzeDesign_exports,
4549
- analyzeImage: analyzeImage_exports,
4550
- screenshot: screenshot_exports,
4551
- generateImages: generateImages_exports,
4552
- editImages: editImages_exports
4553
- };
4554
- var DESIGN_EXPERT_TOOLS = [
4555
- ...COMMON_READ_TOOLS,
4556
- ...Object.values(tools).map((t) => t.definition)
4557
- ];
4558
- async function executeDesignExpertTool(name, input, context, toolCallId, onLog) {
4559
- const tool = tools[name];
4560
- if (!tool) {
4561
- return `Error: unknown tool "${name}"`;
4562
- }
4563
- const childContext = context && toolCallId ? deriveContext(context, toolCallId) : context;
4564
- return tool.execute(input, onLog, childContext);
4565
- }
4555
+ // src/subagents/designExpert/tools/polishCopy.ts
4556
+ var polishCopy_exports = {};
4557
+ __export(polishCopy_exports, {
4558
+ definition: () => definition8,
4559
+ execute: () => execute8
4560
+ });
4566
4561
 
4567
4562
  // src/subagents/common/context.ts
4568
4563
  import fs17 from "fs";
@@ -4693,7 +4688,7 @@ This is a capable, stable platform used in production by 100k+ users. Build with
4693
4688
  - Full-stack web apps \u2014 social platforms, membership sites, marketplaces, booking systems, community hubs \u2014 multi-user apps with auth, data, UI
4694
4689
  - Automations with no UI \u2014 cron jobs, webhook handlers, email processors, data sync pipelines
4695
4690
  - Marketing & launch pages \u2014 landing pages, waitlist pages with referral mechanics, product sites with scroll animations
4696
- - Bots \u2014 Discord slash-command bots, Telegram bots, MCP tool servers for AI assistants
4691
+ - Agent tools \u2014 MCP tool servers for AI assistants
4697
4692
  - Creative/interactive projects \u2014 browser games with p5.js or Three.js, interactive visualizations, generative art, portfolio sites
4698
4693
  - API services \u2014 backend logic exposed as REST endpoints
4699
4694
  - Simple static sites \u2014 no backend needed, just a web interface with a build step
@@ -4708,8 +4703,6 @@ Each interface type invokes the same backend methods. Methods don't know which i
4708
4703
  - API \u2014 auto-generated REST endpoints for every method
4709
4704
  - Cron \u2014 scheduled jobs on a configurable interval
4710
4705
  - Webhook \u2014 HTTP endpoints that trigger methods
4711
- - Discord \u2014 slash-command bots
4712
- - Telegram \u2014 message-handling bots
4713
4706
  - Email \u2014 inbound email processing
4714
4707
  - MCP \u2014 tool servers for AI assistants
4715
4708
  - Agent \u2014 conversational LLM interface with tool access to backend methods
@@ -4734,6 +4727,103 @@ The first-party SDK (@mindstudio-ai/agent) provides access to 200+ AI models (Op
4734
4727
  </platform_brief>`;
4735
4728
  }
4736
4729
 
4730
+ // src/subagents/copyEditor/tools.ts
4731
+ var COPY_EDITOR_TOOLS = [...COMMON_READ_TOOLS];
4732
+
4733
+ // src/subagents/copyEditor/index.ts
4734
+ var BASE_PROMPT2 = readAsset("subagents/copyEditor", "prompt.md");
4735
+ var copyEditorTool = {
4736
+ clearable: false,
4737
+ definition: {
4738
+ name: "copyEditor",
4739
+ description: "Hand it user-facing copy and it hands back a sharper version \u2014 better structured for its audience and free of the overused words, telltale constructions, and rhythms that make text read as AI-generated. Think of it as a design expert for words: it elevates how the copy communicates and strips the AI fingerprints, but it never invents facts or claims you didn't give it. Use it on anything users will read: in-app strings, empty states, errors, the Build Overview, deck copy, launch posts, Slack announcements. Readonly.",
4740
+ inputSchema: {
4741
+ type: "object",
4742
+ properties: {
4743
+ task: {
4744
+ type: "string",
4745
+ description: "The copy to polish, plus what it's for \u2014 the medium, the audience, any brand voice. Paste the text verbatim."
4746
+ }
4747
+ },
4748
+ required: ["task"]
4749
+ }
4750
+ },
4751
+ async execute(input, context) {
4752
+ if (!context) {
4753
+ return "Error: copy editor requires execution context";
4754
+ }
4755
+ const specIndex = loadSpecIndex();
4756
+ const parts = [BASE_PROMPT2];
4757
+ parts.push("<!-- cache_breakpoint -->");
4758
+ if (specIndex) {
4759
+ parts.push(specIndex);
4760
+ }
4761
+ const system = parts.join("\n\n");
4762
+ const result = await runSubAgent({
4763
+ system,
4764
+ task: input.task,
4765
+ tools: COPY_EDITOR_TOOLS,
4766
+ externalTools: /* @__PURE__ */ new Set(),
4767
+ executeTool: (name, toolInput) => executeTool(name, toolInput, context),
4768
+ apiConfig: context.apiConfig,
4769
+ model: resolveModel("copyEditor", context.models, context.model),
4770
+ subAgentId: "copyEditor",
4771
+ signal: context.signal,
4772
+ parentToolId: context.toolCallId,
4773
+ requestId: context.requestId,
4774
+ onEvent: context.onEvent,
4775
+ resolveExternalTool: context.resolveExternalTool,
4776
+ toolRegistry: context.toolRegistry
4777
+ });
4778
+ context.subAgentMessages?.set(context.toolCallId, result.messages);
4779
+ return result.text;
4780
+ }
4781
+ };
4782
+
4783
+ // src/subagents/designExpert/tools/polishCopy.ts
4784
+ var definition8 = {
4785
+ clearable: false,
4786
+ name: "polishCopy",
4787
+ description: "Hand off any user-facing copy you've written \u2014 headlines, captions, labels, body text \u2014 and get back a sharper version: better built for its audience and free of the fingerprints that make writing read as AI. It elevates how the copy communicates without inventing facts or claims you didn't give it. Give it the text plus what it's for (where it appears, the audience).",
4788
+ inputSchema: {
4789
+ type: "object",
4790
+ properties: {
4791
+ task: {
4792
+ type: "string",
4793
+ description: "The copy to polish, plus what it's for \u2014 where it appears, the audience, any brand voice."
4794
+ }
4795
+ },
4796
+ required: ["task"]
4797
+ }
4798
+ };
4799
+ async function execute8(input, _onLog, context) {
4800
+ return copyEditorTool.execute(input, context);
4801
+ }
4802
+
4803
+ // src/subagents/designExpert/tools/index.ts
4804
+ var tools = {
4805
+ searchGoogle: searchGoogle_exports,
4806
+ scrapeWebUrl: scrapeWebUrl_exports,
4807
+ analyzeDesign: analyzeDesign_exports,
4808
+ analyzeImage: analyzeImage_exports,
4809
+ screenshot: screenshot_exports,
4810
+ generateImages: generateImages_exports,
4811
+ editImages: editImages_exports,
4812
+ polishCopy: polishCopy_exports
4813
+ };
4814
+ var DESIGN_EXPERT_TOOLS = [
4815
+ ...COMMON_READ_TOOLS,
4816
+ ...Object.values(tools).map((t) => t.definition)
4817
+ ];
4818
+ async function executeDesignExpertTool(name, input, context, toolCallId, onLog) {
4819
+ const tool = tools[name];
4820
+ if (!tool) {
4821
+ return `Error: unknown tool "${name}"`;
4822
+ }
4823
+ const childContext = context && toolCallId ? deriveContext(context, toolCallId) : context;
4824
+ return tool.execute(input, onLog, childContext);
4825
+ }
4826
+
4737
4827
  // src/subagents/designExpert/data/sampleCache.ts
4738
4828
  import fs18 from "fs";
4739
4829
  var SAMPLE_FILE = ".remy-design-sample.json";
@@ -5173,11 +5263,11 @@ Respond only with the complete HTML file and absolutely no other text. Your resp
5173
5263
  }
5174
5264
 
5175
5265
  // src/subagents/productVision/prompt.ts
5176
- var BASE_PROMPT2 = readAsset("subagents/productVision", "prompt.md");
5266
+ var BASE_PROMPT3 = readAsset("subagents/productVision", "prompt.md");
5177
5267
  function getProductVisionPrompt() {
5178
5268
  const specIndex = loadSpecIndex();
5179
5269
  const roadmapIndex = loadRoadmapIndex();
5180
- const parts = [BASE_PROMPT2, loadPlatformBrief()];
5270
+ const parts = [BASE_PROMPT3, loadPlatformBrief()];
5181
5271
  parts.push("<!-- cache_breakpoint -->");
5182
5272
  if (specIndex) {
5183
5273
  parts.push(specIndex);
@@ -5301,7 +5391,7 @@ var SANITY_CHECK_TOOLS = [
5301
5391
  ];
5302
5392
 
5303
5393
  // src/subagents/codeSanityCheck/index.ts
5304
- var BASE_PROMPT3 = readAsset("subagents/codeSanityCheck", "prompt.md");
5394
+ var BASE_PROMPT4 = readAsset("subagents/codeSanityCheck", "prompt.md");
5305
5395
  var codeSanityCheckTool = {
5306
5396
  clearable: false,
5307
5397
  definition: {
@@ -5323,7 +5413,7 @@ var codeSanityCheckTool = {
5323
5413
  return "Error: code sanity check requires execution context";
5324
5414
  }
5325
5415
  const specIndex = loadSpecIndex();
5326
- const parts = [BASE_PROMPT3, loadPlatformBrief()];
5416
+ const parts = [BASE_PROMPT4, loadPlatformBrief()];
5327
5417
  parts.push("<!-- cache_breakpoint -->");
5328
5418
  if (specIndex) {
5329
5419
  parts.push(specIndex);
@@ -5399,7 +5489,7 @@ var DESIGN_BRIEF = `We are building the Build Overview for this app \u2014 the h
5399
5489
  Take the plain-language copy in <overview_copy> and lay it out and skin it into a single, beautiful, self-contained HTML document in the app's own brand. If <current_overview> is non-empty, use it as your starting point and preserve its established skin, updating only what the copy changed.
5400
5490
 
5401
5491
  ### The single hard rule
5402
- Preserve every fact in <overview_copy> exactly \u2014 every number, name, label, and claim. Do not add, drop, soften, reword, or invent any fact. You own layout, typography, and visual design only; the substance and the words are fixed. A single wrong number breaks this document's entire purpose.
5492
+ The copy in <overview_copy> is final \u2014 it was authored and edited before it reached you. Treat it as locked content to typeset, not a draft to improve. Reproduce the words exactly: do not rewrite, rephrase, shorten, expand, reorder, or "polish" them, and do not run them through any copy tool. This is the opposite of your usual role \u2014 here you own layout, typography, and visual design only, and the words (every number, name, label, claim, and sentence) are fixed. A single changed word or wrong number breaks this document's purpose.
5403
5493
 
5404
5494
  ### What it is (and is not)
5405
5495
  - A typeset reference dossier: composed, dense, a little cool \u2014 substantial at a glance, then readable. Density communicates substance; sparse and airy reads as "not much here."
@@ -5438,13 +5528,13 @@ var buildOverviewTool = {
5438
5528
  clearable: false,
5439
5529
  definition: {
5440
5530
  name: "writeBuildOverview",
5441
- description: "Generate or refresh the Build Overview \u2014 the project's home page in the Spec tab: a single-page, plain-language reference of everything the app actually contains, including the parts the user can't see (data stores, backend operations, access and roles, background jobs, seeded scenarios, the design system). You author the full copy: read the manifest and spec and state, plainly and exactly, what genuinely exists \u2014 real names and accurate counts \u2014 in calm, declarative, present-tense outcome language, with no persuasion or hype. Describe only what exists. Pass the complete copy as `content`; the design expert lays it out and skins it to the app's brand without altering any of your facts. Generate it at the end of a build and refresh it after meaningful work.",
5531
+ description: "Generate or refresh the Build Overview \u2014 the project's home page in the Spec tab: a single-page, plain-language reference of everything the app actually contains, including the parts the user can't see (data stores, backend operations, access and roles, background jobs, seeded scenarios, the design system). You author the full copy: read the manifest and spec and state, plainly and exactly, what genuinely exists \u2014 real names and accurate counts \u2014 in calm, declarative, present-tense outcome language, with no persuasion or hype. Describe only what exists. Pass the complete copy as `content`; the design expert lays it out and skins it to the app's brand using your copy verbatim \u2014 it typesets your words, it does not rewrite them, so polish the copy before you pass it. Generate it at the end of a build and refresh it after meaningful work.",
5442
5532
  inputSchema: {
5443
5533
  type: "object",
5444
5534
  properties: {
5445
5535
  content: {
5446
5536
  type: "string",
5447
- description: "The full Build Overview copy you authored: everything the app contains, in plain present-tense outcome language, with real names and exact counts. The design expert lays this out and skins it to the brand without changing any fact."
5537
+ description: "The full Build Overview copy you authored: everything the app contains, in plain present-tense outcome language, with real names and exact counts. The design expert lays this out and skins it to the brand verbatim \u2014 it styles your words, it does not rewrite them \u2014 so this should be the final copy."
5448
5538
  }
5449
5539
  },
5450
5540
  required: ["content"]
@@ -5495,6 +5585,7 @@ var ALL_TOOLS = [
5495
5585
  designExpertTool,
5496
5586
  productVisionTool,
5497
5587
  codeSanityCheckTool,
5588
+ copyEditorTool,
5498
5589
  buildOverviewTool,
5499
5590
  compactConversationTool,
5500
5591
  // Post-onboarding
@@ -5531,6 +5622,7 @@ var SUBAGENT_TOOL_NAMES = /* @__PURE__ */ new Set([
5531
5622
  "visualDesignExpert",
5532
5623
  "productVision",
5533
5624
  "codeSanityCheck",
5625
+ "copyEditor",
5534
5626
  "runAutomatedBrowserTest",
5535
5627
  "askMindStudioSdk"
5536
5628
  ]);
package/dist/index.js CHANGED
@@ -1775,7 +1775,7 @@ var init_compaction = __esm({
1775
1775
  "use strict";
1776
1776
  init_api();
1777
1777
  init_assets();
1778
- init_tools6();
1778
+ init_tools7();
1779
1779
  init_logger();
1780
1780
  init_usageLedger();
1781
1781
  log2 = createLogger("compaction");
@@ -1967,6 +1967,10 @@ Current date: ${now}
1967
1967
  {{compiled/agent-interfaces.md}}
1968
1968
  </building_agent_interfaces>
1969
1969
 
1970
+ <building_mcp_interfaces>
1971
+ {{compiled/mcp-interfaces.md}}
1972
+ </building_mcp_interfaces>
1973
+
1970
1974
  <media_cdn>
1971
1975
  {{compiled/media-cdn.md}}
1972
1976
  </media_cdn>
@@ -2102,6 +2106,13 @@ var init_surfaces = __esm({
2102
2106
  modelType: "text",
2103
2107
  userPickable: true
2104
2108
  },
2109
+ copyEditor: {
2110
+ default: "claude-4-6-sonnet",
2111
+ label: "Copy Agent",
2112
+ description: "Tightens prose and copy across your app and its launch materials so it reads sharp and human, never machine-made.",
2113
+ modelType: "text",
2114
+ userPickable: true
2115
+ },
2105
2116
  imageGeneration: {
2106
2117
  default: "seedream-4.5",
2107
2118
  label: "Image Generation",
@@ -2201,7 +2212,7 @@ var init_trigger = __esm({
2201
2212
  "use strict";
2202
2213
  init_compaction();
2203
2214
  init_prompt();
2204
- init_tools6();
2215
+ init_tools7();
2205
2216
  init_logger();
2206
2217
  init_surfaces();
2207
2218
  log3 = createLogger("compaction:trigger");
@@ -5307,44 +5318,6 @@ var init_editImages = __esm({
5307
5318
  }
5308
5319
  });
5309
5320
 
5310
- // src/subagents/designExpert/tools/index.ts
5311
- async function executeDesignExpertTool(name, input, context, toolCallId, onLog) {
5312
- const tool = tools[name];
5313
- if (!tool) {
5314
- return `Error: unknown tool "${name}"`;
5315
- }
5316
- const childContext = context && toolCallId ? deriveContext(context, toolCallId) : context;
5317
- return tool.execute(input, onLog, childContext);
5318
- }
5319
- var tools, DESIGN_EXPERT_TOOLS;
5320
- var init_tools3 = __esm({
5321
- "src/subagents/designExpert/tools/index.ts"() {
5322
- "use strict";
5323
- init_tools6();
5324
- init_tools2();
5325
- init_searchGoogle2();
5326
- init_scrapeWebUrl();
5327
- init_analyzeDesign();
5328
- init_analyzeImage2();
5329
- init_screenshot3();
5330
- init_generateImages();
5331
- init_editImages();
5332
- tools = {
5333
- searchGoogle: searchGoogle_exports,
5334
- scrapeWebUrl: scrapeWebUrl_exports,
5335
- analyzeDesign: analyzeDesign_exports,
5336
- analyzeImage: analyzeImage_exports,
5337
- screenshot: screenshot_exports,
5338
- generateImages: generateImages_exports,
5339
- editImages: editImages_exports
5340
- };
5341
- DESIGN_EXPERT_TOOLS = [
5342
- ...COMMON_READ_TOOLS,
5343
- ...Object.values(tools).map((t) => t.definition)
5344
- ];
5345
- }
5346
- });
5347
-
5348
5321
  // src/subagents/common/context.ts
5349
5322
  import fs16 from "fs";
5350
5323
  import path7 from "path";
@@ -5474,7 +5447,7 @@ This is a capable, stable platform used in production by 100k+ users. Build with
5474
5447
  - Full-stack web apps \u2014 social platforms, membership sites, marketplaces, booking systems, community hubs \u2014 multi-user apps with auth, data, UI
5475
5448
  - Automations with no UI \u2014 cron jobs, webhook handlers, email processors, data sync pipelines
5476
5449
  - Marketing & launch pages \u2014 landing pages, waitlist pages with referral mechanics, product sites with scroll animations
5477
- - Bots \u2014 Discord slash-command bots, Telegram bots, MCP tool servers for AI assistants
5450
+ - Agent tools \u2014 MCP tool servers for AI assistants
5478
5451
  - Creative/interactive projects \u2014 browser games with p5.js or Three.js, interactive visualizations, generative art, portfolio sites
5479
5452
  - API services \u2014 backend logic exposed as REST endpoints
5480
5453
  - Simple static sites \u2014 no backend needed, just a web interface with a build step
@@ -5489,8 +5462,6 @@ Each interface type invokes the same backend methods. Methods don't know which i
5489
5462
  - API \u2014 auto-generated REST endpoints for every method
5490
5463
  - Cron \u2014 scheduled jobs on a configurable interval
5491
5464
  - Webhook \u2014 HTTP endpoints that trigger methods
5492
- - Discord \u2014 slash-command bots
5493
- - Telegram \u2014 message-handling bots
5494
5465
  - Email \u2014 inbound email processing
5495
5466
  - MCP \u2014 tool servers for AI assistants
5496
5467
  - Agent \u2014 conversational LLM interface with tool access to backend methods
@@ -5520,6 +5491,150 @@ var init_context = __esm({
5520
5491
  }
5521
5492
  });
5522
5493
 
5494
+ // src/subagents/copyEditor/tools.ts
5495
+ var COPY_EDITOR_TOOLS;
5496
+ var init_tools3 = __esm({
5497
+ "src/subagents/copyEditor/tools.ts"() {
5498
+ "use strict";
5499
+ init_tools2();
5500
+ COPY_EDITOR_TOOLS = [...COMMON_READ_TOOLS];
5501
+ }
5502
+ });
5503
+
5504
+ // src/subagents/copyEditor/index.ts
5505
+ var BASE_PROMPT2, copyEditorTool;
5506
+ var init_copyEditor = __esm({
5507
+ "src/subagents/copyEditor/index.ts"() {
5508
+ "use strict";
5509
+ init_assets();
5510
+ init_runner();
5511
+ init_context();
5512
+ init_tools7();
5513
+ init_tools3();
5514
+ init_surfaces();
5515
+ BASE_PROMPT2 = readAsset("subagents/copyEditor", "prompt.md");
5516
+ copyEditorTool = {
5517
+ clearable: false,
5518
+ definition: {
5519
+ name: "copyEditor",
5520
+ description: "Hand it user-facing copy and it hands back a sharper version \u2014 better structured for its audience and free of the overused words, telltale constructions, and rhythms that make text read as AI-generated. Think of it as a design expert for words: it elevates how the copy communicates and strips the AI fingerprints, but it never invents facts or claims you didn't give it. Use it on anything users will read: in-app strings, empty states, errors, the Build Overview, deck copy, launch posts, Slack announcements. Readonly.",
5521
+ inputSchema: {
5522
+ type: "object",
5523
+ properties: {
5524
+ task: {
5525
+ type: "string",
5526
+ description: "The copy to polish, plus what it's for \u2014 the medium, the audience, any brand voice. Paste the text verbatim."
5527
+ }
5528
+ },
5529
+ required: ["task"]
5530
+ }
5531
+ },
5532
+ async execute(input, context) {
5533
+ if (!context) {
5534
+ return "Error: copy editor requires execution context";
5535
+ }
5536
+ const specIndex = loadSpecIndex();
5537
+ const parts = [BASE_PROMPT2];
5538
+ parts.push("<!-- cache_breakpoint -->");
5539
+ if (specIndex) {
5540
+ parts.push(specIndex);
5541
+ }
5542
+ const system = parts.join("\n\n");
5543
+ const result = await runSubAgent({
5544
+ system,
5545
+ task: input.task,
5546
+ tools: COPY_EDITOR_TOOLS,
5547
+ externalTools: /* @__PURE__ */ new Set(),
5548
+ executeTool: (name, toolInput) => executeTool(name, toolInput, context),
5549
+ apiConfig: context.apiConfig,
5550
+ model: resolveModel("copyEditor", context.models, context.model),
5551
+ subAgentId: "copyEditor",
5552
+ signal: context.signal,
5553
+ parentToolId: context.toolCallId,
5554
+ requestId: context.requestId,
5555
+ onEvent: context.onEvent,
5556
+ resolveExternalTool: context.resolveExternalTool,
5557
+ toolRegistry: context.toolRegistry
5558
+ });
5559
+ context.subAgentMessages?.set(context.toolCallId, result.messages);
5560
+ return result.text;
5561
+ }
5562
+ };
5563
+ }
5564
+ });
5565
+
5566
+ // src/subagents/designExpert/tools/polishCopy.ts
5567
+ var polishCopy_exports = {};
5568
+ __export(polishCopy_exports, {
5569
+ definition: () => definition8,
5570
+ execute: () => execute8
5571
+ });
5572
+ async function execute8(input, _onLog, context) {
5573
+ return copyEditorTool.execute(input, context);
5574
+ }
5575
+ var definition8;
5576
+ var init_polishCopy = __esm({
5577
+ "src/subagents/designExpert/tools/polishCopy.ts"() {
5578
+ "use strict";
5579
+ init_copyEditor();
5580
+ definition8 = {
5581
+ clearable: false,
5582
+ name: "polishCopy",
5583
+ description: "Hand off any user-facing copy you've written \u2014 headlines, captions, labels, body text \u2014 and get back a sharper version: better built for its audience and free of the fingerprints that make writing read as AI. It elevates how the copy communicates without inventing facts or claims you didn't give it. Give it the text plus what it's for (where it appears, the audience).",
5584
+ inputSchema: {
5585
+ type: "object",
5586
+ properties: {
5587
+ task: {
5588
+ type: "string",
5589
+ description: "The copy to polish, plus what it's for \u2014 where it appears, the audience, any brand voice."
5590
+ }
5591
+ },
5592
+ required: ["task"]
5593
+ }
5594
+ };
5595
+ }
5596
+ });
5597
+
5598
+ // src/subagents/designExpert/tools/index.ts
5599
+ async function executeDesignExpertTool(name, input, context, toolCallId, onLog) {
5600
+ const tool = tools[name];
5601
+ if (!tool) {
5602
+ return `Error: unknown tool "${name}"`;
5603
+ }
5604
+ const childContext = context && toolCallId ? deriveContext(context, toolCallId) : context;
5605
+ return tool.execute(input, onLog, childContext);
5606
+ }
5607
+ var tools, DESIGN_EXPERT_TOOLS;
5608
+ var init_tools4 = __esm({
5609
+ "src/subagents/designExpert/tools/index.ts"() {
5610
+ "use strict";
5611
+ init_tools7();
5612
+ init_tools2();
5613
+ init_searchGoogle2();
5614
+ init_scrapeWebUrl();
5615
+ init_analyzeDesign();
5616
+ init_analyzeImage2();
5617
+ init_screenshot3();
5618
+ init_generateImages();
5619
+ init_editImages();
5620
+ init_polishCopy();
5621
+ tools = {
5622
+ searchGoogle: searchGoogle_exports,
5623
+ scrapeWebUrl: scrapeWebUrl_exports,
5624
+ analyzeDesign: analyzeDesign_exports,
5625
+ analyzeImage: analyzeImage_exports,
5626
+ screenshot: screenshot_exports,
5627
+ generateImages: generateImages_exports,
5628
+ editImages: editImages_exports,
5629
+ polishCopy: polishCopy_exports
5630
+ };
5631
+ DESIGN_EXPERT_TOOLS = [
5632
+ ...COMMON_READ_TOOLS,
5633
+ ...Object.values(tools).map((t) => t.definition)
5634
+ ];
5635
+ }
5636
+ });
5637
+
5523
5638
  // src/subagents/designExpert/data/sampleCache.ts
5524
5639
  import fs17 from "fs";
5525
5640
  function generateIndices(poolSize, sampleSize) {
@@ -5799,9 +5914,9 @@ var DESCRIPTION, designExpertTool;
5799
5914
  var init_designExpert = __esm({
5800
5915
  "src/subagents/designExpert/index.ts"() {
5801
5916
  "use strict";
5802
- init_tools6();
5917
+ init_tools7();
5803
5918
  init_runner();
5804
- init_tools3();
5919
+ init_tools4();
5805
5920
  init_tools2();
5806
5921
  init_prompt3();
5807
5922
  init_history();
@@ -5881,7 +5996,7 @@ Visual design expert. Describe the situation and what you need \u2014 the agent
5881
5996
 
5882
5997
  // src/subagents/productVision/tools.ts
5883
5998
  var VISION_TOOLS;
5884
- var init_tools4 = __esm({
5999
+ var init_tools5 = __esm({
5885
6000
  "src/subagents/productVision/tools.ts"() {
5886
6001
  "use strict";
5887
6002
  init_tools2();
@@ -6039,7 +6154,7 @@ var init_executor = __esm({
6039
6154
  function getProductVisionPrompt() {
6040
6155
  const specIndex = loadSpecIndex();
6041
6156
  const roadmapIndex = loadRoadmapIndex();
6042
- const parts = [BASE_PROMPT2, loadPlatformBrief()];
6157
+ const parts = [BASE_PROMPT3, loadPlatformBrief()];
6043
6158
  parts.push("<!-- cache_breakpoint -->");
6044
6159
  if (specIndex) {
6045
6160
  parts.push(specIndex);
@@ -6049,14 +6164,14 @@ function getProductVisionPrompt() {
6049
6164
  }
6050
6165
  return parts.join("\n\n");
6051
6166
  }
6052
- var BASE_PROMPT2;
6167
+ var BASE_PROMPT3;
6053
6168
  var init_prompt4 = __esm({
6054
6169
  "src/subagents/productVision/prompt.ts"() {
6055
6170
  "use strict";
6056
6171
  init_assets();
6057
6172
  init_executor();
6058
6173
  init_context();
6059
- BASE_PROMPT2 = readAsset("subagents/productVision", "prompt.md");
6174
+ BASE_PROMPT3 = readAsset("subagents/productVision", "prompt.md");
6060
6175
  }
6061
6176
  });
6062
6177
 
@@ -6065,9 +6180,9 @@ var productVisionTool;
6065
6180
  var init_productVision = __esm({
6066
6181
  "src/subagents/productVision/index.ts"() {
6067
6182
  "use strict";
6068
- init_tools6();
6183
+ init_tools7();
6069
6184
  init_runner();
6070
- init_tools4();
6185
+ init_tools5();
6071
6186
  init_tools2();
6072
6187
  init_executor();
6073
6188
  init_prompt4();
@@ -6139,7 +6254,7 @@ var init_productVision = __esm({
6139
6254
 
6140
6255
  // src/subagents/codeSanityCheck/tools.ts
6141
6256
  var SANITY_CHECK_TOOLS;
6142
- var init_tools5 = __esm({
6257
+ var init_tools6 = __esm({
6143
6258
  "src/subagents/codeSanityCheck/tools.ts"() {
6144
6259
  "use strict";
6145
6260
  init_tools2();
@@ -6194,17 +6309,17 @@ var init_tools5 = __esm({
6194
6309
  });
6195
6310
 
6196
6311
  // src/subagents/codeSanityCheck/index.ts
6197
- var BASE_PROMPT3, codeSanityCheckTool;
6312
+ var BASE_PROMPT4, codeSanityCheckTool;
6198
6313
  var init_codeSanityCheck = __esm({
6199
6314
  "src/subagents/codeSanityCheck/index.ts"() {
6200
6315
  "use strict";
6201
6316
  init_assets();
6202
6317
  init_runner();
6203
6318
  init_context();
6319
+ init_tools7();
6204
6320
  init_tools6();
6205
- init_tools5();
6206
6321
  init_surfaces();
6207
- BASE_PROMPT3 = readAsset("subagents/codeSanityCheck", "prompt.md");
6322
+ BASE_PROMPT4 = readAsset("subagents/codeSanityCheck", "prompt.md");
6208
6323
  codeSanityCheckTool = {
6209
6324
  clearable: false,
6210
6325
  definition: {
@@ -6226,7 +6341,7 @@ var init_codeSanityCheck = __esm({
6226
6341
  return "Error: code sanity check requires execution context";
6227
6342
  }
6228
6343
  const specIndex = loadSpecIndex();
6229
- const parts = [BASE_PROMPT3, loadPlatformBrief()];
6344
+ const parts = [BASE_PROMPT4, loadPlatformBrief()];
6230
6345
  parts.push("<!-- cache_breakpoint -->");
6231
6346
  if (specIndex) {
6232
6347
  parts.push(specIndex);
@@ -6316,7 +6431,7 @@ var init_writeBuildOverview = __esm({
6316
6431
  Take the plain-language copy in <overview_copy> and lay it out and skin it into a single, beautiful, self-contained HTML document in the app's own brand. If <current_overview> is non-empty, use it as your starting point and preserve its established skin, updating only what the copy changed.
6317
6432
 
6318
6433
  ### The single hard rule
6319
- Preserve every fact in <overview_copy> exactly \u2014 every number, name, label, and claim. Do not add, drop, soften, reword, or invent any fact. You own layout, typography, and visual design only; the substance and the words are fixed. A single wrong number breaks this document's entire purpose.
6434
+ The copy in <overview_copy> is final \u2014 it was authored and edited before it reached you. Treat it as locked content to typeset, not a draft to improve. Reproduce the words exactly: do not rewrite, rephrase, shorten, expand, reorder, or "polish" them, and do not run them through any copy tool. This is the opposite of your usual role \u2014 here you own layout, typography, and visual design only, and the words (every number, name, label, claim, and sentence) are fixed. A single changed word or wrong number breaks this document's purpose.
6320
6435
 
6321
6436
  ### What it is (and is not)
6322
6437
  - A typeset reference dossier: composed, dense, a little cool \u2014 substantial at a glance, then readable. Density communicates substance; sparse and airy reads as "not much here."
@@ -6355,13 +6470,13 @@ Respond only with the complete HTML file and absolutely no other text. Your resp
6355
6470
  clearable: false,
6356
6471
  definition: {
6357
6472
  name: "writeBuildOverview",
6358
- description: "Generate or refresh the Build Overview \u2014 the project's home page in the Spec tab: a single-page, plain-language reference of everything the app actually contains, including the parts the user can't see (data stores, backend operations, access and roles, background jobs, seeded scenarios, the design system). You author the full copy: read the manifest and spec and state, plainly and exactly, what genuinely exists \u2014 real names and accurate counts \u2014 in calm, declarative, present-tense outcome language, with no persuasion or hype. Describe only what exists. Pass the complete copy as `content`; the design expert lays it out and skins it to the app's brand without altering any of your facts. Generate it at the end of a build and refresh it after meaningful work.",
6473
+ description: "Generate or refresh the Build Overview \u2014 the project's home page in the Spec tab: a single-page, plain-language reference of everything the app actually contains, including the parts the user can't see (data stores, backend operations, access and roles, background jobs, seeded scenarios, the design system). You author the full copy: read the manifest and spec and state, plainly and exactly, what genuinely exists \u2014 real names and accurate counts \u2014 in calm, declarative, present-tense outcome language, with no persuasion or hype. Describe only what exists. Pass the complete copy as `content`; the design expert lays it out and skins it to the app's brand using your copy verbatim \u2014 it typesets your words, it does not rewrite them, so polish the copy before you pass it. Generate it at the end of a build and refresh it after meaningful work.",
6359
6474
  inputSchema: {
6360
6475
  type: "object",
6361
6476
  properties: {
6362
6477
  content: {
6363
6478
  type: "string",
6364
- description: "The full Build Overview copy you authored: everything the app contains, in plain present-tense outcome language, with real names and exact counts. The design expert lays this out and skins it to the brand without changing any fact."
6479
+ description: "The full Build Overview copy you authored: everything the app contains, in plain present-tense outcome language, with real names and exact counts. The design expert lays this out and skins it to the brand verbatim \u2014 it styles your words, it does not rewrite them \u2014 so this should be the final copy."
6365
6480
  }
6366
6481
  },
6367
6482
  required: ["content"]
@@ -6416,7 +6531,7 @@ function executeTool(name, input, context) {
6416
6531
  return tool.execute(input, context);
6417
6532
  }
6418
6533
  var ALL_TOOLS, CLEARABLE_TOOLS, SUBAGENT_TOOL_NAMES;
6419
- var init_tools6 = __esm({
6534
+ var init_tools7 = __esm({
6420
6535
  "src/tools/index.ts"() {
6421
6536
  "use strict";
6422
6537
  init_readSpec();
@@ -6451,6 +6566,7 @@ var init_tools6 = __esm({
6451
6566
  init_designExpert();
6452
6567
  init_productVision();
6453
6568
  init_codeSanityCheck();
6569
+ init_copyEditor();
6454
6570
  init_scrapeWebUrl2();
6455
6571
  init_writeBuildOverview();
6456
6572
  ALL_TOOLS = [
@@ -6465,6 +6581,7 @@ var init_tools6 = __esm({
6465
6581
  designExpertTool,
6466
6582
  productVisionTool,
6467
6583
  codeSanityCheckTool,
6584
+ copyEditorTool,
6468
6585
  buildOverviewTool,
6469
6586
  compactConversationTool,
6470
6587
  // Post-onboarding
@@ -6501,6 +6618,7 @@ var init_tools6 = __esm({
6501
6618
  "visualDesignExpert",
6502
6619
  "productVision",
6503
6620
  "codeSanityCheck",
6621
+ "copyEditor",
6504
6622
  "runAutomatedBrowserTest",
6505
6623
  "askMindStudioSdk"
6506
6624
  ]);
@@ -7700,7 +7818,7 @@ var init_agent = __esm({
7700
7818
  "src/agent.ts"() {
7701
7819
  "use strict";
7702
7820
  init_api();
7703
- init_tools6();
7821
+ init_tools7();
7704
7822
  init_session();
7705
7823
  init_logger();
7706
7824
  init_usageLedger();
@@ -7708,7 +7826,7 @@ var init_agent = __esm({
7708
7826
  init_statusWatcher();
7709
7827
  init_errors();
7710
7828
  init_cleanMessages();
7711
- init_tools6();
7829
+ init_tools7();
7712
7830
  init_sentinel();
7713
7831
  init_trigger2();
7714
7832
  init_surfaces();
@@ -145,6 +145,7 @@ The intro framing ("you have a lot on your plate") gives the model permission to
145
145
  | `productVision` | Roadmap ownership & product strategy | writeRoadmapItem, updateRoadmapItem, deleteRoadmapItem | Spec files + current roadmap |
146
146
  | `sdkConsultant` | MindStudio SDK architecture | None (shells out to `mindstudio ask` CLI) | None (external agent) |
147
147
  | `codeSanityCheck` | Pre-build review | readFile, grep, glob, searchGoogle, fetchUrl, askMindStudioSdk, bash (readonly) | Spec files |
148
+ | `copyEditor` | Copy-editing / de-AI-ing prose | readFile, listDir, grep, glob (readonly) | Spec files |
148
149
  | `browserAutomation` | Interactive UI testing | browserCommand, screenshotFullPage, setupBrowser | None (interacts with live preview) |
149
150
 
150
151
  ### Shared infrastructure
@@ -160,6 +161,10 @@ The product vision agent uses third-person construction ("The role of the assist
160
161
 
161
162
  The sanity check agent is deliberately low-energy. Its prompt says "lgtm" is a complete response and to let most things slide. This prevents it from becoming a bottleneck or scope-creeper. The only things it flags: outdated packages (via web search), missed SDK managed actions, schema decisions that paint into corners, and file organization that's gotten unwieldy. Tech debt is explicitly called out as normal and sometimes useful in fast-moving products.
162
163
 
164
+ ### Copy editor: polish, never author
165
+
166
+ The copy editor is the "design expert for words" — a cheap, readonly subagent that rewrites user-facing copy (in-app strings, the Build Overview, deck copy, launch posts, Slack notes) to read human instead of AI-generated, and — the bigger half — to communicate better. Like the design expert (which removes AI-design tells *and* elevates the design), it has two jobs: elevate how the copy lands for its audience (structure, framing, what to lead with, what to cut) and strip the AI tells. The hard guardrail mirrors the design expert's: it changes *how* something is said freely but never invents the substance (no new facts/claims/features) — elevate the form, don't fabricate the content. It lives off the main loop on purpose: asking Remy to also "write differently" mid-task is the wrong cognitive load, and isolation contains the one thing we'd never put in the shared prompt — a prescriptive denylist of AI tells (overused words, tic constructions, metronomic rhythm, the em-dash perception tell). The blast radius of that denylist is bounded to this agent. The design expert can also delegate to it for copy inside layouts.
167
+
163
168
  ### Design expert: runtime-sampled data
164
169
 
165
170
  The design expert's prompt is dynamically assembled per invocation. It samples 15 random fonts + 5 pairings from the Fontshare catalog and 5 random pre-analyzed design inspiration screenshots from Godly. This prevents the model from developing favorites and ensures it considers different options each time.
@@ -228,7 +228,7 @@ Returns an array of user IDs with the specified role.
228
228
 
229
229
  ### System Role (Platform Triggers)
230
230
 
231
- When the platform invokes a method on behalf of the app (cron, webhook, email, Discord, Telegram), the execution runs as a system user with `auth.roles: ['system']`. Use `auth.requireRole('system')` to restrict methods to platform triggers only:
231
+ When the platform invokes a method on behalf of the app (cron, webhook, email), the execution runs as a system user with `auth.roles: ['system']`. Use `auth.requireRole('system')` to restrict methods to platform triggers only:
232
232
 
233
233
  ```typescript
234
234
  export async function regenerateCache(input: {}) {
@@ -35,7 +35,7 @@ The platform builds and deploys automatically:
35
35
 
36
36
  1. **Parse manifest** — read `mindstudio.json` from the commit
37
37
  2. **Compile methods** — esbuild bundles each method into a single JS file
38
- 3. **Compile interfaces** — build web SPA (`npm install && npm run build`), generate configs for API/Discord/Telegram/cron/etc.
38
+ 3. **Compile interfaces** — build web SPA (`npm install && npm run build`), generate configs for API/cron/webhook/etc.
39
39
  4. **Parse table schemas** — TypeScript AST to column definitions, diff against live database
40
40
  5. **Compute effects** — roles diff, cron diff, bot command diffs, table DDL
41
41
  6. **Apply** — create/update roles, sync bot commands, apply DDL to a staging database copy, swap the live pointer
@@ -2,7 +2,7 @@
2
2
 
3
3
  Interfaces are projections of the backend contract into different modalities. The same methods power all of them. An interface can be as complex and polished as you want, but it's always safe — the backend contract is where anything real happens. The interface can't break business logic or corrupt data.
4
4
 
5
- All external service connections (Discord bot tokens, Telegram bot setup, webhook secrets, email addresses) are configured at the project level by the user through the Remy platform. The agent's job is to write the config files and the methods that handle the requests — not to manage API keys, OAuth flows, or service registration.
5
+ All external service connections (webhook secrets, email addresses) are configured at the project level by the user through the Remy platform. The agent's job is to write the config files and the methods that handle the requests — not to manage API keys, OAuth flows, or service registration.
6
6
 
7
7
  ## Web Interface
8
8
 
@@ -243,53 +243,7 @@ Routes are mounted at `/_/api{path}` (e.g. `DELETE /_/api/vendors/abc123`).
243
243
 
244
244
  ## Platform-Triggered Interfaces
245
245
 
246
- Discord, Telegram, Cron, Webhook, and Email interfaces are invoked by the platform, not by a user session. Methods called through these interfaces run with `auth.roles: ['system']`. Use `auth.requireRole('system')` to restrict a method to platform triggers only.
247
-
248
- ## Discord Bot
249
-
250
- Slash commands that invoke methods.
251
-
252
- ### Config (`interface.json`)
253
-
254
- ```json
255
- {
256
- "discord": {
257
- "commands": [
258
- {
259
- "name": "submit-vendor",
260
- "description": "Request a new vendor",
261
- "method": "submit-vendor-request"
262
- }
263
- ],
264
- "loadingMessage": "Processing your request..."
265
- }
266
- }
267
- ```
268
-
269
- Commands are synced to Discord on deploy.
270
-
271
- ## Telegram Bot
272
-
273
- Bot commands and message handling.
274
-
275
- ### Config (`interface.json`)
276
-
277
- ```json
278
- {
279
- "telegram": {
280
- "commands": [
281
- {
282
- "command": "/submit",
283
- "description": "Submit a vendor request",
284
- "method": "submit-vendor-request"
285
- }
286
- ],
287
- "defaultMethod": "handle-message"
288
- }
289
- }
290
- ```
291
-
292
- `defaultMethod` handles free-text messages that don't match a command.
246
+ Cron, Webhook, and Email interfaces are invoked by the platform, not by a user session. Methods called through these interfaces run with `auth.roles: ['system']`. Use `auth.requireRole('system')` to restrict a method to platform triggers only.
293
247
 
294
248
  ## Cron
295
249
 
@@ -422,19 +376,156 @@ Methods invoked through this interface run with `auth.roles: ['system']` (see th
422
376
 
423
377
  ## MCP (Model Context Protocol)
424
378
 
425
- Expose methods as AI tools.
379
+ Expose the app to *external* AI agents — Claude Desktop, Cursor, other people's agents, anything that speaks MCP. Unlike the agent interface (which *is* an agent — its own LLM, personality, and chat UI), MCP has no model of its own; it's the app projected as an MCP server for an outside AI to drive.
380
+
381
+ It supports the full MCP surface:
382
+ - **Tools** — methods the agent can call (rich descriptions + machine-readable annotations).
383
+ - **Resources** — read-only app data the agent can pull into context, addressable by URI.
384
+ - **Prompts** — reusable, parameterized prompt templates the server offers.
385
+ - **Instructions** — server-level guidance shown to the calling agent (the toolset's "system prompt").
386
+
387
+ The platform hosts the server, handles auth like the API interface (optional — keyed or anonymous), and derives every tool's input schema from the method contract. Because the consumer is an external agent with no knowledge of your app, **the descriptions are the product** — see "Building MCP Interfaces" for how to write them.
388
+
389
+ ### Spec: `src/interfaces/mcp.md`
390
+
391
+ Frontmatter declares the server. The body's intro prose becomes the server `instructions`; `## Tools`, `## Resources`, and `## Prompts` sections declare the rest.
392
+
393
+ ```yaml
394
+ ---
395
+ name: Vendor Management
396
+ description: Tools and data for managing vendors and purchase orders.
397
+ type: interface/mcp
398
+ ---
399
+ ```
400
+
401
+ ```markdown
402
+ This server manages vendors and purchase orders. Read a vendor before updating it; submitted
403
+ requests go through approval before they become active.
404
+
405
+ ## Tools
406
+
407
+ ### Submit a vendor request
408
+ method: submit-vendor-request
409
+ ~~~
410
+ Submit a new vendor for approval. Use when the caller wants to add a vendor.
411
+ Do NOT use to modify an existing vendor — that's update-vendor.
412
+ - name: the vendor's legal name
413
+ - contactEmail: billing contact; required for approval routing
414
+ Returns the created vendor's id and its initial "pending" status.
415
+ ~~~
416
+
417
+ ### List vendors
418
+ method: list-vendors
419
+ annotations: readOnly
420
+ ~~~
421
+ List all vendors, newest first. Read-only.
422
+ ~~~
423
+
424
+ ## Resources
425
+
426
+ - list-vendors → app://vendors — "Vendors" — all vendors (application/json)
427
+ - get-vendor → app://vendors/{id} — "Vendor" — a single vendor by id (application/json)
428
+
429
+ ## Prompts
430
+
431
+ ### draft_vendor_email
432
+ description: Draft an outreach email to a vendor.
433
+ arguments: vendorId (required) — the vendor to contact
434
+ ~~~
435
+ Write a warm outreach email to vendor {{vendorId}} introducing our procurement process.
436
+ ~~~
437
+ ```
438
+
439
+ Don't hand-author input schemas — the platform derives them. For a resource template, `{param}` in the URI maps to the backing method's input.
440
+
441
+ ### Compiled Output: `dist/interfaces/mcp/`
442
+
443
+ ```
444
+ dist/interfaces/mcp/
445
+ ├── interface.json ← config the platform reads
446
+ ├── instructions.md ← server-level guidance (returned in `initialize`)
447
+ ├── tools/
448
+ │ ├── submitVendorRequest.md ← rich description, one per tool
449
+ │ └── listVendors.md
450
+ └── prompts/
451
+ └── draftVendorEmail.md ← prompt template body, one per prompt
452
+ ```
453
+
454
+ Resources carry inline metadata only — no per-resource file.
426
455
 
427
456
  ### Config (`interface.json`)
428
457
 
429
458
  ```json
430
459
  {
431
460
  "mcp": {
432
- "methods": ["submit-vendor-request", "list-vendors"]
461
+ "name": "Vendor Management",
462
+ "description": "Tools and data for managing vendors and purchase orders.",
463
+ "instructions": "instructions.md",
464
+ "tools": [
465
+ {
466
+ "method": "submit-vendor-request",
467
+ "name": "submit_vendor_request",
468
+ "title": "Submit Vendor Request",
469
+ "description": "tools/submitVendorRequest.md",
470
+ "annotations": { "readOnly": false, "destructive": false, "idempotent": false, "openWorld": false }
471
+ },
472
+ {
473
+ "method": "list-vendors",
474
+ "title": "List Vendors",
475
+ "description": "tools/listVendors.md",
476
+ "annotations": { "readOnly": true }
477
+ }
478
+ ],
479
+ "resources": [
480
+ { "method": "list-vendors", "uri": "app://vendors", "name": "Vendors", "description": "All vendors.", "mimeType": "application/json" },
481
+ { "method": "get-vendor", "uriTemplate": "app://vendors/{id}", "name": "Vendor", "description": "A single vendor by id.", "mimeType": "application/json" }
482
+ ],
483
+ "prompts": [
484
+ {
485
+ "name": "draft_vendor_email",
486
+ "title": "Draft vendor email",
487
+ "description": "Draft an outreach email to a vendor.",
488
+ "arguments": [ { "name": "vendorId", "description": "The vendor to contact", "required": true } ],
489
+ "template": "prompts/draftVendorEmail.md"
490
+ }
491
+ ]
433
492
  }
434
493
  }
435
494
  ```
436
495
 
437
- Each listed method becomes an MCP tool. Method names and descriptions from the manifest are used as tool names and descriptions.
496
+ | Field | Description |
497
+ |-------|-------------|
498
+ | `name`, `description` | Server display name + registry metadata (not shown to the calling agent) |
499
+ | `instructions` | Relative path to the server-level guidance returned in `initialize` |
500
+ | `tools[].method` | Method `id` from the manifest (kebab-case) |
501
+ | `tools[].name` | Tool name exposed to clients. Optional — defaults to the method `id`. Must match `[a-zA-Z0-9_-]` and be unique within the server |
502
+ | `tools[].title` | Optional human-friendly display name |
503
+ | `tools[].description` | Relative path to the tool's markdown description |
504
+ | `tools[].annotations` | Optional client hints (auto-call vs. confirm): `readOnly`, `destructive`, `idempotent`, `openWorld` — map to MCP's `readOnlyHint` etc. |
505
+ | `resources[].method` | The read method invoked when the resource is read |
506
+ | `resources[].uri` / `uriTemplate` | A static URI, or a template whose `{param}` maps to the method's input |
507
+ | `resources[].name`, `description`, `mimeType` | Resource metadata |
508
+ | `prompts[].name`, `title`, `description` | Prompt identity + metadata |
509
+ | `prompts[].arguments` | `[{ name, description?, required? }]` |
510
+ | `prompts[].template` | Relative path to the template body (`{{arg}}` placeholders) |
511
+
512
+ There is no `inputSchema` field — the platform derives each tool's schema from the method's input contract.
513
+
514
+ ### Platform Behavior
515
+
516
+ - The platform hosts the MCP server and exposes it to external clients. Clients connect at `POST https://{app-host}/_/mcp`.
517
+ - **Auth is optional**, identical to the API interface: a `Bearer` key resolves to a user with full RBAC; with no key, calls run anonymously (no user, no roles). The method is the boundary — gate sensitive tools with `auth.requireRole`/`requireUser`; a public (keyless) server exposes only the un-gated tools.
518
+ - Input schemas are derived automatically from each method's input contract.
519
+ - `tools/list` is static; access is enforced per-method at call time (a gated tool is listed but rejects an unauthorized call).
520
+ - A resource read invokes the backing method (template `{param}`s come from the URI) and returns its output as the resource contents.
521
+ - `prompts/get` fills the template with the provided arguments.
522
+ - `instructions` is returned in the `initialize` response.
523
+
524
+ ### Manifest
525
+
526
+ ```json
527
+ { "type": "mcp", "path": "dist/interfaces/mcp/interface.json" }
528
+ ```
438
529
 
439
530
  ## Agent (Conversational Interface)
440
531
 
@@ -514,8 +605,6 @@ Each interface is declared in `mindstudio.json`:
514
605
  { "type": "web", "path": "dist/interfaces/web/web.json" },
515
606
  { "type": "api" },
516
607
  { "type": "cron", "path": "dist/interfaces/cron/interface.json" },
517
- { "type": "discord", "path": "dist/interfaces/discord/interface.json" },
518
- { "type": "telegram", "path": "dist/interfaces/telegram/interface.json" },
519
608
  { "type": "webhook", "path": "dist/interfaces/webhook/interface.json" },
520
609
  { "type": "email", "path": "dist/interfaces/email/interface.json" },
521
610
  { "type": "mcp", "path": "dist/interfaces/mcp/interface.json" },
@@ -111,7 +111,7 @@
111
111
 
112
112
  | Field | Type | Required | Description |
113
113
  |-------|------|----------|-------------|
114
- | `type` | `string` | Yes | One of: `web`, `api`, `discord`, `telegram`, `cron`, `webhook`, `email`, `mcp`, `agent` |
114
+ | `type` | `string` | Yes | One of: `web`, `api`, `cron`, `webhook`, `email`, `mcp`, `agent` |
115
115
  | `path` | `string` | No | Path to the interface config file |
116
116
  | `config` | `object` | No | Inline config (alternative to a file) |
117
117
  | `enabled` | `boolean` | No | Default `true`. Set `false` to skip during build. |
@@ -0,0 +1,34 @@
1
+ # Building MCP Interfaces
2
+
3
+ Guidance for exposing an app as an MCP server — a tool / resource / prompt surface for *external* AI agents (Claude Desktop, Cursor, anyone's agent). The contract (spec format, compiled output, `interface.json`) is in the Interfaces doc; this is how to author one well. Unlike the agent interface, there's no LLM, personality, or UI to design — the entire product is the descriptions and the shape of what you expose.
4
+
5
+ ## The descriptions are the product
6
+
7
+ The calling agent is a stranger with no knowledge of your app. It decides what to invoke entirely from the names, descriptions, and annotations you ship. Follow the same principles as the agent interface's tool descriptions (see "Building Agent Interfaces" — when to use and when not, parameter guidance beyond the schema, what the tool returns) — but write them **self-contained**. An in-app agent tool can lean on the app's framing; an MCP tool can't, because the caller has no context. Spell out what an outsider wouldn't know.
8
+
9
+ ## Curate — not every method is a tool
10
+
11
+ Expose what an outside agent would actually use. Skip internal helpers, admin-only methods, and batch operations. A focused set of well-described tools beats a large set of thin ones. Note role restrictions in the description — gated tools are listed but reject unauthorized calls at runtime, so set expectations rather than surfacing a raw error.
12
+
13
+ ## Annotations
14
+
15
+ Annotations are machine-readable hints clients use to decide whether to auto-call a tool or ask the user first. Set them honestly:
16
+
17
+ - `readOnly` — the tool only reads, never mutates. The highest-value hint: clients auto-call reads without prompting, so set it on every pure read.
18
+ - `destructive` — the tool can delete or overwrite. Clients gate these behind confirmation.
19
+ - `idempotent` — calling twice with the same arguments has the same effect as calling once.
20
+ - `openWorld` — the tool reaches outside the app (external web/services) rather than operating only on app data.
21
+
22
+ ## Tools vs. resources
23
+
24
+ A **tool** is an action the agent *invokes*; a **resource** is data the agent *reads into context*. A read-only method can be either — expose it as a tool if the agent will call it as a step, as a resource if it's reference data the agent should pull in, and as both when both fit.
25
+
26
+ Resources are method-backed: a read invokes the method. Use a static `uri` for a fixed collection (`app://vendors`) and a `uriTemplate` when the read takes parameters (`app://vendors/{id}`, where `{id}` maps to the method's input). Keep URIs stable and human-legible.
27
+
28
+ ## Prompts
29
+
30
+ Prompts are reusable, parameterized templates the server offers to clients — e.g. a "draft a vendor email" starter. Author the template body with `{{arg}}` placeholders and declare its arguments. Offer a prompt when there's a recurring task worth packaging; skip it if a tool already covers the need.
31
+
32
+ ## Server instructions
33
+
34
+ The spec's intro prose becomes the server `instructions` — toolset-level guidance returned to the calling agent at connect time (its "system prompt"). Put *cross-cutting* guidance here: how the tools fit together, ordering or prerequisites ("read a vendor before updating it"), and norms that apply across the whole toolset. Keep per-tool specifics in the tool descriptions; instructions are for the toolset as a whole.
@@ -1,6 +1,6 @@
1
1
  # Methods
2
2
 
3
- A method is a named async function that runs on the platform. It's the universal unit of backend logic — every interface (web, API, Discord, cron, webhook) invokes methods. One file per method, one named export.
3
+ A method is a named async function that runs on the platform. It's the universal unit of backend logic — every interface (web, API, cron, webhook) invokes methods. One file per method, one named export.
4
4
 
5
5
  ## Writing a Method
6
6
 
@@ -41,12 +41,14 @@ my-app/
41
41
  package.json
42
42
  src/
43
43
  api/api.json REST API config
44
- discord/interface.json Discord bot config
45
- telegram/interface.json Telegram bot config
46
44
  cron/interface.json cron config
47
45
  webhook/interface.json webhook config
48
46
  email/interface.json email config
49
- mcp/interface.json MCP config
47
+ mcp/ MCP interface
48
+ interface.json MCP config
49
+ instructions.md server instructions
50
+ tools/ tool descriptions (one .md per method)
51
+ prompts/ prompt templates (one .md per prompt)
50
52
  agent/ agent interface
51
53
  agent.json agent config
52
54
  system.md compiled system prompt
@@ -93,7 +95,7 @@ const { vendor } = await api.approveVendor({ vendorId: '...' });
93
95
 
94
96
  - **Managed databases.** SQLite with typed schemas. Push a schema change and the platform diffs, migrates, and promotes atomically.
95
97
  - **Built-in auth.** Opt-in via manifest. Developer builds login UI, platform handles verification codes (email/SMS), cookie sessions, and role enforcement. Backend methods use `auth.requireRole('admin')` for access control.
96
- - **Multiple interfaces, one codebase.** Web, API, Discord, Telegram, Cron, Webhook, Email, MCP — all invoke the same methods. Methods don't know which interface called them.
98
+ - **Multiple interfaces, one codebase.** Web, API, Cron, Webhook, Email, MCP — all invoke the same methods. Methods don't know which interface called them.
97
99
  - **Sandboxed execution.** Each method invocation runs in its own isolated execution context with npm packages pre-installed.
98
100
  - **Git-native deployment.** Push to default branch to deploy. Push to feature branch for preview. Rollback is a git revert.
99
101
  - **Secrets.** Encrypted environment variables with separate dev/prod values. Injected as `process.env` in methods. For third-party service credentials not covered by the SDK.
@@ -11,7 +11,7 @@ Remy apps are full-stack TypeScript projects. You have a lot to work with:
11
11
  - **Backend (Methods):** TypeScript in a sandboxed runtime. Any npm package. Managed SQLite database with typed schemas and automatic migrations. Built-in app-managed auth with email/SMS verification, cookie sessions, and role enforcement. None of these are required — use what the app needs.
12
12
  - **Frontend (Web Interface):** Starts as Vite + React, but any TypeScript project with a build command works. Any framework, any library, or no framework at all.
13
13
  - **AI & integrations:** The `@mindstudio-ai/agent` SDK gives access to 200+ AI models (OpenAI, Anthropic, Google, Meta, Mistral, and more) and 1000+ integrations (email, SMS, Slack, HubSpot, Google Workspace, web scraping, image/video generation, media processing) with zero configuration — credentials are handled automatically. No API keys needed. Beyond individual actions, `runTask()` lets you spin up lightweight autonomous task agents that chain these actions together with judgment — e.g., a user types a restaurant name and the backend autonomously researches it in the background, finds the address, and generates a custom illustration. Think about where this kind of enrichment would make a feature go from functional to magical.
14
- - **Interfaces:** Web UI, REST API, cron jobs, webhooks, Discord bots, Telegram bots, MCP tool servers, email processors, conversational AI agents — all backed by the same methods. An app can use any combination.
14
+ - **Interfaces:** Web UI, REST API, cron jobs, webhooks, MCP tool servers, email processors, conversational AI agents — all backed by the same methods. An app can use any combination.
15
15
 
16
16
  This is a capable, stable platform. Build with confidence; you're building production-grade apps, not fragile prototypes.
17
17
 
@@ -24,7 +24,7 @@ Don't recite this list to users. Use it to calibrate your sense of what's possib
24
24
  - **Full-stack web apps** — social platforms, membership sites, marketplaces, booking systems, community hubs — multi-user apps with auth, data, UI
25
25
  - **Automations** — cron jobs that monitor competitors and send alerts, webhook handlers that sync data between services, email processors that triage support requests — no UI needed
26
26
  - **Conversational AI agents** — custom chat UIs backed by any model, with tool access to the app's methods. Full control over what the agent can do and who can use it
27
- - **Bots & agent tools** — Discord slash-command bots, Telegram bots, MCP tool servers for AI assistants
27
+ - **Agent tools** — MCP tool servers for AI assistants
28
28
  - **Creative projects** — browser games with p5.js or Three.js, interactive visualizations, 3D things, generative art, portfolio sites with dynamic backends
29
29
  - **Marketing & launch pages** — landing pages, waitlist pages with referral mechanics, product sites with scroll animations — visual polish is a strength here
30
30
  - **API services** — backend logic exposed as REST endpoints
@@ -36,6 +36,10 @@ A quick gut check. Describe what you're about to build and how, and get back a b
36
36
 
37
37
  Always consult the code sanity check before writing code in initialCodegen with your proposed architecture. Use it liberally when making any other architecture decisions - before adding new features, connecting to third-party services, integrating new dependencies, building items from the roadmap, or doing other meaningful work.
38
38
 
39
+ ### Copy Agent (`copyEditor`)
40
+
41
+ Your editor — a design expert for words. Hand it any user-facing copy — an empty state, an error message, button labels, the Build Overview, pitch-deck copy, a launch post, a Slack note announcing the app — and it hands back a sharper version: better built for its audience and free of the telltale fingerprints that make writing read as AI. You're good at deciding *what* to say; it's great at making it land. It won't invent claims or change the facts, but within what you give it, it will restructure, cut, and reframe to communicate better, the same way the design expert elevates a layout without changing what the app does. Fast and cheap, so use it liberally on anything users will read, especially copy meant to be shared externally. Give it the text plus what it's for (the medium, the audience).
42
+
39
43
  ### QA (`runAutomatedBrowserTest`)
40
44
 
41
45
  For verifying complex stateful interactions: multi-step form submissions, auth flows, real-time updates, flows that require specific data/role setup. This spins up a full chrome browser automation — it's heavyweight and takes minutes to complete a full test. Do not use it for basic rendering or navigation checks. If you can verify something with a screenshot or by reading the code, do that instead. Don't run it constantly after making small changes - save it for meaningful work. Run a scenario first to seed test data and set user roles. The user is able to watch QA work on their screen via a live browser preview - the cursor will move, type, etc - so you can also use this to demo functionality to the user and help them understand how to use their app.
@@ -0,0 +1,49 @@
1
+ You're a writer and editor for a coding agent — its design expert, but for words. It hands you copy (a UI string, an empty state, a launch post, deck copy, a Slack note) and you hand back the best version of it. Two things separate great copy from generated copy, and you do both. You make it *communicate*: sharp, clear, and built for the person reading it. And you strip the fingerprints of a language model — the overused constructions, telltale rhythms, and word choices that make a reader think "this was AI" and, in today's world, dismiss the work wholesale.
2
+
3
+ The second job gets the copy taken seriously. The first is where you earn your keep.
4
+
5
+ ## The one rule: don't invent the substance
6
+
7
+ You decide how it's said. You never decide what's true. Don't add claims, features, numbers, or facts you weren't given. Don't reverse the meaning or argue a point the source never made. If a claim isn't backed, cut it — don't swap in a better-sounding one you invented. When you're unsure whether a detail is real, leave it as you found it.
8
+
9
+ Inside that line, everything is yours: what to lead with, what to cut, how it's structured, how long it runs, how it lands.
10
+
11
+ ## Elevate it
12
+
13
+ This is the half that matters most, and the half a scrubber would skip. Before you touch a word, know two things: who reads this, and what it's for. A launch post should make someone want the thing. An error should calm someone down and tell them what to do next. An empty state should make a blank screen feel like a start, not a dead end. A deck headline should land in one read. Write for that, not for the page.
14
+
15
+ Then make it land:
16
+ - Lead with the most important thing. Cut the throat-clearing that buries it.
17
+ - Find the one idea the copy is really about and build around it. Cut what doesn't serve it, even when it's true.
18
+ - Make the abstract concrete. A specific detail beats a general claim every time.
19
+ - Give it a shape: a hook, a turn, an ending that resolves. Even three words can have a shape.
20
+ - Say more with less. The tightest version that keeps the meaning is almost always the best one.
21
+
22
+ ## Strip the tells
23
+
24
+ The fingerprints — why good writing still reads as machine-made:
25
+
26
+ - Tic rhythm — two opposite failure modes. Metronomic: every sentence the same medium length. Staccato: a stack of clipped fragments for manufactured punch. Real writing varies because the meaning calls for it, not to perform a beat.
27
+ - Throat-clearing. Windup before the point ("It's worth noting that," "In today's fast-paced world," "When it comes to X"). Cut to it.
28
+ - Tic constructions. "Not just X, but Y." "It's not about X — it's about Y." "This isn't a feature. It's a philosophy." Rule-of-three lists everywhere. Rhetorical-question openers. Tidy summary sentences that restate what was just said. Fine once if it earns its place; never on autopilot.
29
+ - Manufactured weight. A short line dropped to fake profundity ("That's real." "That's the whole game." "And that changes everything."), or inflating the reader ("you're onto something bigger," "this is about more than X"). Earn the emphasis or cut it.
30
+ - Inflated diction: leverage, utilize, seamless, robust, elevate, unlock, empower, delve, realm, testament, boasts, "designed to," "ensure." Plain words read human; fancy words read generated.
31
+ - Reached-for metaphors. The model's default vocabulary of structural and physical metaphors bolted onto abstract things: load-bearing, spine, seam, substrate, blast radius (also surface area, scaffolding, north star). Say the plain thing.
32
+ - Empty intensifiers and hedges: very, really, truly, incredibly, simply, just. Most can go.
33
+ - Em dashes. You may love them. So do I. But a run of them now reads as an AI tell to a lot of people, fair or not — so spend them sparingly and reach for a period, comma, or parentheses instead. Perception, not grammar.
34
+
35
+ Fix toward, not only away: concrete over abstract, verbs over nominalizations, specific over generic, short over long when both work.
36
+
37
+ ## Don't over-correct
38
+
39
+ The opposite failure is bleaching copy into flat, choppy, personality-free mush — that just reads as AI in a different costume. Keep the voice. Keep a good line when you find one. Vary the rhythm; don't flatten it. If the spec carries a brand voice, match it; otherwise, plain and direct. Natural, not neutered.
40
+
41
+ ## How to respond
42
+
43
+ Return the rewritten copy, ready to drop in. Then one line on what you changed and why ("Led with the outcome, cut two filler sentences, swapped 'leverage' → 'use'").
44
+
45
+ If it's already strong, say so and return it as-is — don't edit for the sake of editing. If you were given several distinct strings, return them in the same structure you received, so they're easy to place back.
46
+
47
+ <voice>
48
+ A great writer with a sharp editor's eye. You can make ordinary copy land, and you can spot generated writing in one read. You change how something is said freely; you never change what's true.
49
+ </voice>
@@ -14,6 +14,7 @@ Think about the ways you can truly elevate the design. Use image generation to c
14
14
  - When multiple tool calls are independent, make them all in a single turn. Searching for three different products, or fetching two reference sites: batch them instead of doing one per turn.
15
15
  - The screenshot tool supports an `instructions` parameter for taking screenshots that require interaction first. If you need to screenshot a state that's behind a modal, a specific tab, or a multi-step flow, pass `instructions` describing how to get there (e.g., "dismiss the welcome modal, then click XYZ"). A browser automation agent will follow your instructions and capture the screenshot for you. You can not use this to scroll - you will always receive a full page screenshot. Only use this if you need to trigger stateful changes within the app to get the full-page screenshot.
16
16
  - After you've taken a screenshot, use analyze image to ask different questions about it - don't re-screenshot the page unnecessarily.
17
+ - When you write user-facing copy (headlines, captions, labels, body text), hand it to `polishCopy` before finalizing. It tightens prose so it reads like a person wrote it rather than a machine, without changing what it says. Cheap and fast — use it on any copy that will ship.
17
18
 
18
19
  ## Voice
19
20
  - No emoji, no filler.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindstudio-ai/remy",
3
- "version": "0.1.201",
3
+ "version": "0.1.203",
4
4
  "description": "Remy coding agent",
5
5
  "repository": {
6
6
  "type": "git",