@mindstudio-ai/remy 0.1.115 → 0.1.117

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
@@ -2507,7 +2507,7 @@ var queryDatabaseTool = {
2507
2507
  };
2508
2508
 
2509
2509
  // src/subagents/common/analyzeImage.ts
2510
- var VISION_MODEL = "claude-4.5-sonnet";
2510
+ var VISION_MODEL = "gemini-3-flash";
2511
2511
  var VISION_MODEL_OVERRIDE = JSON.stringify({
2512
2512
  model: VISION_MODEL,
2513
2513
  config: { thinkingBudget: "off" }
@@ -3162,6 +3162,39 @@ ${partial}` : "[INTERRUPTED] Agent was interrupted before producing output.",
3162
3162
 
3163
3163
  // src/subagents/browserAutomation/tools.ts
3164
3164
  var BROWSER_TOOLS = [
3165
+ {
3166
+ clearable: false,
3167
+ name: "setupBrowser",
3168
+ description: "Pre-authenticate the browser and optionally navigate to a starting page. Call this before interacting with authenticated content instead of manually logging in. Auth is optional \u2014 omit to just navigate without authenticating.",
3169
+ inputSchema: {
3170
+ type: "object",
3171
+ properties: {
3172
+ auth: {
3173
+ type: "object",
3174
+ description: "Authentication config. Upserts the user if they don't exist.",
3175
+ properties: {
3176
+ email: {
3177
+ type: "string",
3178
+ description: "User email address."
3179
+ },
3180
+ phone: {
3181
+ type: "string",
3182
+ description: "User phone number."
3183
+ },
3184
+ roles: {
3185
+ type: "array",
3186
+ items: { type: "string" },
3187
+ description: "Roles to set on the user."
3188
+ }
3189
+ }
3190
+ },
3191
+ path: {
3192
+ type: "string",
3193
+ description: 'Navigate to this path after setup (default "/").'
3194
+ }
3195
+ }
3196
+ }
3197
+ },
3165
3198
  {
3166
3199
  clearable: true,
3167
3200
  name: "browserCommand",
@@ -3334,6 +3367,21 @@ var browserAutomationTool = {
3334
3367
  tools: BROWSER_TOOLS,
3335
3368
  externalTools: BROWSER_EXTERNAL_TOOLS,
3336
3369
  executeTool: async (name, _input, _toolCallId, onLog) => {
3370
+ if (name === "setupBrowser") {
3371
+ try {
3372
+ const result2 = await sidecarRequest(
3373
+ "/setup-browser",
3374
+ {
3375
+ auth: _input.auth,
3376
+ path: _input.path
3377
+ },
3378
+ { timeout: 15e3 }
3379
+ );
3380
+ return JSON.stringify(result2);
3381
+ } catch (err) {
3382
+ return `Error setting up browser: ${err.message}`;
3383
+ }
3384
+ }
3337
3385
  if (name === "screenshotFullPage") {
3338
3386
  try {
3339
3387
  return await captureAndAnalyzeScreenshot({
@@ -3605,7 +3653,7 @@ var definition5 = {
3605
3653
  },
3606
3654
  instructions: {
3607
3655
  type: "string",
3608
- description: "If the screenshot you need requires interaction first (dismissing a modal, clicking a tab, filling out a form, navigating a flow), describe the steps to get there. A browser automation agent will follow these instructions before capturing the screenshot. You will always get back a full-height screenshot of the entire page. Do not attempt to scroll or capture specific areas. Only use instructions when you need to trigger stateful changes. Never describe what names or values to use when applying the isntructions - the browser automation agent must use its own values for it to work properly."
3656
+ description: "If the screenshot you need requires interaction first (dismissing a modal, clicking a tab, filling out a form, navigating a flow, getting through a login/auth checkpoint), describe the steps to get there. A browser automation agent will follow these instructions before capturing the screenshot - it can bypass auth and get right to where it needs to be if you tell it to authenticate as a test user and give it the path/screen to start its test at. You will always get back a full-height screenshot of the entire page. Do not attempt to scroll or capture specific areas. Only use instructions when you need to trigger stateful changes. Never describe what names or values to use when applying the isntructions - the browser automation agent must use its own values for it to work properly."
3609
3657
  }
3610
3658
  }
3611
3659
  }
package/dist/index.js CHANGED
@@ -2214,7 +2214,7 @@ var init_analyzeImage = __esm({
2214
2214
  "src/subagents/common/analyzeImage.ts"() {
2215
2215
  "use strict";
2216
2216
  init_runCli();
2217
- VISION_MODEL = "claude-4.5-sonnet";
2217
+ VISION_MODEL = "gemini-3-flash";
2218
2218
  VISION_MODEL_OVERRIDE = JSON.stringify({
2219
2219
  model: VISION_MODEL,
2220
2220
  config: { thinkingBudget: "off" }
@@ -2903,6 +2903,39 @@ var init_tools = __esm({
2903
2903
  "src/subagents/browserAutomation/tools.ts"() {
2904
2904
  "use strict";
2905
2905
  BROWSER_TOOLS = [
2906
+ {
2907
+ clearable: false,
2908
+ name: "setupBrowser",
2909
+ description: "Pre-authenticate the browser and optionally navigate to a starting page. Call this before interacting with authenticated content instead of manually logging in. Auth is optional \u2014 omit to just navigate without authenticating.",
2910
+ inputSchema: {
2911
+ type: "object",
2912
+ properties: {
2913
+ auth: {
2914
+ type: "object",
2915
+ description: "Authentication config. Upserts the user if they don't exist.",
2916
+ properties: {
2917
+ email: {
2918
+ type: "string",
2919
+ description: "User email address."
2920
+ },
2921
+ phone: {
2922
+ type: "string",
2923
+ description: "User phone number."
2924
+ },
2925
+ roles: {
2926
+ type: "array",
2927
+ items: { type: "string" },
2928
+ description: "Roles to set on the user."
2929
+ }
2930
+ }
2931
+ },
2932
+ path: {
2933
+ type: "string",
2934
+ description: 'Navigate to this path after setup (default "/").'
2935
+ }
2936
+ }
2937
+ }
2938
+ },
2906
2939
  {
2907
2940
  clearable: true,
2908
2941
  name: "browserCommand",
@@ -3138,6 +3171,21 @@ var init_browserAutomation = __esm({
3138
3171
  tools: BROWSER_TOOLS,
3139
3172
  externalTools: BROWSER_EXTERNAL_TOOLS,
3140
3173
  executeTool: async (name, _input, _toolCallId, onLog) => {
3174
+ if (name === "setupBrowser") {
3175
+ try {
3176
+ const result2 = await sidecarRequest(
3177
+ "/setup-browser",
3178
+ {
3179
+ auth: _input.auth,
3180
+ path: _input.path
3181
+ },
3182
+ { timeout: 15e3 }
3183
+ );
3184
+ return JSON.stringify(result2);
3185
+ } catch (err) {
3186
+ return `Error setting up browser: ${err.message}`;
3187
+ }
3188
+ }
3141
3189
  if (name === "screenshotFullPage") {
3142
3190
  try {
3143
3191
  return await captureAndAnalyzeScreenshot({
@@ -3494,7 +3542,7 @@ var init_screenshot3 = __esm({
3494
3542
  },
3495
3543
  instructions: {
3496
3544
  type: "string",
3497
- description: "If the screenshot you need requires interaction first (dismissing a modal, clicking a tab, filling out a form, navigating a flow), describe the steps to get there. A browser automation agent will follow these instructions before capturing the screenshot. You will always get back a full-height screenshot of the entire page. Do not attempt to scroll or capture specific areas. Only use instructions when you need to trigger stateful changes. Never describe what names or values to use when applying the isntructions - the browser automation agent must use its own values for it to work properly."
3545
+ description: "If the screenshot you need requires interaction first (dismissing a modal, clicking a tab, filling out a form, navigating a flow, getting through a login/auth checkpoint), describe the steps to get there. A browser automation agent will follow these instructions before capturing the screenshot - it can bypass auth and get right to where it needs to be if you tell it to authenticate as a test user and give it the path/screen to start its test at. You will always get back a full-height screenshot of the entire page. Do not attempt to scroll or capture specific areas. Only use instructions when you need to trigger stateful changes. Never describe what names or values to use when applying the isntructions - the browser automation agent must use its own values for it to work properly."
3498
3546
  }
3499
3547
  }
3500
3548
  }
@@ -86,11 +86,25 @@ interface AppUser {
86
86
 
87
87
  `auth.getCurrentUser()` returns `AppUser | null`. `null` means unauthenticated.
88
88
 
89
- ### State (sync)
89
+ ### State
90
90
 
91
91
  ```typescript
92
- auth.getCurrentUser() // AppUser | null
93
- auth.isAuthenticated() // boolean
92
+ auth.getCurrentUser() // AppUser | null
93
+ auth.currentUser // AppUser | null (sync getter, same as getCurrentUser())
94
+ auth.isAuthenticated() // boolean
95
+ auth.onAuthStateChanged(cb) // fires immediately with current user, then on every
96
+ // auth transition (verify, confirm, logout).
97
+ // Returns an unsubscribe function.
98
+ ```
99
+
100
+ Use `onAuthStateChanged` in React instead of reading `currentUser` once at render time:
101
+
102
+ ```typescript
103
+ function useAuth() {
104
+ const [user, setUser] = useState<AppUser | null>(null);
105
+ useEffect(() => auth.onAuthStateChanged(setUser), []);
106
+ return user;
107
+ }
94
108
  ```
95
109
 
96
110
  ### Email Code Flow
@@ -125,6 +139,19 @@ const user = await auth.confirmPhoneChange('+15559876543', '123456');
125
139
  await auth.logout(); // clears session
126
140
  ```
127
141
 
142
+ ### Error Codes
143
+
144
+ All auth methods throw on failure with a `code` property:
145
+
146
+ | Code | HTTP | Meaning |
147
+ |------|------|---------|
148
+ | `rate_limited` | 429 | Too many requests |
149
+ | `invalid_code` | 400 | Wrong verification code |
150
+ | `verification_expired` | 400 | Code has expired |
151
+ | `max_attempts_exceeded` | 400 | Too many failed attempts |
152
+ | `not_authenticated` | 401 | No active session |
153
+ | `invalid_session` | 401 | Session expired or invalid |
154
+
128
155
  ### Phone Helpers
129
156
 
130
157
  ```typescript
@@ -176,31 +203,56 @@ Returns an array of user IDs with the specified role.
176
203
  ## Login Page Example
177
204
 
178
205
  ```tsx
206
+ import { useState, useEffect } from 'react';
179
207
  import { auth } from '@mindstudio-ai/interface';
208
+ import { useLocation } from 'wouter';
209
+
210
+ function useAuth() {
211
+ const [user, setUser] = useState<AppUser | null>(null);
212
+ useEffect(() => auth.onAuthStateChanged(setUser), []);
213
+ return user;
214
+ }
180
215
 
181
216
  function LoginPage() {
217
+ const user = useAuth();
218
+ const [, navigate] = useLocation();
182
219
  const [email, setEmail] = useState('');
183
220
  const [code, setCode] = useState('');
184
221
  const [verificationId, setVerificationId] = useState('');
185
- const [codeSent, setCodeSent] = useState(false);
222
+ const [error, setError] = useState('');
223
+
224
+ // Redirect when authenticated (fires via onAuthStateChanged after verify)
225
+ useEffect(() => { if (user) navigate('/dashboard'); }, [user]);
186
226
 
187
227
  const handleSendCode = async () => {
188
- const { verificationId } = await auth.sendEmailCode(email);
189
- setVerificationId(verificationId);
190
- setCodeSent(true);
228
+ try {
229
+ const { verificationId } = await auth.sendEmailCode(email);
230
+ setVerificationId(verificationId);
231
+ setError('');
232
+ } catch (err: any) {
233
+ setError(err.code === 'rate_limited' ? 'Too many attempts. Try again later.' : err.message);
234
+ }
191
235
  };
192
236
 
193
237
  const handleVerify = async () => {
194
- await auth.verifyEmailCode(verificationId, code);
195
- window.location.href = '/dashboard';
238
+ try {
239
+ await auth.verifyEmailCode(verificationId, code);
240
+ // onAuthStateChanged fires, useAuth updates, redirect happens
241
+ } catch (err: any) {
242
+ if (err.code === 'invalid_code') setError('Wrong code. Try again.');
243
+ else if (err.code === 'verification_expired') setError('Code expired. Request a new one.');
244
+ else if (err.code === 'max_attempts_exceeded') setError('Too many attempts. Request a new code.');
245
+ else setError(err.message);
246
+ }
196
247
  };
197
248
 
198
- if (!codeSent) {
249
+ if (!verificationId) {
199
250
  return (
200
251
  <div>
201
252
  <h1>Sign in</h1>
202
253
  <input placeholder="Email" value={email} onChange={e => setEmail(e.target.value)} />
203
254
  <button onClick={handleSendCode}>Send code</button>
255
+ {error && <p>{error}</p>}
204
256
  </div>
205
257
  );
206
258
  }
@@ -210,6 +262,8 @@ function LoginPage() {
210
262
  <p>Enter the code we sent to {email}</p>
211
263
  <input placeholder="123456" value={code} onChange={e => setCode(e.target.value)} />
212
264
  <button onClick={handleVerify}>Verify</button>
265
+ <button onClick={() => setVerificationId('')}>Resend</button>
266
+ {error && <p>{error}</p>}
213
267
  </div>
214
268
  );
215
269
  }
@@ -251,3 +305,23 @@ Roles are declared in the manifest, stored as an array column on the user table,
251
305
  ## Apps Without Auth
252
306
 
253
307
  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.
308
+
309
+ ## Designing Auth in Web Interfaces
310
+ The most imporant user experience consideration with auth is that authentication moments must feel natural and intuitive - they should not feel jarring or surprising. Take care to integrate them into the entire experience when building.
311
+
312
+ For the overwhelming majority of apps, a user should never land on auth at the root of an app when opening it for the first time (except in cases where the app is, e.g., an internal tool or some other protected experience - and even then it should feel more like a welcome/splash screen than an error state). Users should be able to explore public resources, or at least encounter some kind of landing/introduction moment, before they get hit with a signup/login screen. Make auth feel like a natural moment in the user's journey.
313
+
314
+ Login and signup screens set the tone for the user's entire experience with the app and are important to get right - they should feel like exciting entry points into the next level of the user journy. A janky login form with misaligned inputs and no feedback dminishes excitement and undermines trust before the user even gets in.
315
+
316
+ Consult the `visualDesignExpert` to help you work through authentication at a high level, including when and where to show auth, and the design of specific screens.
317
+
318
+ ### Rules for Building Auth Screens
319
+ **Auth modes:** Think about which mode(s) makes the most sense for the type of app you are building. Consumer apps likely to be used on mobile should probably tend toward SMS auth as the default - business apps used on desktop make more sense to use email verification - or allow both, there's no harm in giving the user choice!
320
+
321
+ **Verification code input:** The 6-digit code entry is the critical moment. Prefer to design it as individual digit boxes (not a single text input), with auto-advance between digits, a beautiful animation and auto-submit on paste, and clear visual feedback. The boxes should be large enough to tap easily on mobile. Show a subtle animation on successful verification. Error states should be inline and immediate, not a separate alert. Make sure there is no layout shift when loading in the success/error states - loading spinners must never pop in below the input and shift the content, for example.
322
+
323
+ **The send/resend flow:** After the user enters their email or phone and taps "Send code," show clear confirmation that the code was sent ("Check your email" with the address displayed). Include a resend option with a cooldown timer (e.g., "Resend in 30s"). The transition from "enter email/phone" to "enter code" should feel smooth, not like a page reload. Always make sure the user can cancel and exit the flow (e.g., they had a typo in their email, or remembered they used a different email to sign up).
324
+
325
+ **The overall login page:** This is a branding moment. Use the app's full visual identity — colors, typography, any logos, hero imagery, or illustration. A centered card on a branded background is a classic pattern. Don't make it look like a generic SaaS login template. The login page must feel like it belongs to this specific app. Consult the `visualDesignExpert` for guidance on how to really make this shine.
326
+
327
+ **Post-login transition:** After successful verification, the transition into the app should feel seamless and instant. Avoid a blank loading screen — if data needs to load, show the app shell with skeleton states. Always make sure the user has a way of logging out.
@@ -47,6 +47,7 @@ Every interface must work on both desktop and mobile. Think about how the app wi
47
47
  - On mobile, stack gracefully. Prioritize content and actions.
48
48
  - Test at both extremes. A layout that only looks good at one breakpoint is not done.
49
49
  - When the app is primarily mobile (e.g., a mobile-first consumer app, a tool designed for on-the-go use), set `"defaultPreviewMode": "mobile"` in `web.json` so the editor previews in a mobile viewport by default.
50
+ - Even for mobile-first apps, make sure to set desktop or larger device breakpoints - nothing looks jankier than opening a mobile-designed site in a desktop browser and seeing a full width bottom tab bar with nav icons stretching 1000px wide. Don't make sloppy, amateur mistakes or omissions like this - the user will notice them and be disappointed.
50
51
 
51
52
  ## Images
52
53
  The `designExpert` can create and source amazing, high quality images, graphics, illustrations, and logos to use in the interface - both with and without transparency. This is a huge level for upgrading the premium look, feel, and quality of the app. Use image logos directly instead of plain text wordmarks; use images for empty states, onboarding screens, full-screen loading, and more.
@@ -88,25 +89,6 @@ The UI should feel instant. Never make the user wait for a server round-trip to
88
89
 
89
90
  Handle errors gracefully. You don't need to design for every error case, but if remote API requests fail, make sure to show them nicely in a toast or some other appropriate view with a human-friendly label - don't just drop "Error 500 XYZ" inline in a form.
90
91
 
91
- ## Auth
92
- Login and signup screens set the tone for the user's entire experience with the app and are important to get right - they should feel like exciting entry points into the next level of the user journy. A janky login form with misaligned inputs and no feedback dminishes excitement and undermines trust before the user even gets in.
93
-
94
- Authentication moments must feel natural and intuitive - they should not feel jarring or surprising. Take care to integrate them into the entire experience when building. MindStudio apps support SMS code verification, email verification, or both, depending on how the app is configured.
95
-
96
- ### Rules for building auth screens
97
-
98
- Consult the `visualDesignExpert` to help you work through authentication at a high level. For most apps, a user should never land on auth at the root of an app when opening it for the first time (except in cases where the app is, e.g., an internal tool or some other protected experience). Users should be able to explore public resources, or at least encounter some kind of landing/introduction moment, before they get hit with a signup/login screen. Make auth feel like a natural moment in the user's journey.
99
-
100
- **Auth modes:** Think about which mode(s) makes the most sense for the type of app you are building. Consumer apps likely to be used on mobile should probably tend toward SMS auth as the default - business apps used on desktop make more sense to use email verification - or allow both, there's no harm in giving the user choice!
101
-
102
- **Verification code input:** The 6-digit code entry is the critical moment. Prefer to design it as individual digit boxes (not a single text input), with auto-advance between digits, a beautiful animation and auto-submit on paste, and clear visual feedback. The boxes should be large enough to tap easily on mobile. Show a subtle animation on successful verification. Error states should be inline and immediate, not a separate alert. Make sure there is no layout shift when loading in the success/error states.
103
-
104
- **The send/resend flow:** After the user enters their email or phone and taps "Send code," show clear confirmation that the code was sent ("Check your email" with the address displayed). Include a resend option with a cooldown timer (e.g., "Resend in 30s"). The transition from "enter email/phone" to "enter code" should feel smooth, not like a page reload. Always make sure the user can cancel and exit the flow (e.g., they had a typo in their email, or remembered they used a different email to sign up).
105
-
106
- **The overall login page:** This is a branding moment. Use the app's full visual identity — colors, typography, any logos, hero imagery, or illustration. A centered card on a branded background is a classic pattern. Don't make it look like a generic SaaS login template. The login page must feel like it belongs to this specific app. Consult the `visualDesignExpert` for additional guidance.
107
-
108
- **Post-login transition:** After successful verification, the transition into the app should feel seamless. Avoid a blank loading screen — if data needs to load, show the app shell with skeleton states. Always make sure the user has a way of logging out.
109
-
110
92
  ## FTUE
111
93
 
112
94
  All interactive apps must be intuitive and easy to use. Form elements must be well-labelled. Complex interfaces should have descriptions or tooltips when helpful. Complex apps benefit from a beautiful simple onboarding modal on first use or a simple click tour. Mobile apps need a beautiful welcome screen sequence that orients the user to the app. Ask the `visualDesignExpert` for advice here.
@@ -75,8 +75,10 @@ const url = await platform.uploadFile(file, {
75
75
  controller.abort(); // cancels the upload
76
76
 
77
77
  // Auth (for apps with auth enabled in manifest)
78
- auth.getCurrentUser() // AppUser { id, email, phone, roles, createdAt } | null
79
- auth.isAuthenticated() // boolean
78
+ auth.getCurrentUser() // AppUser { id, email, phone, roles, createdAt } | null
79
+ auth.currentUser // same as getCurrentUser() (sync getter)
80
+ auth.isAuthenticated() // boolean
81
+ auth.onAuthStateChanged(cb) // fires immediately + on transitions; returns unsubscribe
80
82
  auth.sendEmailCode(email) // → { verificationId }
81
83
  auth.verifyEmailCode(verId, code) // → AppUser (sets session)
82
84
  auth.sendSmsCode(phone) // → { verificationId }
@@ -12,7 +12,7 @@ After intake, write the spec immediately. Do not ask "ready for me to start?" or
12
12
  The scaffold starts with these spec files that cover the full picture of the app:
13
13
 
14
14
  - **`src/app.md`** — the core application: what it does, how data flows, who's involved, the rules
15
- - **`src/interfaces/web.md`** — the web interface: layout, screens, interactions, user experience
15
+ - **`src/interfaces/web.md`** — the web interface: layout, screens, interactions, anduser experience, in detail
16
16
  - **`src/interfaces/@brand/visual.md`** — aesthetic direction: the overall look, surfaces, spacing, interaction feel
17
17
  - **`src/interfaces/@brand/colors.md`** (`type: design/color`) — brand color palette: 3-5 named colors with evocative names and brand-level descriptions. The design system is derived from these.
18
18
  - **`src/interfaces/@brand/typography.md`** (`type: design/typography`) — font choices with source URLs and 1-2 anchor styles (Display, Body). Additional styles are derived from these anchors.
@@ -40,7 +40,7 @@ Always consult the code sanity check before writing code in initialCodegen with
40
40
 
41
41
  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.
42
42
 
43
- The QA agent can see the screen. Describe what to test, not how — it will figure out what to click, what to check, and what values to use. It always starts its tests logged out/unauthenticated on "/" root. After every test session, the browser is reset to / and any authentication used or created by the tester is cleared and reset.
43
+ The QA agent can see the screen. Describe what to test, not how — it will figure out what to click, what to check, and what values to use. By default, it always starts its tests logged out/unauthenticated on "/" root, but if you want to test a deeper piece of the app it can bypass auth and automatically authenticate itself as any user/role - just tell it to authenticate as the test user and navigate to X to start the test. After every test session, the browser is reset to / and any authentication used or created by the tester is cleared and reset.
44
44
 
45
45
  Never tell QA what names to use when testing or what values to input - it will use its own judgment.
46
46
 
@@ -8,11 +8,13 @@ You are a browser smoke test agent. You verify that features work end to end by
8
8
  The user is watching the automation happen on their screen in real-time. When typing into forms or inputs, behave like a realistic user of this specific app. Use the app context (if provided) to understand the audience and tone. Type the way that audience would actually type — not formal, not robotic. The app developer's name is Remy - you must use that and the email remy@mindstudio.ai as the basis for any testing that requires a persona.
9
9
 
10
10
  ### Auth Testing
11
- When the app has a login or signup flow, you must use `remy@mindstudio.ai` for email and `+15551234567` for phone number. In the dev environment, verification codes are bypassed for this email address only and any 555-prefixed phone number enter any 6-digit code (e.g., `123456`) and it will be accepted. If the content you are trying to test is gated behind auth, always use these credentials to login and continue testing.
11
+ When the content you need to test is behind authentication, use the `setupBrowser` tool to automatically pre-authenticate instead of manually navigating login flows. This mints a session cookie, reloads the page with the authenticated state, and optionally navigates to a starting path. Use `remy@mindstudio.ai` as the email. If the test requires a specific role, pass it in the `roles` array.
12
+
13
+ If you need to test the login/signup flow itself (e.g., verifying the UI, error states, or the verification code input), navigate it manually: use `remy@mindstudio.ai` for email and `+15551234567` for phone. In the dev environment, verification codes are bypassed for this email and any 555-prefixed phone number — enter any 6-digit code (e.g., `123456`).
12
14
 
13
15
  ## Browser Commands
14
16
 
15
- Your session always starts on the app root / in a logged out/unauthenticated state.
17
+ Your session always starts on the app root / in a logged out/unauthenticated state. Use `setupBrowser` to authenticate before testing protected pages.
16
18
 
17
19
  ### Snapshot format
18
20
 
@@ -18,6 +18,9 @@ These are things we already know about and have decided to accept:
18
18
 
19
19
  - Limited browser support for `oklch` gradients using `in <colorspace>` syntax — we accept the compatibility tradeoff for better color quality
20
20
  - Limited browser support for CSS scroll-driven animations (`animation-timeline: scroll()` / `view()`) - we accept this tradeoff
21
+ - Platform SDKs (these are the core of every MindStudio app):
22
+ - `@mindstudio-ai/interface` — frontend SDK. `createClient<T>()` gives typed RPC to backend methods (no raw fetch). `auth` handles auth state (`auth.currentUser`, `auth.onAuthStateChanged(cb)`, verification flows, logout). `platform.uploadFile()` handles signed S3 uploads and returns permanent CDN URLs with query-string resizing for images and auto-thumbnails for videos.
23
+ - `@mindstudio-ai/agent` — backend SDK. `db.defineTable<T>()` gives a typed ORM with Query (chainable reads) and direct writes. `auth` gives `auth.userId`, `auth.roles`, `auth.requireRole()`, `auth.hasRole()`. Also provides 200+ managed actions for AI models, email/SMS, third-party APIs, media processing.
21
24
  - Libraries we know are actively maintained, don't bother checking:
22
25
  - swr
23
26
  - motion (formerly framer-motion — import from `motion/react`, not `framer-motion`)
@@ -28,7 +31,7 @@ These are things we already know about and have decided to accept:
28
31
  - react-textarea-autosize
29
32
  - Preferences:
30
33
  - use [wouter](https://github.com/molefrog/wouter) for React routing instead of reaching for react-router
31
- - uploading user files should mostly always happen via @mindstudio-ai/interface's platform.uploadFile() - it does the whole signed S3 upload dance and returns a permanent CDN url, including query-string-resizable images, videos + auto-thumbnails, etc.
34
+ - uploading user files should always happen via `platform.uploadFile()` from `@mindstudio-ai/interface` not custom S3 code, not FormData to a method endpoint
32
35
  - for static prerendering of Vite + React sites, roll your own with a post-build `renderToString` script — do not use `vite-prerender-plugin` (it bundles the prerender script as a client chunk, adding ~800KB to the user-facing bundle with no way to prevent it)
33
36
 
34
37
  ### Common pitfalls (always flag these)
@@ -53,7 +56,9 @@ When a plan includes multiple screens/API calls, always note this item for the d
53
56
 
54
57
  - **Image preloading for detail views.** If the plan has a grid/list of thumbnails that link to detail views with full-size images, flag it if there's no preloading strategy. The fix: preload full-size images in the background (`new Image().src = url`) so they're in the browser cache by the time the user taps. This makes transitions feel instant.
55
58
 
56
- - **Layout shift with dynamic data or AI generatd text** If the plan includes dynamically-sized data (e.g., a wizard form with questions of differing lengths) or AI generated text (where text stream length is unpredictable), make sure to flag concerns about layout stability. Everything must either be a fixed size or smoothly animate between sizes. Text can never be clipped by a container or cause layout to jump around or grow in snappy/janky ways. Make sure to remind the developer that this is important to pay attention to.
59
+ - **Auth state read once instead of subscribed.** If the plan reads `auth.currentUser` or `auth.getCurrentUser()` in a `useState` initializer, at component top-level, or in a one-time check, the UI won't update after login/logout. The correct pattern is `auth.onAuthStateChanged(cb)` which fires immediately and on every auth transition. Flag if you see auth state read without a subscription.
60
+
61
+ - **Layout shift with dynamic data or AI generated text** If the plan includes dynamically-sized data (e.g., a wizard form with questions of differing lengths) or AI generated text (where text stream length is unpredictable), make sure to flag concerns about layout stability. Everything must either be a fixed size or smoothly animate between sizes. Text can never be clipped by a container or cause layout to jump around or grow in snappy/janky ways. Make sure to remind the developer that this is important to pay attention to.
57
62
 
58
63
  ## When to stay quiet
59
64
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindstudio-ai/remy",
3
- "version": "0.1.115",
3
+ "version": "0.1.117",
4
4
  "description": "MindStudio coding agent",
5
5
  "repository": {
6
6
  "type": "git",