@mindstudio-ai/remy 0.1.261 → 0.1.263

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
@@ -483,13 +483,17 @@ var ALLOWED_MODELS_BY_TYPE = {
483
483
  "gemini-3.1-pro",
484
484
  "gemini-3-flash",
485
485
  "gemini-3.5-flash",
486
+ "gemini-3.7-flash",
486
487
  "grok-build-0.1",
487
488
  "grok-4.5",
489
+ "grok-4.6",
488
490
  "glm-5.2",
489
491
  "muse-spark-1.1",
490
492
  "kimi-k2-7-code",
491
493
  "kimi-k3",
492
- "deepseek-v4-flash-0731"
494
+ "deepseek-v4-flash-0731",
495
+ "qwen3.8-2.4t-a95b-deepinfra",
496
+ "minimax-m3"
493
497
  ]
494
498
  // vision: undefined — unconstrained
495
499
  // image_generation: undefined — unconstrained
@@ -2106,7 +2110,7 @@ var loadSkillTool = {
2106
2110
  definition: {
2107
2111
  clearable: true,
2108
2112
  name: "loadSkill",
2109
- description: "Load the full reference for a platform capability that isn't in your system prompt \u2014 task agents, agent interfaces, MCP interfaces, data sources. The available skills and the trigger for each are listed in <available_skills>. Load one before writing code in its area, not after: these are APIs where a plausible-looking guess is usually wrong. Calling this is cheap and expected \u2014 if you're unsure whether you need it, load it. Only covers the capabilities listed in the catalog; for backend SDK actions and model IDs use askMindStudioSdk.",
2113
+ description: "Load the full reference for a platform capability that isn't in your system prompt \u2014 task agents, agent interfaces, voice interfaces, MCP interfaces, data sources. The available skills and the trigger for each are listed in <available_skills>. Load one before writing code in its area, not after: these are APIs where a plausible-looking guess is usually wrong. Calling this is cheap and expected \u2014 if you're unsure whether you need it, load it. Only covers the capabilities listed in the catalog; for backend SDK actions and model IDs use askMindStudioSdk.",
2110
2114
  inputSchema: {
2111
2115
  type: "object",
2112
2116
  properties: {
@@ -4323,6 +4327,7 @@ Each interface type invokes the same backend methods. Methods don't know which i
4323
4327
  - Email \u2014 inbound email processing
4324
4328
  - MCP \u2014 tool servers for AI assistants
4325
4329
  - Agent \u2014 conversational LLM interface with tool access to backend methods
4330
+ - Voice \u2014 the app's agent as a realtime voice conversation, with the same tool access
4326
4331
 
4327
4332
  ## Backend
4328
4333
 
package/dist/index.js CHANGED
@@ -2195,13 +2195,17 @@ var init_surfaces = __esm({
2195
2195
  "gemini-3.1-pro",
2196
2196
  "gemini-3-flash",
2197
2197
  "gemini-3.5-flash",
2198
+ "gemini-3.7-flash",
2198
2199
  "grok-build-0.1",
2199
2200
  "grok-4.5",
2201
+ "grok-4.6",
2200
2202
  "glm-5.2",
2201
2203
  "muse-spark-1.1",
2202
2204
  "kimi-k2-7-code",
2203
2205
  "kimi-k3",
2204
- "deepseek-v4-flash-0731"
2206
+ "deepseek-v4-flash-0731",
2207
+ "qwen3.8-2.4t-a95b-deepinfra",
2208
+ "minimax-m3"
2205
2209
  ]
2206
2210
  // vision: undefined — unconstrained
2207
2211
  // image_generation: undefined — unconstrained
@@ -2923,7 +2927,7 @@ var init_loadSkill = __esm({
2923
2927
  definition: {
2924
2928
  clearable: true,
2925
2929
  name: "loadSkill",
2926
- description: "Load the full reference for a platform capability that isn't in your system prompt \u2014 task agents, agent interfaces, MCP interfaces, data sources. The available skills and the trigger for each are listed in <available_skills>. Load one before writing code in its area, not after: these are APIs where a plausible-looking guess is usually wrong. Calling this is cheap and expected \u2014 if you're unsure whether you need it, load it. Only covers the capabilities listed in the catalog; for backend SDK actions and model IDs use askMindStudioSdk.",
2930
+ description: "Load the full reference for a platform capability that isn't in your system prompt \u2014 task agents, agent interfaces, voice interfaces, MCP interfaces, data sources. The available skills and the trigger for each are listed in <available_skills>. Load one before writing code in its area, not after: these are APIs where a plausible-looking guess is usually wrong. Calling this is cheap and expected \u2014 if you're unsure whether you need it, load it. Only covers the capabilities listed in the catalog; for backend SDK actions and model IDs use askMindStudioSdk.",
2927
2931
  inputSchema: {
2928
2932
  type: "object",
2929
2933
  properties: {
@@ -5160,6 +5164,7 @@ Each interface type invokes the same backend methods. Methods don't know which i
5160
5164
  - Email \u2014 inbound email processing
5161
5165
  - MCP \u2014 tool servers for AI assistants
5162
5166
  - Agent \u2014 conversational LLM interface with tool access to backend methods
5167
+ - Voice \u2014 the app's agent as a realtime voice conversation, with the same tool access
5163
5168
 
5164
5169
  ## Backend
5165
5170
 
@@ -214,6 +214,8 @@ All auth methods throw on failure with a `code` property:
214
214
  | `invalid_state` | 400 | Sign in with Remy: returned CSRF state didn't match (stale/replayed redirect) |
215
215
  | `popup_blocked` | — | Sign in with Remy (embedded): popup was blocked — prompt to allow popups and retry |
216
216
  | `signin_timeout` | — | Sign in with Remy (embedded): popup didn't complete in time |
217
+ | `auth_required` | 401 | Agent/voice interface requires an authenticated user (interface `auth` block) |
218
+ | `role_required` | 403 | Agent/voice interface requires a role the user doesn't hold |
217
219
 
218
220
  ### Phone Helpers
219
221
 
@@ -380,9 +382,19 @@ Roles are declared in the manifest, stored as an array column on the user table,
380
382
  - Writable from dashboard: Remy dashboard shows app users and their roles
381
383
  - Backend enforcement: `auth.requireRole('admin')` works as before
382
384
 
385
+ ## Interface-Level Auth (Agent + Voice)
386
+
387
+ Agent and voice interfaces additionally declare auth **in their config** (a required `auth` key:
388
+ `{ "requireUser": boolean, "requireRole"?: string[] }`) because those sessions spend money without
389
+ necessarily calling a backend method — the platform gates the lobby itself, before any model or
390
+ media spend. `requireRole` uses the same manifest role ids with OR semantics. Denials reach the
391
+ frontend SDK as `MindStudioInterfaceError` codes `auth_required` (401) and `role_required` (403) —
392
+ route them to the app's login flow. See the `agentInterfaces` / `voiceInterfaces` skills for the
393
+ full contract. Method-level `auth.requireRole(...)` checks still apply to every tool call inside.
394
+
383
395
  ## Apps Without Auth
384
396
 
385
- Apps without `auth` in the manifest use anonymous guest sessions. No login, no user identity, no roles. This is the default and works fine for single-user apps, internal tools, and simple utilities.
397
+ Apps without `auth` in the manifest use anonymous guest sessions. No login, no user identity, no roles. This is the default and works fine for single-user apps, internal tools, and simple utilities. (Agent/voice interfaces on such apps declare `"auth": { "requireUser": false }` explicitly — anonymous callers are scoped by a per-browser visitor identity.)
386
398
 
387
399
  ## Important: Designing Auth in Web Interfaces
388
400
 
@@ -88,6 +88,8 @@ auth.logout() // clears session
88
88
 
89
89
  For apps with an agent interface, the SDK also provides `createAgentChatClient()` for thread management and streaming chat. Load the `agentInterfaces` skill for its usage — thread APIs, streaming callbacks, and attachments are all there.
90
90
 
91
+ For apps with a voice interface, `createVoiceClient()` lives on the `@mindstudio-ai/interface/voice` subpath (deliberately separate so non-voice apps ship none of it). Load the `voiceInterfaces` skill for its usage — session lifecycle, live-caption events, tool status, and the voice-UI patterns are all there.
92
+
91
93
  The project uses `"jsx": "react-jsx"` (automatic JSX transform) — do not `import React from 'react'`. Only import the specific hooks and types you need (e.g., `import { useState, useEffect } from 'react'`).
92
94
 
93
95
  On deploy, the platform runs `npm install && npm run build` in the web directory and hosts the output on CDN.
@@ -180,10 +182,16 @@ It supports the full MCP surface: tools (methods the agent can call), resources
180
182
 
181
183
  ## Agent (Conversational Interface)
182
184
 
183
- A conversational interface where an LLM has access to the app's methods as tools. Unlike MCP (which exposes methods for external agents), the agent interface IS the agent — it has its own personality, system prompt, and model config, and orchestrates tool calls against the app's methods internally. Chat runs as the authenticated user, so every tool call carries that user's roles.
185
+ A conversational interface where an LLM has access to the app's methods as tools. Unlike MCP (which exposes methods for external agents), the agent interface IS the agent — it has its own personality, system prompt, and model config, and orchestrates tool calls against the app's methods internally. Chat runs as the authenticated user, so every tool call carries that user's roles. The config must declare an `auth` block (`{ "requireUser": boolean, "requireRole"?: string[] }`) gating who may chat at all.
184
186
 
185
187
  **Load the `agentInterfaces` skill** before authoring `src/interfaces/agent.md` or building the chat UI — the spec frontmatter, compiled output, `agent.json`, and the entire frontend surface are all there.
186
188
 
189
+ ## Voice (Realtime Conversation)
190
+
191
+ The app's agent as a live voice conversation — the user talks, and the agent answers in sub-second, interruptible speech, calling methods mid-conversation. A sibling of the agent interface, not a mode of it: its own spec, a persona written for the ear rather than the screen, and a smaller toolset where every tool carries a latency class governing how the agent handles the wait out loud. Sessions run as the authenticated user, so tool calls carry that user's roles; the platform handles the realtime media, turn-taking, barge-in, and transcripts. The config must declare an `auth` block (`{ "requireUser": boolean, "requireRole"?: string[] }`) gating who may start a session at all.
192
+
193
+ **Load the `voiceInterfaces` skill** before authoring `src/interfaces/voice.md` or building the voice UI — the spoken-register rules, latency classes, spec format, `interface.json`, and the `createVoiceClient()` frontend surface are all there.
194
+
187
195
  ## Manifest Declaration
188
196
 
189
197
  Each interface is declared in `mindstudio.json`:
@@ -197,7 +205,8 @@ Each interface is declared in `mindstudio.json`:
197
205
  { "type": "webhook", "path": "dist/interfaces/webhook/interface.json" },
198
206
  { "type": "email", "path": "dist/interfaces/email/interface.json" },
199
207
  { "type": "mcp", "path": "dist/interfaces/mcp/interface.json" },
200
- { "type": "agent", "path": "dist/interfaces/agent/agent.json" }
208
+ { "type": "agent", "path": "dist/interfaces/agent/agent.json" },
209
+ { "type": "voice", "path": "dist/interfaces/voice/interface.json" }
201
210
  ]
202
211
  }
203
212
  ```
@@ -111,7 +111,7 @@
111
111
 
112
112
  | Field | Type | Required | Description |
113
113
  |-------|------|----------|-------------|
114
- | `type` | `string` | Yes | One of: `web`, `api`, `cron`, `webhook`, `email`, `mcp`, `agent` |
114
+ | `type` | `string` | Yes | One of: `web`, `api`, `cron`, `webhook`, `email`, `mcp`, `agent`, `voice` |
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. |
@@ -23,6 +23,7 @@ my-app/
23
23
  web.md web UI spec
24
24
  api.md API conventions
25
25
  agent.md agent personality and behavior spec
26
+ voice.md voice agent persona and toolset spec
26
27
  cron.md scheduled job descriptions
27
28
  roadmap/ feature roadmap (one file per item, type: roadmap)
28
29
 
@@ -53,6 +54,10 @@ my-app/
53
54
  agent.json agent config
54
55
  system.md compiled system prompt
55
56
  tools/ tool descriptions (one .md per method)
57
+ voice/ voice interface
58
+ interface.json voice config
59
+ system.md compiled voice-register system prompt
60
+ tools/ tool descriptions (one .md per method)
56
61
  ```
57
62
 
58
63
  ## What Goes Where
@@ -95,7 +100,7 @@ const { vendor } = await api.approveVendor({ vendorId: '...' });
95
100
 
96
101
  - **Managed databases.** SQLite with typed schemas. Push a schema change and the platform diffs, migrates, and promotes atomically.
97
102
  - **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.
98
- - **Multiple interfaces, one codebase.** Web, API, Cron, Webhook, Email, MCP — all invoke the same methods. Methods don't know which interface called them.
103
+ - **Multiple interfaces, one codebase.** Web, API, Cron, Webhook, Email, MCP, Agent, Voice — all invoke the same methods. Methods don't know which interface called them.
99
104
  - **Sandboxed execution.** Each method invocation runs in its own isolated execution context with npm packages pre-installed.
100
105
  - **Git-native deployment.** Push to default branch to deploy. Push to feature branch for preview. Rollback is a git revert.
101
106
  - **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.
@@ -257,6 +257,7 @@ dist/interfaces/agent/
257
257
  "temperature": 0.5,
258
258
  "maxTokens": 16000,
259
259
  "systemPrompt": "system.md",
260
+ "auth": { "requireUser": true },
260
261
  "tools": [
261
262
  { "method": "create-todo", "description": "tools/createTodo.md" },
262
263
  { "method": "list-todos", "description": "tools/listTodos.md" }
@@ -276,6 +277,7 @@ across rather than copying the key.
276
277
  | `temperature` | Model temperature |
277
278
  | `maxTokens` | Max response tokens (the spec's `maxResponseTokens`) |
278
279
  | `systemPrompt` | Relative path to the compiled system prompt markdown file |
280
+ | `auth` | **Required.** Who may open the lobby: `{ "requireUser": boolean, "requireRole"?: string[] }`. See the Auth section below |
279
281
  | `tools` | Array of tool entries — `method` references a method `id` from the manifest, `description` is a relative path to a markdown file with rich tool docs (when to use, examples, edge cases, parameter guidance) |
280
282
  | `webInterfacePath` | Optional. If the app has a web interface with a chat page, this path tells the IDE where to show the preview. Otherwise the agent is accessed via API. |
281
283
 
@@ -287,8 +289,29 @@ Declare it in `mindstudio.json`:
287
289
 
288
290
  ## Auth
289
291
 
290
- Agent chat runs as the **authenticated user**, not as a system role tool calls carry that user's
291
- roles, so a method gated with `auth.requireRole` behaves exactly as it would if the user had called it
292
- from the web frontend. That's what makes exposing real methods safe; it's also why role restrictions
293
- belong in the tool descriptions, so the agent can decline gracefully instead of surfacing a rejection.
292
+ **Every agent config declares an `auth` block.** Agent chat spends the owner's money on every
293
+ message without necessarily touching a backend method, so the platform gates the lobby itself
294
+ enforced at thread creation and message send:
295
+
296
+ ```json
297
+ "auth": { "requireUser": true, "requireRole": ["support-agent", "admin"] }
298
+ ```
299
+
300
+ - `requireUser: true` — only authenticated app users may chat; `false` — anyone, including
301
+ anonymous visitors. Most apps want `true`; choose `false` deliberately (a public concierge).
302
+ - `requireRole` (optional) — the user must hold **at least one** of the listed manifest role ids
303
+ (OR semantics, same as the backend `auth.requireRole(...)`). Omit or leave empty for no role
304
+ gate. Requires `requireUser: true`. Unknown role ids fail the build.
305
+ - Denials surface to the frontend SDK as `MindStudioInterfaceError` with code `auth_required`
306
+ (401) or `role_required` (403).
307
+ - Dev preview is exempt — the builder is never locked out while testing.
308
+ - Older compiled apps without the block fall back to the manifest's `auth.enabled` (auth-enabled →
309
+ users only; no auth → public). New configs always declare it explicitly.
310
+
311
+ Once inside, agent chat runs as the **authenticated user**, not as a system role — tool calls
312
+ carry that user's roles, so a method gated with `auth.requireRole` behaves exactly as it would if
313
+ the user had called it from the web frontend. That's what makes exposing real methods safe; it's
314
+ also why role restrictions belong in the tool descriptions, so the agent can decline gracefully
315
+ instead of surfacing a rejection. Anonymous visitors (when allowed) are scoped by a per-browser
316
+ visitor identity: their threads are private to their browser, and gated methods still reject.
294
317
 
@@ -268,7 +268,7 @@ Declare it in `mindstudio.json`:
268
268
  `custom_subdomain` host (e.g. `myapp.madewithremy.com`), a custom domain if configured, or the UUID
269
269
  host (`<appId>.madewithremy.com` / `.msagent.ai`).
270
270
  - **Auth is optional.** A `Bearer` key resolves to a user with full RBAC, so the method's own
271
- `auth.requireRole`/`requireUser` checks apply as they would for that user. With no key, calls run
271
+ `auth.requireRole(...)`/`hasRole(...)` checks apply as they would for that user. With no key, calls run
272
272
  anonymously — no user, no roles. The method is the boundary: gate sensitive tools, and understand that
273
273
  a public (keyless) server effectively exposes only the un-gated ones.
274
274
  - Input schemas are derived automatically from each method's input contract.
@@ -141,7 +141,7 @@ Routes are mounted at `/_/api{path}` (e.g. `DELETE /_/api/vendors/abc123`).
141
141
  - **Request body** for POST/PUT/PATCH is the input directly (no `{ input: {...} }` wrapper)
142
142
  - **Response** is the method output directly (no `{ output: {...} }` wrapper)
143
143
  - **Auth** via `Authorization: Bearer sk_...` — an API key resolves to a user with full RBAC, so the
144
- method's own `auth.requireRole`/`requireUser` checks apply exactly as they would for that user
144
+ method's own `auth.requireRole(...)`/`hasRole(...)` checks apply exactly as they would for that user
145
145
  - **Streaming**: `Accept: text/event-stream` header returns SSE chunks
146
146
  - **Raw request context**: Every API method receives `input._request` with `{ method, headers, rawBody }`.
147
147
  `rawBody` is the original unparsed body as a UTF-8 string — needed for signature verification, since
@@ -0,0 +1,359 @@
1
+ ---
2
+ name: Voice Interfaces
3
+ what: Realtime voice conversation as a first-class interface — the user talks to the app and its voice agent talks back in sub-second, interruptible speech, calling the app's methods mid-conversation as the authenticated user. The platform handles the media transport, turn-taking, barge-in, and transcripts, so the work is authorship — a persona written for the ear, a small toolset where every tool carries a latency class, and descriptions that say results out loud. Any app whose methods do something interesting can pick up a voice, and it is often the most impressive surface it has.
4
+ when: Before authoring `src/interfaces/voice.md`, choosing a voice model or pipeline, deciding which methods a voice agent gets, or building the voice UI with `createVoiceClient()`.
5
+ ---
6
+
7
+ # Building Voice Interfaces
8
+
9
+ A voice interface is the app's agent as a live phone-call-quality conversation: the user speaks, the
10
+ agent answers in speech, and the app's methods are its tools. It is a **sibling of the agent
11
+ interface, not a mode of it** — the two share a philosophy (an LLM projecting the backend contract
12
+ into conversation; load the `agentInterfaces` skill for that shared ground), but everything you
13
+ author differs. The persona is written for the ear, not the screen. The toolset is smaller and
14
+ curated for conversational latency. And every tool declares how the agent should handle the wait,
15
+ because in a live call, silence reads as a dropped line.
16
+
17
+ The platform owns the hard parts — realtime audio transport, turn detection, interruption handling,
18
+ transcripts, session limits, per-user auth on every tool call. Your job is the spec
19
+ (`src/interfaces/voice.md`) and its compilation into `dist/interfaces/voice/`.
20
+
21
+ ## Voice Agent Design
22
+
23
+ ### Written for the ear
24
+
25
+ Everything the agent produces gets spoken aloud. That inverts several habits that are correct
26
+ everywhere else, and the compiled system prompt must carry them explicitly:
27
+
28
+ - **No visual formatting, ever.** No markdown, no lists, no tables, no emoji, no URLs read as
29
+ punctuation soup. If a tool returns a link, say what it is and where it will be, don't recite it.
30
+ - **Spoken-form values.** "Forty-two fifty," not "$42.50". "Two fifteen in the afternoon," not
31
+ "14:15". Read email addresses and confirmation codes character by character, and read them *back*
32
+ for confirmation before acting on them — mishearing one digit of a phone number is the classic
33
+ voice failure.
34
+ - **Brevity is a hard rule, not a style preference.** One to two sentences per turn, one question at
35
+ a time. A paragraph that reads fine in chat is a monologue on a call.
36
+ - **Handle unclear audio explicitly.** Give the prompt a rule for it: respond only to clear audio;
37
+ if it's noisy or ambiguous, ask the user to repeat — never guess, and never call a tool on input
38
+ the agent isn't sure it heard.
39
+ - **Pin the language.** State the response language in the prompt; don't let the model infer it from
40
+ an accent.
41
+
42
+ Beyond the mechanics, the persona itself should be *of the ear*: pacing, warmth, how it handles
43
+ being interrupted, what it says when it needs a second. This is the fun part, same as the agent
44
+ interface — a distinct character beats a generic assistant, and voice makes character land harder
45
+ than any other surface.
46
+
47
+ ### The latency classes
48
+
49
+ Every tool in the spec declares one of three classes. This is the voice-specific discipline — get it
50
+ right and tool use feels like talking to a competent person; get it wrong and every action is an
51
+ awkward pause.
52
+
53
+ - **`fast`** — sub-second reads: lookups, availability checks, small queries. The agent calls
54
+ silently; announcing a sub-second call adds more delay than the call itself.
55
+ - **`slow`** — a noticeable wait, roughly one to three seconds: writes, searches, anything that does
56
+ real work. The agent speaks a one-line preamble ("Let me get that booked") generated in parallel
57
+ with the call, so the line never goes quiet.
58
+ - **`background`** — long-running work: reports, enrichment, bulk operations. The agent
59
+ acknowledges, keeps conversing, and reports the result when it lands. Background tools are
60
+ cancellable — if the user changes course mid-run, the work stops.
61
+
62
+ Classify by how the method actually behaves, not by what it is named. A "lookup" that fans out to an
63
+ external service is `slow`. When in doubt between `fast` and `slow`, pick `slow` — a needless
64
+ preamble is mildly chatty; an unexplained silence feels broken.
65
+
66
+ ### Tool descriptions say results out loud
67
+
68
+ Follow the agent-interface principles for tool descriptions (when to use and when not, parameter
69
+ guidance, what comes back) — plus one voice-specific layer: **how to speak the result.** A tool that
70
+ returns a booking record needs its description to say what the confirmation sounds like ("You're all
71
+ set for Tuesday at two") and what never gets read aloud (internal ids, timestamps, enum values).
72
+
73
+ Curate harder than you would for chat. A voice agent with four excellent tools outperforms one with
74
+ twelve adequate ones — every tool the model considers is a beat of hesitation. Skip batch
75
+ operations, admin utilities, and anything whose output can't be said in a breath or two. Note role
76
+ restrictions in the description so the agent declines gracefully in character instead of surfacing a
77
+ rejection.
78
+
79
+ ### Confirmation scales with risk
80
+
81
+ Bake the policy into the system prompt: read-only tools — just call them. Writes — summarize what's
82
+ about to happen and get a yes. Anything destructive or financial — read the details back first,
83
+ piece by piece. In voice there is no confirmation dialog to lean on; the conversation *is* the
84
+ confirmation UI.
85
+
86
+ ### Choosing the model
87
+
88
+ Two shapes, one `model` field:
89
+
90
+ - **Native speech-to-speech** (`{"model": ..., "voice": ...}`) — one realtime model hears and
91
+ speaks. Lowest latency, most natural prosody, hears tone and hesitation. The default for
92
+ personality-forward, conversational apps.
93
+ - **Cascaded** (`{"llm": ..., "stt": ..., "tts": ..., "voice": ...}`) — streaming transcription
94
+ into any chat model in the catalog, streaming speech out. Slightly higher latency, but the brain
95
+ can be *any* chat model — the right choice when the app's reasoning demands a specific model, or
96
+ when the agent interface already uses one and the voice should think identically. The blessed
97
+ streaming pairing is `"stt": "deepgram-nova-3", "tts": "cartesia-sonic-3"` — the lowest-latency
98
+ combination the platform wires; prefer it unless there's a reason not to. One nuance: cascaded
99
+ engines speak the `greeting` verbatim (they have a real TTS); speech-to-speech engines have the
100
+ model say it, so it may paraphrase slightly.
101
+
102
+ Ask `askMindStudioSdk` for available ids — realtime, transcription, and speech models are separate
103
+ catalogs, and MindStudio ids don't match vendor ids, so treat ids in this document as illustrative.
104
+ Voice ids are model-specific; query for those too. The user's UI has a picker for changing the model
105
+ later, so validate only when you set it.
106
+
107
+ ### Seeding from an existing agent
108
+
109
+ If the app already has an agent interface, start from it: same character, same values, same
110
+ terminology — then rewrite for the ear (shorter, spoken-form, no formatting) and re-curate the
111
+ toolset for latency. Don't copy `agent.md`'s prose wholesale; a chat persona read aloud sounds like
112
+ someone reading chat aloud.
113
+
114
+ ### Anti-patterns
115
+
116
+ - Prose that would render fine in chat — bullet lists, headers, or markdown anywhere in `system.md`.
117
+ - A tool description that explains what to display instead of what to say.
118
+ - Exposing the whole method surface. Voice is the most curated interface the app has.
119
+ - A generic greeting ("Hello! How can I assist you today?"). The greeting is the first thing anyone
120
+ hears; make it the character's.
121
+ - Writing your own current-user placeholder — the platform appends a `## Current User` block (name,
122
+ roles) to every system prompt at runtime.
123
+
124
+ ## Compiling the Voice Spec
125
+
126
+ When building `dist/interfaces/voice/`, consider the spec, the app, and the `@brand/` guidelines —
127
+ the voice agent should be unmistakably the same product as the web UI, projected into sound. Output:
128
+
129
+ **`system.md`** — the persona compiled for the ear. Character first, then the mandatory carries from
130
+ "Written for the ear" above (spoken-form rules, brevity, unclear-audio handling, language pinning,
131
+ confirmation-by-risk), then any preamble phrasing guidance for `slow` tools so the fillers sound like
132
+ the character too.
133
+
134
+ **`tools/*.md`** — one per tool: when to use, parameter guidance, how to say the result, role
135
+ restrictions.
136
+
137
+ **`interface.json`** — the config tying it together. Full shape in "The wiring" below.
138
+
139
+ ## Voice UI
140
+
141
+ When the app has a web interface, voice arrives as a **layer over it**, not a separate page: a
142
+ persistent affordance (a button, an orb in a corner) that starts a session in place, with the app
143
+ still visible and usable. A dedicated full-screen voice mode is the immersive option for apps where
144
+ the conversation *is* the product — earn it, don't default to it.
145
+
146
+ ### Frontend SDK: `createVoiceClient()`
147
+
148
+ Ships as a subpath of the interface SDK so apps that never use voice pay nothing for it. All voice
149
+ UIs go through it — never hand-roll audio capture or transport.
150
+
151
+ ```ts
152
+ import { createVoiceClient } from '@mindstudio-ai/interface/voice';
153
+
154
+ const voice = createVoiceClient();
155
+
156
+ // Prompts for mic permission, mints a session, connects.
157
+ // Throws MindStudioInterfaceError('microphone_denied') on refusal.
158
+ const session = await voice.startSession();
159
+
160
+ session.state; // 'connecting' | 'listening' | 'thinking' | 'speaking' | 'ended'
161
+ session.on('stateChange', (state) => { }); // on() returns an unsubscribe fn
162
+
163
+ // Live captions, both sides. Each event carries the segment's FULL text so
164
+ // far (never a delta) — render by upserting on segmentId, not appending.
165
+ session.on('transcript', ({ role, segmentId, text, final }) => { });
166
+
167
+ session.on('toolCall', ({ method, status }) => { }); // 'running' | 'done' | 'failed'
168
+ session.on('error', (err) => { });
169
+
170
+ session.mute(); session.unmute(); session.isMuted;
171
+ session.sendText('123 Main Street'); // inject text into the live conversation
172
+ session.end();
173
+ ```
174
+
175
+ Agent audio playback is handled inside the SDK (a hidden autoplaying element) — never create audio
176
+ elements for the agent. `startSession()` throws `MindStudioInterfaceError` with code
177
+ `microphone_denied` when mic access is refused (surface that state gently in the UI),
178
+ `voice_concurrency_limit` / `voice_visitor_limit` when the app's session limits are hit, and
179
+ `auth_required` (401) / `role_required` (403) when the interface's `auth` block denies the caller
180
+ (route those to the app's login flow).
181
+
182
+ Past sessions are call records with transcripts: `voice.listSessions()` /
183
+ `voice.getSession(id)` — the material for a history view if the app wants one.
184
+
185
+ ### The state machine, made visible
186
+
187
+ One audio-reactive element carries the session: idle → connecting → listening → thinking → speaking.
188
+ Always pair it with a **text state label** — never signal state by color or motion alone. Calm at
189
+ idle, responsive to actual audio levels while listening and speaking. Respect
190
+ `prefers-reduced-motion` with a static-but-labeled variant.
191
+
192
+ ### Live captions
193
+
194
+ Stream `transcript` events as captions — both sides of the conversation. Captions make the agent
195
+ feel accurate, catch mishearings early, and are the accessibility story. User-side transcripts
196
+ arrive as recognition output and can lag or differ slightly from what the model heard; render them
197
+ as captions, never treat them as input to app logic.
198
+
199
+ ### Controls that must exist
200
+
201
+ **Mute** and **end call**, always visible, always working. `sendText` earns its place the moment the
202
+ conversation needs an exact string — an address, a code, an email — typing it beats spelling it
203
+ aloud three times. Show tool activity as a compact inline status from `toolCall` events, in the
204
+ app's voice ("Booking your appointment…"), never raw names or JSON.
205
+
206
+ ### Anti-patterns
207
+
208
+ - Blocking the whole UI behind the session — voice is a layer, the app stays usable.
209
+ - An orb with no label, or state changes conveyed only by color.
210
+ - Rendering user-side captions as authoritative ("you said X") — they're recognition output.
211
+ - Auto-starting a session on page load. Microphone access is always a deliberate user action.
212
+
213
+ ---
214
+
215
+ # The wiring
216
+
217
+ ## Spec: `src/interfaces/voice.md`
218
+
219
+ Frontmatter holds the structured fields; the body is the persona plus an explicit `## Tools`
220
+ section.
221
+
222
+ ```yaml
223
+ ---
224
+ name: Front Desk
225
+ description: Books appointments and answers questions by voice.
226
+ type: interface/voice
227
+ model: {"model": "gpt-realtime-mini", "voice": "marin"}
228
+ turnDetection: {"eagerness": "medium"}
229
+ greeting: Hey! I can help you book, reschedule, or answer questions — what do you need?
230
+ ---
231
+ ```
232
+
233
+ Frontmatter fields:
234
+
235
+ - `name` — display name
236
+ - `description` — one-liner for listings
237
+ - `model` — JSON string, two shapes: native speech-to-speech `{"model": <realtime model id>,
238
+ "voice": <voice id>}`, or cascaded `{"llm": <chat model id>, "stt": <transcription model id>,
239
+ "tts": <speech model id>, "voice": <voice id>}`. Optional `config` for model-specific settings.
240
+ Ids via `askMindStudioSdk`.
241
+ - `turnDetection` — optional; `{"eagerness": "low" | "medium" | "high"}` — how quickly the platform
242
+ decides the user finished speaking. High is snappier; low is more patient (users dictating
243
+ numbers or addresses). Default `medium`.
244
+ - `greeting` — optional spoken opener, delivered on session start. Omit and the agent waits for the
245
+ user to speak first. Verbatim on cascaded engines; model-spoken (may paraphrase) on
246
+ speech-to-speech.
247
+
248
+ Body: persona prose (voice register), then the toolset:
249
+
250
+ ```markdown
251
+ ## Tools
252
+
253
+ ### Book appointment
254
+ method: book-appointment
255
+ latency: slow
256
+ ~~~
257
+ Book an appointment once the caller has confirmed a date, time, and service.
258
+ Read the details back and get a yes before calling. Say the confirmation
259
+ naturally ("You're all set for Tuesday the 4th at 2pm") — never read the
260
+ booking id aloud unless asked.
261
+ ~~~
262
+ ```
263
+
264
+ `latency` is one of `fast` / `slow` / `background` (semantics in "The latency classes" above).
265
+ Don't hand-author input schemas — the platform derives them from the method contract.
266
+
267
+ ## Compiled Output: `dist/interfaces/voice/`
268
+
269
+ ```
270
+ dist/interfaces/voice/
271
+ ├── interface.json ← config the platform reads
272
+ ├── system.md ← compiled voice-register system prompt
273
+ └── tools/
274
+ └── bookAppointment.md ← rich tool description, one per tool
275
+ ```
276
+
277
+ ## Config (`interface.json`)
278
+
279
+ The top-level key must match the interface type (`voice`):
280
+
281
+ ```json
282
+ {
283
+ "voice": {
284
+ "name": "Front Desk",
285
+ "description": "Books appointments and answers questions by voice.",
286
+ "model": "gpt-realtime-mini",
287
+ "voice": "marin",
288
+ "turnDetection": { "eagerness": "medium" },
289
+ "greeting": "Hey! I can help you book, reschedule, or answer questions — what do you need?",
290
+ "systemPrompt": "system.md",
291
+ "auth": { "requireUser": true },
292
+ "tools": [
293
+ { "method": "book-appointment", "latency": "slow", "description": "tools/bookAppointment.md" }
294
+ ],
295
+ "webInterfacePath": "/"
296
+ }
297
+ }
298
+ ```
299
+
300
+ | Field | Description |
301
+ |-------|-------------|
302
+ | `name`, `description` | Display name + listing metadata |
303
+ | `model` | Realtime model id (native speech-to-speech). Mutually exclusive with `llm`/`stt`/`tts` |
304
+ | `llm`, `stt`, `tts` | The cascaded alternative: chat model id + streaming transcription id + streaming speech id |
305
+ | `voice` | Provider voice id (model-specific; query `askMindStudioSdk`) |
306
+ | `turnDetection` | `{ "eagerness": "low" \| "medium" \| "high" }`, optional |
307
+ | `greeting` | Optional spoken opener |
308
+ | `systemPrompt` | Relative path to the compiled system prompt |
309
+ | `auth` | **Required.** Who may start a session: `{ "requireUser": boolean, "requireRole"?: string[] }`. See the Auth section below |
310
+ | `tools` | `{ method, latency, description }` — method `id` from the manifest, a latency class, and a relative path to the tool's markdown |
311
+ | `webInterfacePath` | Optional. Where the voice layer lives in the web interface, for the editor preview |
312
+
313
+ Declare it in `mindstudio.json`:
314
+
315
+ ```json
316
+ { "type": "voice", "path": "dist/interfaces/voice/interface.json" }
317
+ ```
318
+
319
+ ## Platform Behavior
320
+
321
+ - Input schemas are derived from each method's contract — never hand-written.
322
+ - The platform appends a `## Current User` block (name, roles) to the system prompt at runtime;
323
+ never author a placeholder for it.
324
+ - Turn detection, barge-in (interruption truncates the agent's context to the audio the user
325
+ actually heard), and background-noise handling are platform-managed; `turnDetection.eagerness` is
326
+ the only knob.
327
+ - Sessions have a per-app concurrency limit and a maximum duration, both configurable in the app's
328
+ settings; an idle session is ended gracefully after a prompt. Voice minutes and model usage are
329
+ metered.
330
+ - Every session persists as a call record with a transcript, visible in the dashboard and readable
331
+ from the frontend via `voice.listSessions()` / `voice.getSession(id)`.
332
+
333
+ ## Auth
334
+
335
+ **Every voice config declares an `auth` block.** A voice session spends the owner's money for its
336
+ entire duration without necessarily touching a backend method, so the platform gates session
337
+ creation itself:
338
+
339
+ ```json
340
+ "auth": { "requireUser": true, "requireRole": ["member"] }
341
+ ```
342
+
343
+ - `requireUser: true` — only authenticated app users may start a session; `false` — anyone,
344
+ including anonymous visitors. Most apps want `true`; choose `false` deliberately (a public
345
+ front-desk line).
346
+ - `requireRole` (optional) — the user must hold **at least one** of the listed manifest role ids
347
+ (OR semantics, same as the backend `auth.requireRole(...)`). Omit or leave empty for no role
348
+ gate. Requires `requireUser: true`. Unknown role ids fail the build.
349
+ - Denials reject `startSession()` with code `auth_required` (401) or `role_required` (403).
350
+ - Dev preview is exempt — the builder is never locked out while testing.
351
+ - Older compiled apps without the block fall back to the manifest's `auth.enabled` (auth-enabled →
352
+ users only; no auth → public). New configs always declare it explicitly.
353
+
354
+ Once inside, voice sessions run as the **authenticated user** — every tool call carries that
355
+ user's roles, so a method gated with `auth.requireRole` behaves exactly as it would from the web
356
+ frontend or the agent interface. Anonymous sessions (when allowed) have no user and no roles:
357
+ gated methods reject, and the caller's history is scoped to their browser's visitor identity.
358
+ That's why role restrictions belong in the tool descriptions — the agent should decline in
359
+ character, not relay a rejection.
@@ -19,7 +19,7 @@ The scaffold starts with these spec files that cover the full picture of the app
19
19
  - **`src/interfaces/@brand/voice.md`** — voice and terminology: tone, error messages, word choices
20
20
  - **`src/roadmap/`** — feature roadmap. One file per feature (`type: roadmap`). See "Roadmap" below.
21
21
 
22
- These are starting points, not constraints. Create as many spec files as the project needs — the `src/` folder is your workspace and every `.md` file in it becomes compilation context. If the app has substantial content (presentation slides, copy, lesson plans, menu items, quiz questions), put it in its own file (`src/content.md`, `src/slides.md`, `src/menu.md`, etc.) rather than cramming it into `app.md` or `web.md`. If the domain is complex, split `app.md` into multiple files by area (`src/billing.md`, `src/approvals.md`). Add interface specs for other interface types (`api.md`, `webhook.md`, `cron.md`, `email.md`, `mcp.md`, `agent.md`) if the app uses them. Each of those has a skill carrying its spec format and config — `restApi`, `webhooks`, `scheduledJobs`, `inboundEmail`, `mcpInterfaces`, `agentInterfaces` — and you should load the relevant one before writing the spec rather than after, since the spec is what the config is compiled from. For external HTTP the choice is between two of them: the Webhook interface handles inbound provider webhooks (Stripe, GitHub) via secret-in-URL routing, while the API interface covers bearer-auth sync endpoints, public REST APIs, and batch tools. Organize however serves clarity — the platform reads the entire `src/` folder.
22
+ These are starting points, not constraints. Create as many spec files as the project needs — the `src/` folder is your workspace and every `.md` file in it becomes compilation context. If the app has substantial content (presentation slides, copy, lesson plans, menu items, quiz questions), put it in its own file (`src/content.md`, `src/slides.md`, `src/menu.md`, etc.) rather than cramming it into `app.md` or `web.md`. If the domain is complex, split `app.md` into multiple files by area (`src/billing.md`, `src/approvals.md`). Add interface specs for other interface types (`api.md`, `webhook.md`, `cron.md`, `email.md`, `mcp.md`, `agent.md`, `voice.md`) if the app uses them. Each of those has a skill carrying its spec format and config — `restApi`, `webhooks`, `scheduledJobs`, `inboundEmail`, `mcpInterfaces`, `agentInterfaces`, `voiceInterfaces` — and you should load the relevant one before writing the spec rather than after, since the spec is what the config is compiled from. For external HTTP the choice is between two of them: the Webhook interface handles inbound provider webhooks (Stripe, GitHub) via secret-in-URL routing, while the API interface covers bearer-auth sync endpoints, public REST APIs, and batch tools. Organize however serves clarity — the platform reads the entire `src/` folder.
23
23
 
24
24
  Remember: users care about look and feel as much as (and often more than) underlying data structures. Don't treat the brand and interface specs as an afterthought — for many users, the visual identity and voice are the first things they want to get right.
25
25
 
@@ -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, generates a custom illustration, and saves the finished record itself. These agents can call the app's own methods too, so they can read existing data to decide what needs doing and write results straight back. 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, 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 (text chat and realtime voice) — 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
 
@@ -23,7 +23,7 @@ Don't recite this list to users. Use it to calibrate your sense of what's possib
23
23
  - **AI-powered apps** — a document processor that extracts structured data from uploaded contracts, an AI image tool that transforms selfies into stylized portraits, a content generator that produces a week of social posts from one brief
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
- - **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
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. The same agents can also answer by realtime voice — a live, interruptible conversation with the app
27
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindstudio-ai/remy",
3
- "version": "0.1.261",
3
+ "version": "0.1.263",
4
4
  "description": "Remy coding agent",
5
5
  "repository": {
6
6
  "type": "git",