@mindstudio-ai/remy 0.1.121 → 0.1.123

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
@@ -378,6 +378,10 @@ Current date: ${now}
378
378
  <scenarios>
379
379
  {{compiled/scenarios.md}}
380
380
  </scenarios>
381
+
382
+ <secrets>
383
+ {{compiled/secrets.md}}
384
+ </secrets>
381
385
  </platform_docs>
382
386
 
383
387
  <mindstudio_agent_sdk_docs>
@@ -4056,6 +4060,7 @@ TypeScript running in a sandboxed environment. Any npm package can be installed.
4056
4060
 
4057
4061
  - Managed SQLite database with typed schemas and automatic migrations. Define a TypeScript interface, push, and the platform handles diffing and migrating.
4058
4062
  - Built-in app-managed auth. Opt-in via manifest \u2014 developer builds login UI, platform handles verification codes (email/SMS), cookie sessions, and role enforcement. Backend methods use auth.requireRole() for access control.
4063
+ - Encrypted secrets with separate dev/prod values, injected as process.env. For third-party service credentials not covered by the SDK.
4059
4064
  - Git-native deployment. Push to default branch to deploy.
4060
4065
 
4061
4066
  ## MindStudio SDK
package/dist/index.js CHANGED
@@ -3941,6 +3941,7 @@ TypeScript running in a sandboxed environment. Any npm package can be installed.
3941
3941
 
3942
3942
  - Managed SQLite database with typed schemas and automatic migrations. Define a TypeScript interface, push, and the platform handles diffing and migrating.
3943
3943
  - Built-in app-managed auth. Opt-in via manifest \u2014 developer builds login UI, platform handles verification codes (email/SMS), cookie sessions, and role enforcement. Backend methods use auth.requireRole() for access control.
3944
+ - Encrypted secrets with separate dev/prod values, injected as process.env. For third-party service credentials not covered by the SDK.
3944
3945
  - Git-native deployment. Push to default branch to deploy.
3945
3946
 
3946
3947
  ## MindStudio SDK
@@ -5938,6 +5939,10 @@ Current date: ${now}
5938
5939
  <scenarios>
5939
5940
  {{compiled/scenarios.md}}
5940
5941
  </scenarios>
5942
+
5943
+ <secrets>
5944
+ {{compiled/secrets.md}}
5945
+ </secrets>
5941
5946
  </platform_docs>
5942
5947
 
5943
5948
  <mindstudio_agent_sdk_docs>
@@ -16,7 +16,8 @@ MindStudio apps can have and manage their own users. Auth is opt-in: configure i
16
16
  "columns": {
17
17
  "email": "email",
18
18
  "phone": "phone",
19
- "roles": "roles"
19
+ "roles": "roles",
20
+ "apiKey": "apiKey"
20
21
  }
21
22
  }
22
23
  },
@@ -32,11 +33,13 @@ MindStudio apps can have and manage their own users. Auth is opt-in: configure i
32
33
  - **`auth.methods`** — which verification methods the app supports. At least one required.
33
34
  - `email-code` — 6-digit code sent via email
34
35
  - `sms-code` — 6-digit code sent via SMS
36
+ - `api-key` — programmatic access via `Authorization: Bearer sk_...` header. Resolves to a user with full RBAC.
35
37
  - **`auth.table.name`** — name of the `defineTable` table that holds user records.
36
38
  - **`auth.table.columns`** — maps platform-managed fields to column names in the developer's table.
37
39
  - `email` — required if `email-code` is in methods
38
40
  - `phone` — required if `sms-code` is in methods
39
41
  - `roles` — optional. Maps to a JSON array column for role assignments.
42
+ - `apiKey` — optional. Required if `api-key` is in methods. Platform stores masked value (`sk_...xxxx`) for display; one key per user.
40
43
  - **`roles`** — declares valid roles for the app. Same as before: `id`, `name`, optional `description`.
41
44
 
42
45
  ## Auth Table
@@ -51,6 +54,7 @@ export const Users = db.defineTable<{
51
54
  email: string;
52
55
  phone?: string;
53
56
  roles: string[];
57
+ apiKey?: string; // masked value (sk_...xxxx), read-only from code
54
58
  // Developer's own fields
55
59
  displayName: string;
56
60
  plan: 'free' | 'pro';
@@ -60,7 +64,7 @@ export const Users = db.defineTable<{
60
64
 
61
65
  ### Platform-Managed Column Behavior
62
66
 
63
- - **`email` / `phone`** — read-only from code. Writing via `update()` or `push()` throws a `MindStudioError`. Use the auth API to change a user's email or phone.
67
+ - **`email` / `phone` / `apiKey`** — read-only from code. Writing via `update()` or `push()` throws a `MindStudioError`. Use the auth API to change a user's email or phone, and `auth.createApiKey()` / `auth.revokeApiKey()` for API keys.
64
68
  - **`roles`** — read/write from both code and the dashboard. `Users.update(userId, { roles: ['admin'] })` works and syncs to the platform. Dashboard role changes sync back to the table.
65
69
  - All other columns are fully the developer's. When auth creates a user row, only the managed columns (email/phone, roles) are populated. All user-defined columns start as null until the user completes onboarding — type them as optional and guard against null.
66
70
 
@@ -80,6 +84,7 @@ interface AppUser {
80
84
  email: string | null;
81
85
  phone: string | null;
82
86
  roles: string[];
87
+ apiKey: string | null; // masked value (sk_...xxxx), null if no key
83
88
  createdAt: string;
84
89
  }
85
90
  ```
@@ -139,6 +144,24 @@ const user = await auth.confirmPhoneChange('+15559876543', '123456');
139
144
  await auth.logout(); // clears session
140
145
  ```
141
146
 
147
+ ### API Keys
148
+
149
+ For apps with `api-key` in their auth methods. API keys resolve to a user with the same `auth.userId`, `auth.roles`, and `requireRole()` enforcement as a cookie session.
150
+
151
+ ```typescript
152
+ // Generate a key for the current user (must be logged in)
153
+ const { key } = await auth.createApiKey();
154
+ // key = "sk_..." — show once, not stored. user.apiKey updates to masked value.
155
+
156
+ // Revoke current user's key
157
+ await auth.revokeApiKey();
158
+ // user.apiKey becomes null
159
+ ```
160
+
161
+ Both methods fire `onAuthStateChanged` since they modify the user object. One key per user — creating a new key replaces the old one.
162
+
163
+ Consumers use the key as a Bearer token: `Authorization: Bearer sk_...`. The platform resolves it to the user, populates the auth context, and executes the method normally. Invalid or revoked key: 401.
164
+
142
165
  ### Error Codes
143
166
 
144
167
  All auth methods throw on failure with a `code` property:
@@ -151,6 +174,7 @@ All auth methods throw on failure with a `code` property:
151
174
  | `max_attempts_exceeded` | 400 | Too many failed attempts |
152
175
  | `not_authenticated` | 401 | No active session |
153
176
  | `invalid_session` | 401 | Session expired or invalid |
177
+ | `not_supported` | 400 | Feature not enabled for this app (e.g. API keys without `api-key` in methods) |
154
178
 
155
179
  ### Phone Helpers
156
180
 
@@ -200,6 +224,19 @@ Array of role IDs assigned to the current user.
200
224
 
201
225
  Returns an array of user IDs with the specified role.
202
226
 
227
+ ### System Role (Platform Triggers)
228
+
229
+ 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:
230
+
231
+ ```typescript
232
+ export async function regenerateCache(input: {}) {
233
+ auth.requireRole('system');
234
+ // Only cron, webhooks, and users with 'system' role can reach this
235
+ }
236
+ ```
237
+
238
+ Web frontend calls (`/_/methods`), API interface calls (`/_/api`), and agent chat all run as the authenticated user — they don't get the system role unless the user has been explicitly assigned it. You can assign `system` to app users via the dashboard or SDK if they need to manually trigger these methods.
239
+
203
240
  ## Login Page Example
204
241
 
205
242
  ```tsx
@@ -98,7 +98,7 @@ Even if the app is intuitive and easy to use, users showing up for the first tim
98
98
  ## What to Actively Avoid At All Costs
99
99
 
100
100
  - **Avoid generic fonts.** Overused defaults that strip away all personality. Instead: pick a distinctive Google Font that fits the app's character.
101
- - **Avoid purple or indigo anything.** Purple gradients, purple buttons, purple accents are overused. The user will be dismissive of our designs if they come out looking purple or indigo.
101
+ - **Avoid purple or indigo anything.** Purple gradients, purple buttons, purple accents are overused. The user will be dismissive of our designs if they come out looking purple or indigo. Avoid terracotta for similar reasons.
102
102
  - **Avoid colored left-border callout boxes.** Rounded divs with a thick colored `border-left` — the generic "info card" pattern. Instead: use typography, spacing, and background tints to create hierarchy. If you need to call something out, use a full subtle background or a top border.
103
103
  - **Avoid three equal boxes with icons.** The default AI landing page layout. Instead: use asymmetric layouts, varied column widths, or a single focused content area.
104
104
  - **Avoid timid color palettes.** Evenly distributed, non-committal colors. Instead: one or two dominant colors with sharp accents. Commit to a direction.
@@ -94,36 +94,135 @@ On deploy, the platform runs `npm install && npm run build` in the web directory
94
94
 
95
95
  ## API Interface
96
96
 
97
- Auto-generated REST endpoints. Every method becomes an API endpoint.
97
+ REST endpoints for external consumers — other services, mobile apps, integrations. This is separate from the web frontend's internal RPC (`@mindstudio-ai/interface` calls `/_/methods` directly and does not use the API interface). The API interface lives at `/_/api/` and exposes only the methods you choose to route.
98
98
 
99
- ### Config (`interface.json`)
99
+ Use it for receiving webhooks (Stripe, Twilio), sync endpoints for other services, a public REST API, batch tools — anything where something outside the app's own frontend needs to call a method over HTTP.
100
100
 
101
- ```json
102
- {
103
- "methods": ["submit-vendor-request", "list-vendors", "get-dashboard"]
104
- }
105
- ```
101
+ ### Spec: `src/interfaces/api.md`
106
102
 
107
- Omit the `methods` field (or the config entirely) to expose all methods.
103
+ The human-readable spec. Frontmatter declares the API name and description; the body maps methods to REST routes using MSFM.
108
104
 
109
- ### Usage
105
+ ```yaml
106
+ ---
107
+ name: Vendor Management API
108
+ description: API for managing vendors and purchase orders.
109
+ type: interface/api
110
+ ---
111
+ ```
110
112
 
111
- ```bash
112
- curl -X POST https://{app-subdomain}.mindstudio.ai/_/methods/submit-vendor-request/invoke \
113
- -H "Authorization: Bearer sk..." \
114
- -H "Content-Type: application/json" \
115
- -d '{ "input": { "name": "Acme" } }'
113
+ Routes are declared as `VERB /path → methodExportName` under resource headings, with annotations for params and descriptions:
114
+
115
+ ```markdown
116
+ ## Vendors
117
+
118
+ ### List vendors
119
+ GET /vendors → listVendors
120
+ ~~~
121
+ Returns all vendors, optionally filtered by status.
122
+ query: status (string, optional) — filter by vendor status
123
+ ~~~
124
+
125
+ ### Create vendor
126
+ POST /vendors → submitVendorRequest
127
+ ~~~
128
+ Submit a new vendor for approval.
129
+ body: name (string, required) — vendor name
130
+ contactEmail (string, required) — billing contact
131
+ ~~~
132
+
133
+ ### Delete vendor
134
+ DELETE /vendors/:vendorId → deleteVendor
135
+ ~~~
136
+ path: vendorId (string, required) — the vendor's unique identifier
137
+ ~~~
116
138
  ```
117
139
 
118
- Auth via API key. Returns `{ output, $releaseId, $methodId }`.
140
+ ### Compiled Output: `dist/interfaces/api/api.json`
119
141
 
120
- ### Streaming
142
+ ```json
143
+ {
144
+ "api": {
145
+ "name": "Vendor Management API",
146
+ "description": "API for managing vendors and purchase orders.",
147
+ "routes": [
148
+ {
149
+ "method": "GET",
150
+ "path": "/vendors",
151
+ "handler": "list-vendors",
152
+ "summary": "List vendors",
153
+ "description": "Returns all vendors, optionally filtered by status.",
154
+ "tag": "Vendors",
155
+ "params": {
156
+ "query": {
157
+ "status": { "type": "string", "required": false, "description": "Filter by vendor status" }
158
+ }
159
+ }
160
+ },
161
+ {
162
+ "method": "POST",
163
+ "path": "/vendors",
164
+ "handler": "submit-vendor-request",
165
+ "summary": "Create vendor",
166
+ "description": "Submit a new vendor for approval.",
167
+ "tag": "Vendors",
168
+ "params": {
169
+ "body": {
170
+ "name": { "type": "string", "required": true, "description": "Vendor name" },
171
+ "contactEmail": { "type": "string", "required": true, "description": "Billing contact" }
172
+ }
173
+ }
174
+ },
175
+ {
176
+ "method": "DELETE",
177
+ "path": "/vendors/:vendorId",
178
+ "handler": "delete-vendor",
179
+ "summary": "Delete vendor",
180
+ "description": "Permanently remove a vendor.",
181
+ "tag": "Vendors",
182
+ "params": {
183
+ "path": {
184
+ "vendorId": { "type": "string", "required": true, "description": "The vendor's unique identifier" }
185
+ }
186
+ }
187
+ }
188
+ ]
189
+ }
190
+ }
191
+ ```
121
192
 
122
- ```bash
123
- curl -X POST ... -d '{ "input": {...}, "stream": true }'
193
+ | Field | Description |
194
+ |-------|-------------|
195
+ | `name` | API display name (used in generated OpenAPI spec) |
196
+ | `description` | API description |
197
+ | `routes[].method` | HTTP method: `GET`, `POST`, `PUT`, `PATCH`, `DELETE` |
198
+ | `routes[].path` | URL path with `:param` placeholders for path params |
199
+ | `routes[].handler` | Method `id` from the manifest (kebab-case) |
200
+ | `routes[].summary` | Short description for the endpoint |
201
+ | `routes[].description` | Longer description |
202
+ | `routes[].tag` | Resource grouping (becomes a tag in OpenAPI) |
203
+ | `routes[].params` | Parameter declarations: `path`, `query`, and/or `body` objects |
204
+
205
+ ### Platform Behavior
206
+
207
+ Routes are mounted at `/_/api{path}` (e.g. `DELETE /_/api/vendors/abc123`).
208
+
209
+ - **Path params** are extracted and merged into the method's input: `/:vendorId` → `{ vendorId: "abc123" }`
210
+ - **Query params** are merged into input for GET requests: `?status=approved` → `{ status: "approved" }`
211
+ - **Request body** for POST/PUT/PATCH is the input directly (no `{ input: {...} }` wrapper)
212
+ - **Response** is the method output directly (no `{ output: {...} }` wrapper)
213
+ - **Auth** via `Authorization: Bearer sk_...` (API key resolves to a user with full RBAC)
214
+ - **Streaming**: `Accept: text/event-stream` header returns SSE chunks
215
+ - **Raw request context**: Every API method receives `input._request` with `{ method, headers, rawBody }`. `rawBody` is the original unparsed body as a UTF-8 string — critical for webhook signature verification (Stripe, GitHub, Shopify). For most methods you don't need `_request` at all.
216
+
217
+ ### Manifest
218
+
219
+ ```json
220
+ { "type": "api", "path": "dist/interfaces/api/api.json" }
124
221
  ```
125
222
 
126
- Returns SSE: `data: { type: 'token', text }` chunks, then `data: { type: 'done', output }`.
223
+ ## Platform-Triggered Interfaces
224
+
225
+ 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.
127
226
 
128
227
  ## Discord Bot
129
228
 
@@ -40,7 +40,7 @@
40
40
 
41
41
  "interfaces": [
42
42
  { "type": "web", "path": "dist/interfaces/web/web.json" },
43
- { "type": "api" },
43
+ { "type": "api", "path": "dist/interfaces/api/api.json" },
44
44
  { "type": "cron", "path": "dist/interfaces/cron/interface.json" }
45
45
  ],
46
46
 
@@ -71,11 +71,12 @@
71
71
  | Field | Type | Required | Description |
72
72
  |-------|------|----------|-------------|
73
73
  | `enabled` | `boolean` | Yes | `true` to enable auth |
74
- | `methods` | `string[]` | Yes | Auth methods: `"email-code"`, `"sms-code"`. At least one required. |
74
+ | `methods` | `string[]` | Yes | Auth methods: `"email-code"`, `"sms-code"`, `"api-key"`. At least one required. |
75
75
  | `table.name` | `string` | Yes | Name of the `defineTable` table holding user records |
76
76
  | `table.columns.email` | `string` | If email-code | Column name for email (platform-managed, read-only from code) |
77
77
  | `table.columns.phone` | `string` | If sms-code | Column name for phone (platform-managed, read-only from code) |
78
78
  | `table.columns.roles` | `string` | No | Column name for roles array (bidirectional sync) |
79
+ | `table.columns.apiKey` | `string` | If api-key | Column name for API key (platform-managed, stores masked value) |
79
80
 
80
81
  ### `roles`
81
82
  `Array<{ id, name?, description? }>`. Defaults to `[]`.
@@ -252,3 +252,43 @@ const result = await api.generateReport(
252
252
  ```
253
253
 
254
254
  The platform handles the SSE transport. The method returns normally — streaming is managed by the SDK and platform, not by your method code.
255
+
256
+ ## Raw Request Context (API Interface)
257
+
258
+ Methods invoked via the API interface receive `input._request` alongside the parsed input:
259
+
260
+ ```typescript
261
+ input._request: {
262
+ method: string; // "GET", "POST", etc.
263
+ headers: Record<string, string>; // all headers (lowercase keys)
264
+ rawBody: string | undefined; // original unparsed body (UTF-8)
265
+ }
266
+ ```
267
+
268
+ `rawBody` preserves the exact bytes the client sent — whitespace, key ordering, encoding. Use it for webhook signature verification:
269
+
270
+ ```typescript
271
+ export async function stripeWebhook(input: {
272
+ type: string;
273
+ data: any;
274
+ _request: { headers: Record<string, string>; rawBody: string };
275
+ }) {
276
+ const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
277
+
278
+ const event = stripe.webhooks.constructEvent(
279
+ input._request.rawBody,
280
+ input._request.headers['stripe-signature'],
281
+ process.env.STRIPE_WEBHOOK_SECRET!,
282
+ );
283
+
284
+ switch (event.type) {
285
+ case 'payment_intent.succeeded':
286
+ // ...
287
+ break;
288
+ }
289
+
290
+ return { received: true };
291
+ }
292
+ ```
293
+
294
+ For most methods, you don't need `_request` — the parsed path params, query params, and body fields are already on `input` directly.
@@ -40,7 +40,7 @@ my-app/
40
40
  web.json dev server config
41
41
  package.json
42
42
  src/
43
- api/interface.json REST API config
43
+ api/api.json REST API config
44
44
  discord/interface.json Discord bot config
45
45
  telegram/interface.json Telegram bot config
46
46
  cron/interface.json cron config
@@ -96,6 +96,7 @@ const { vendor } = await api.approveVendor({ vendorId: '...' });
96
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.
97
97
  - **Sandboxed execution.** Each method invocation runs in its own isolated execution context with npm packages pre-installed.
98
98
  - **Git-native deployment.** Push to default branch to deploy. Push to feature branch for preview. Rollback is a git revert.
99
+ - **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.
99
100
 
100
101
  ## Minimum Viable App
101
102
 
@@ -0,0 +1,40 @@
1
+ # Secrets & Environment Variables
2
+
3
+ Apps can store encrypted secrets (API keys, database URLs, tokens) that get injected into method execution as `process.env` variables. Secrets have separate dev and prod values — dev values are used in the editor sandbox, prod values are used in deployed releases.
4
+
5
+ ## When to Use Secrets
6
+
7
+ Secrets are for third-party services that aren't covered by the MindStudio SDK. If the SDK already provides a capability (AI models, SMS, email, web search, image generation, etc.), use the SDK — it handles auth, billing, and key management automatically.
8
+
9
+ Use secrets for things like Stripe, webhook signing secrets, or any other external service you connect to directly.
10
+
11
+ Never expose secrets to frontends or interfaces. You can only consume secrets in backend methods.
12
+
13
+ ## Accessing Secrets
14
+
15
+ ```typescript
16
+ export async function createPaymentIntent(input: { amount: number }) {
17
+ const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
18
+ // stripe.create....
19
+ }
20
+ ```
21
+
22
+ Never hardcode credentials in method source — always use `process.env`.
23
+
24
+ ## Key Format
25
+
26
+ Uppercase snake_case, starting with a letter: `STRIPE_SECRET_KEY`, `DATABASE_URL`, `GITHUB_TOKEN`.
27
+
28
+ ## Dev vs Prod
29
+
30
+ Each secret has a dev value and a prod value. The same code (`process.env.STRIPE_SECRET_KEY`) automatically resolves to the right value based on execution context. Use test/sandbox keys for dev, live keys for prod - or use the same value for both if the service does not make a distinction.
31
+
32
+ ## Management
33
+
34
+ Secrets are managed through the app's dashboard or the `mindstudio-prod secrets` CLI.
35
+
36
+ ## What NOT to Store
37
+
38
+ - AI model API keys (OpenAI, Anthropic, Google) — use the SDK
39
+ - Keys for platform-provided integrations (SMS, email, web search, image gen) — use the SDK
40
+ - Non-sensitive values — use method input parameters or database tables
@@ -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`, `cron.md`, `agent.md`, etc.) if the app uses them. 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`, `cron.md`, `agent.md`, etc.) if the app uses them. The API interface is useful whenever the app needs to receive or serve external HTTP requests — webhook endpoints, sync APIs, batch tools — not just comprehensive REST APIs. 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
 
@@ -47,12 +47,17 @@ For multi-step tasks with branching logic (research, enrichment, content pipelin
47
47
  ### State Management
48
48
  - Calls to methods introduce latency. When building web frontends that load data from methods, front-load as much data as you can in a single API request - e.g., when possible, load a large data object into a central store and use that to render sub-screens in an app, rather than an API call on every screen. User experience and perceived speed/performance are far more valuable than normalization and good REST API design.
49
49
 
50
+ ### Secrets & Third-Party Integrations
51
+ When a method needs credentials for a third-party service, use `process.env` and use the CLI to set it on behalf of the user (chat logs are secure and scrubbed, so it's fine for them to paste) or they can set it manually in the Dashboard.
52
+
53
+ When integrating with external services that have programmable setup APIs (webhook registration, OAuth app config, etc.), automate the setup rather than sending the user to the service's dashboard. If you have the API key in `process.env`, use it to register webhooks, configure endpoints, and store any resulting secrets (like signing keys) automatically. The user shouldn't have to leave the conversation for setup steps you can handle programmatically.
54
+
50
55
  ### Dependencies
51
56
  Before installing a package you haven't used in this project, do a quick web search to confirm it's still the best option. The JavaScript ecosystem moves fast — the package you remember from training may have been superseded by something smaller, faster, or better maintained. A 10-second search beats debugging a deprecated library.
52
57
 
53
58
  ### Production App Management
54
59
  You have access to `mindstudio-prod`, a CLI for managing the user's production MindStudio app. Use it via your bash tool. All output is JSON. Run `mindstudio-prod --help` or `mindstudio-prod <command> --help` to discover usage and available options.
55
60
 
56
- Available commands: `requests` (logs, error rates, latency), `releases` (deploy status, history), `domains` (custom subdomain management), `users` (list, set roles), `db` (query production sql db), `methods` (list, invoke).
61
+ Available commands: `requests` (logs, error rates, latency), `releases` (deploy status, history), `domains` (custom subdomain management), `users` (list, set roles), `db` (query production sql db), `methods` (list, invoke), `secrets` (list, get, set, delete).
57
62
 
58
63
  Use when the user asks about production behavior (errors, logs, metrics), wants to manage their live app (domains, users, roles), needs to seed or query production data, or wants to check release status.
@@ -17,7 +17,7 @@
17
17
  - Pushing to main branch will trigger a deploy. The user presses the publish button in the interface to request publishing.
18
18
 
19
19
  ### Build Notes
20
- For complex tasks — especially an initial buildout from a spec or making multiple changes in a single turn — write a `.remy-notes.md` scratchpad in the project root. Use it to track progress: a checklist of what's been built and what's remaining. Do not include implementation details or other decisions in the notes - it is solely for keeping track of tasks. Read the spec files directly when you need design details, implementation decisions, or other reference materials. Delete the notes file when your work is done.
20
+ For complex tasks — especially an initial buildout from a spec or making multiple changes in a single turn — write a `.remy-notes.md` scratchpad in the project root. Use it to track progress: a checklist of what's been built and what's remaining. Do not include implementation details or other decisions in the notes - it is solely for keeping track of tasks. Read the spec files directly when you need design details, implementation decisions, or other reference materials - never write them to the notes file. Delete the notes file when your work is done.
21
21
 
22
22
  ## Communication
23
23
  The user can already see your tool calls, so most of your work is visible without narration. Focus text output on three things:
@@ -8,6 +8,8 @@ Most things are fine. These are fast-moving products built by non-technical user
8
8
 
9
9
  **A package is dead or superseded.** If the plan involves a package, do a quick web search. Only flag it if there's a clearly better, actively maintained alternative. "This works fine" is a valid finding.
10
10
 
11
+ **External HTTP endpoints should use the API interface.** If the plan involves receiving webhooks from external services (Stripe, Twilio, etc.), exposing sync endpoints, or serving any external HTTP requests, flag that the API interface (`src/interfaces/api.md`) is the right tool. Don't build custom HTTP handling when the platform handles routing, auth, and OpenAPI generation.
12
+
11
13
  **There's a managed SDK action for this.** If the plan involves writing custom code for something that sounds like media processing, email/SMS, third-party APIs, or AI model calls — check `askMindStudioSdk`. The managed action handles retries, auth, and scaling.
12
14
 
13
15
  **Project organization needs a reset.** After heavy iteration, a file or folder structure might have grown unwieldy. If things would genuinely benefit from being reorganized, say so. But only at the structural level — "this 500-line component should be a folder" not "rename this variable."
@@ -16,6 +18,8 @@ Most things are fine. These are fast-moving products built by non-technical user
16
18
 
17
19
  These are things we already know about and have decided to accept:
18
20
 
21
+ - API interface methods have access to `input._request.rawBody` for webhook signature verification (Stripe, GitHub, etc.). Do NOT suggest external proxies or workarounds — the raw body is available natively.
22
+
19
23
  - Limited browser support for `oklch` gradients using `in <colorspace>` syntax — we accept the compatibility tradeoff for better color quality
20
24
  - Limited browser support for CSS scroll-driven animations (`animation-timeline: scroll()` / `view()`) - we accept this tradeoff
21
25
  - Platform SDKs (these are the core of every MindStudio app):
@@ -36,6 +40,10 @@ These are things we already know about and have decided to accept:
36
40
 
37
41
  ### Common pitfalls (always flag these)
38
42
 
43
+ - **External redirects in iframe.** If the plan involves redirecting to a third-party domain (payment checkout, OAuth login, external auth), flag that `window.location.href = url` will break in the preview iframe. Use `window.open(url, '_top')` for same-tab navigation or `window.open(url, '_blank')` for a new tab. This applies to any external redirect — Stripe, OAuth providers, third-party login pages.
44
+
45
+ - **Hardcoded credentials.** If the plan or code contains API keys, tokens, or connection strings inline, flag it — these should be `process.env` secrets managed via the dashboard. Also flag if the plan uses `process.env` for something the MindStudio SDK already handles (AI model keys, email/SMS sending, etc.).
46
+
39
47
  These are recurring mistakes the coding agent makes. If you see the conditions for any of these, flag it proactively:
40
48
 
41
49
  - **CSS Module animation scoping.** If the agent defines `@keyframes` in a global CSS file but references the animation name from a CSS Module, the animation will silently fail. CSS Modules scope animation names, so a keyframe defined globally can't be found by a scoped class. The fix: define keyframes in the same CSS Module that uses them, or use `:global()` to escape the scoping.
@@ -46,7 +46,7 @@ Every interface must work on both desktop and mobile.
46
46
  ## What to Actively Avoid At All Costs
47
47
 
48
48
  - **Avoid generic fonts.** Overused defaults that strip away all personality. Instead: pick a distinctive Google Font that fits the app's character.
49
- - **Avoid purple or indigo anything.** Purple gradients, purple buttons, purple accents are overused. The user will be dismissive of our designs if they come out looking purple or indigo.
49
+ - **Avoid purple or indigo anything.** Purple gradients, purple buttons, purple accents are overused. The user will be dismissive of our designs if they come out looking purple or indigo. Avoid terracotta for similar reasons. Challenge yourself to choose beautiful, modern, 2026-inspired colors.
50
50
  - **Avoid colored left-border callout boxes.** Rounded divs with a thick colored `border-left` — the generic "info card" pattern. Instead: use typography, spacing, and background tints to create hierarchy. If you need to call something out, use a full subtle background or a top border.
51
51
  - **Avoid three equal boxes with icons.** The default AI landing page layout. Instead: use asymmetric layouts, varied column widths, or a single focused content area.
52
52
  - **Avoid timid color palettes.** Evenly distributed, non-committal colors. Instead: one or two dominant colors with sharp accents. Commit to a direction.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindstudio-ai/remy",
3
- "version": "0.1.121",
3
+ "version": "0.1.123",
4
4
  "description": "MindStudio coding agent",
5
5
  "repository": {
6
6
  "type": "git",