Skip to content

Commit 59dde92

Browse files
NikAiyerMastra Code (anthropic/claude-opus-4-7)
andauthored
feat(agent-builder): fast-followups — smoke-test skill alignment + product fixes (#17246)
## Summary Agent Builder fast-followups. Two threads: 1. **Builder smoke-test skill (`.claude/skills/builder-smoke-test`)** — bring docs, scaffolding, and scripts into sync with shipped Agent Builder behavior so the next person running the skill can trust it. 2. **Server fix (`PLTFRM-1012`)** — make the favorites response shape consistent across every read/write path on stored agents and skills. Both threads fell out of a from-scratch run of the smoke test against `origin/main`. ## Skill alignment (no runtime impact) `3b5eb7ec` — 16 corrections from running the full smoke test: - Scaffold template imports `createBuilderAgent` (factory). The old singleton `builderAgent` export no longer exists. - `stars` → `favorites` rename swept across SKILL.md, references, endpoints (`/star` → `/favorite`), response fields (`starCount`/`isStarred` → `favoriteCount`/`isFavorited`), and feature flags. - Picker docs corrected to use `.picker.visibleTools` etc. (were top-level). - Agent/skill shape: `model: { provider, name }`; skill attach is a record map `{ id: {} }`, never an array; oversized avatar returns `413` (not `400`); `favoriteCount` populated as `0` on create. - Model policy jq path: `.configuration.agent.models`. - `scaffold.sh` auto-writes `SMOKE_TEST_COOKIE_LEAK=1` for auth-on runs. - `wait-for-server.sh` logs a tail-of-log hint when the dev server fails to boot. - Minor: registries always present with `enabled: false` (not omitted), partial PATCH works, `/auth/me` returns `200 null` under `--auth off`. `53b1504c` — agent view header only contains `Switch to Edit mode`. The `Add to library` toggle lives on the **edit** page right panel, not the view header. `0abe10cf` — `/favorite` returns `401` or `404` under `--auth off` depending on build (saw both across runs); skill now accepts either. `stored/skills` create requires `description` alongside `name`/`instructions`. ## Server fix — PLTFRM-1012 `6817aaca` — `fix(server): annotate isFavorited on stored agent/skill POST + PATCH + publish`. Before this commit, POST, PATCH, and (for skills) publish returned the resolved storage row without running favorites enrichment, so `isFavorited` was missing from the response, and under `--auth off` `favoriteCount: 0` leaked through where GET would have stripped it. ### Response matrix For a freshly-created, unfavorited entity on `/api/stored/agents/:id` or `/api/stored/skills/:id`: | Path | Auth-off (before → after) | Auth-on (before → after) | | --- | --- | --- | | POST | `favoriteCount: 0`, no `isFavorited` → **neither field** | `favoriteCount: 0`, no `isFavorited` → **`favoriteCount: 0`, `isFavorited: false`** | | PATCH | `favoriteCount: 0`, no `isFavorited` → **neither field** | `favoriteCount: 0`, no `isFavorited` → **`favoriteCount: 0`, `isFavorited: false`** | | Publish (skill) | same as PATCH | same as PATCH | | GET | neither field (unchanged) | `favoriteCount: 0`, `isFavorited: false` (unchanged) | | LIST | neither field (unchanged) | `favoriteCount: 0`, `isFavorited: false` (unchanged) | | PUT/DELETE `/favorite` | 401/404 (unchanged) | `{ favorited, favoriteCount }` (unchanged) | After the fix, every read/write path on a single entity shares one shape, so client code can read `response.isFavorited` directly without an extra GET round-trip. ### Implementation Adds `enrichOrStripFavorites(mastra, requestContext, entityType, record)` to `favorites-enrichment.ts` — same shape as the existing inline GET logic (run `prepareFavoritesEnrichment`; on hit, spread the record and add `isFavorited`; on miss, `stripFavoriteFields`). Applied at 6 call sites: - `stored-agents.ts`: GET (refactored to use helper), POST return, PATCH return. - `stored-skills.ts`: GET (refactored to use helper), POST return, PATCH return, publish return. LIST handlers are unchanged — they already had the correct strip-when-feature-off branch. `starCount` / `isStarred` do not appear in any response shape. They never did; the original ticket's "deprecated alias leakage" framing was withdrawn during investigation. ## Verification - `pnpm --filter @mastra/server test stored-agents stored-skills favorites` → 131/131 pass. - `pnpm build:server` clean. - Live re-probe against `localhost:4111` on both auth modes, agent and skill, confirms the matrix above. - Full builder smoke test (32 tasks) ran twice against this branch — auth-off (14 sections) + auth-on (15 sections) both green; reports at `/tmp/builder-smoke-report.md` and `/tmp/builder-smoke-report-run2.md`. ## Linear - [`PLTFRM-1012`](https://linear.app/kepler-crm/issue/PLTFRM-1012) — fixed here. - [`PLTFRM-1011`](https://linear.app/kepler-crm/issue/PLTFRM-1011) — investigated and closed as not-a-bug during smoke-test run 2; the auth-off favorite button is a properly disabled `<button disabled>` with `cursor-not-allowed` and a sign-in aria-label. Skill docs corrected accordingly. ## Test plan 1. Pull the branch. 2. `pnpm --filter @mastra/server test stored-agents stored-skills favorites`. 3. Optional: run `.claude/skills/builder-smoke-test` end-to-end (`scripts/scaffold.sh --auth off` and `--auth on --workos-...`) and confirm all sections pass. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This PR updates the Agent Builder smoke tests and scaffolding to match the shipped product, and fixes a server bug so "favorite" fields in API responses are consistent whether you read or write an entity. ## Overview Two concurrent threads: 1. Align the builder smoke-test skill docs, scripts, and templates with shipped Agent Builder behavior (renames, docs, scaffold and script fixes, UI/docs expectations). 2. Server fix (PLTFRM-1012): centralize favorites enrichment so GET/POST/PATCH/publish single-entity responses present a consistent favorites shape. ## Key Changes ### Builder smoke-test alignment - Renamed "stars" → "favorites" across docs, references, endpoints, feature flags, and tests; added new favorites.md reference. - Documentation updates: picker allowlist path (.picker.visibleTools), model-policy jq path (.configuration.agent.models), registry/visibility/workspace/infrastructure/permissions clarifications, UI expectations (Agent view header, Add to library placement). - Skills/agents behavior documented: create now requires description + name/instructions; partial PATCH supported; publish authoritative from SKILL.md frontmatter; avatar uploads return 413 for oversized images; favoriteCount initialized to 0 on create. - Scaffolding/scripts: template uses createBuilderAgent() factory; scaffold.sh now writes SMOKE_TEST_COOKIE_LEAK for auth-on runs; wait-for-server.sh adds a log-tail hint for stale template imports. - Feature flags: favorites enabled flags added; favorites endpoints return 404 when feature disabled. ### Server — favorites consistency (PLTFRM-1012) - New helper: enrichOrStripFavorites<T>(mastra, requestContext, entityType, record) in packages/server/src/server/handlers/favorites-enrichment.ts to centralize either annotating records with isFavorited or stripping favorite fields when enrichment is unavailable. - Applied to stored-agents and stored-skills handlers: GET (single), POST, PATCH, and skill PUBLISH responses now consistently use enrichOrStripFavorites. - List routes now strip favorite fields when enrichment is unavailable instead of returning raw records. - Responses from write endpoints (POST/PATCH/publish) now match GET shape: include isFavorited when applicable or omit favorite fields per feature/auth state. ## Verification - Server tests for stored-agents, stored-skills, and favorites pass (131/131). - pnpm build:server completes cleanly. - Builder smoke test ran successfully (twice) in both auth modes; live probes confirm expected response matrix. - PLTFRM-1012 resolved; PLTFRM-1011 investigated and closed. ## Notable files touched - .claude/skills/builder-smoke-test/** (docs, templates, scripts) - packages/server/src/server/handlers/favorites-enrichment.ts - packages/server/src/server/handlers/stored-agents.ts - packages/server/src/server/handlers/stored-skills.ts - .changeset for `@mastra/server` <!-- review_stack_entry_start --> [![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/17246?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Mastra Code (anthropic/claude-opus-4-7) <noreply@mastra.ai>
1 parent 7ed8985 commit 59dde92

21 files changed

Lines changed: 293 additions & 238 deletions

File tree

.changeset/silver-zebras-rule.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@mastra/server': patch
3+
---
4+
5+
Stored agent and skill POST, PATCH, and skill publish responses now include `isFavorited`, matching GET behavior. Clients can read favorite status from write responses without an extra GET request.
6+
7+
Under auth-off, write responses also omit `favoriteCount` to match GET, so the response shape is consistent across all single-entity endpoints.

.claude/skills/builder-smoke-test/SKILL.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ This skill is for **branch QA** — it complements the release-time `mastra-smok
2626
| 7 | **Registry** | `references/registry.md` | `--test registry` or full |
2727
| 8 | **Agents** | `references/agents.md` | `--test agents` or full |
2828
| 9 | **Picker Allowlists** | `references/picker-allowlist.md` | `--test pickers` or full |
29-
| 10 | **Stars** | `references/stars.md` | `--test stars` or full |
29+
| 10 | **Favorites** | `references/favorites.md` | `--test favorites` or full (formerly `stars`) |
3030
| 11 | **Permissions / RBAC** | `references/permissions.md` | `--test permissions` or full |
3131
| 12 | **Infrastructure** | `references/infrastructure.md` | `--test infrastructure` or full |
3232
| 13 | **Channels** | `references/channels.md` | `--test channels` or full |
@@ -57,14 +57,14 @@ Example: `--test skills,registry,agents` → Setup + Skills + Registry + Agents.
5757

5858
`--scope` runs a curated group of related sections. Setup is always implied.
5959

60-
| Scope | Includes |
61-
| -------- | --------------------------------------------------------- |
62-
| `rbac` | permissions, auth |
63-
| `skills` | skills, registry, defaults |
64-
| `agents` | agents, pickers, defaults, model-policy |
65-
| `infra` | infrastructure, channels, reconciliation |
66-
| `ui` | ui |
67-
| `quick` | workspace, skills, agents, stars, ui (skips long-running) |
60+
| Scope | Includes |
61+
| -------- | ------------------------------------------------------------- |
62+
| `rbac` | permissions, auth |
63+
| `skills` | skills, registry, defaults |
64+
| `agents` | agents, pickers, defaults, model-policy |
65+
| `infra` | infrastructure, channels, reconciliation |
66+
| `ui` | ui |
67+
| `quick` | workspace, skills, agents, favorites, ui (skips long-running) |
6868

6969
`--scope` and `--test` can be combined; the union is run.
7070

@@ -76,7 +76,7 @@ Example: `--test skills,registry,agents` → Setup + Skills + Registry + Agents.
7676

7777
# Specific sections
7878
/builder-smoke-test --test workspace,skills
79-
/builder-smoke-test --test agents,stars
79+
/builder-smoke-test --test agents,favorites
8080
/builder-smoke-test --test reconciliation
8181
/builder-smoke-test --test ui
8282

@@ -142,7 +142,7 @@ accordingly:
142142
- **Required (every run):** `setup.md`. Any failure here blocks the rest
143143
of the run.
144144
- **Standard (default tiers for `full`, `quick`, scope shortcuts):**
145-
`workspace.md`, `skills.md`, `agents.md`, `stars.md`, `ui.md` (core),
145+
`workspace.md`, `skills.md`, `agents.md`, `favorites.md`, `ui.md` (core),
146146
`auth.md` when `--auth on`.
147147
- **Extended (only when explicitly selected via `--test`/`--scope` or
148148
the matching code surface changed):** `reconciliation.md`,
@@ -389,11 +389,11 @@ run the per-section commands in `references/<section>.md`.
389389
| Registry install | `POST /editor/builder/registries/:registryId/install` |
390390
| Workspace CRUD | `GET/POST/PATCH/DELETE /stored/workspaces[/:id]` |
391391
| Agent CRUD | `GET/POST/PATCH/DELETE /stored/agents[/:id]` |
392-
| Agent star | `PUT / DELETE /stored/agents/:id/star` |
392+
| Agent favorite | `PUT / DELETE /stored/agents/:id/favorite` |
393393
| Agent avatar | `PATCH /stored/agents/:id` with `metadata.avatarUrl` (owner-only) |
394394
| Skill CRUD | `GET/POST/PATCH/DELETE /stored/skills[/:id]` |
395395
| Skill publish | `POST /stored/skills/:id/publish` |
396-
| Skill star | `PUT / DELETE /stored/skills/:id/star` |
396+
| Skill favorite | `PUT / DELETE /stored/skills/:id/favorite` |
397397
| Auth me | `GET /api/auth/me` (returns logged-in user + roles + permissions) |
398398
| Auth refresh | `POST /auth/refresh` |
399399

@@ -507,7 +507,7 @@ Some flows are documented in `references/` but are not driven by the smoke-test
507507
- `references/registry.md` — skills.sh browse/install, library Copy flow, origin badges, gating
508508
- `references/agents.md` — stored agent CRUD, skill attachment, model swap, delete-from-edit, avatar upload
509509
- `references/picker-allowlist.md` — tools/agents/workflows pickers respect allowlists
510-
- `references/stars.md`star/unstar agents and skills, idempotency
510+
- `references/favorites.md`favorite/unfavorite agents and skills, idempotency (formerly `stars.md`)
511511
- `references/permissions.md` — viewer/member/admin/owner gating, role expectation matrix, UI impersonation, auth-off bypass
512512
- `references/infrastructure.md``/editor/builder/infrastructure` payload + UI
513513
- `references/channels.md` — Slack provider visibility, connectChannel tool

.claude/skills/builder-smoke-test/assets/template/src/mastra/index.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { Context } from 'hono';
22
import { Mastra } from '@mastra/core/mastra';
33
import { Workspace, LocalFilesystem } from '@mastra/core/workspace';
44
import { MastraEditor } from '@mastra/editor';
5-
import { builderAgent } from '@mastra/editor/ee';
5+
import { createBuilderAgent } from '@mastra/editor/ee';
66
import { LibSQLStore } from '@mastra/libsql';
77
import { Observability, DefaultExporter, SensitiveDataFilter } from '@mastra/observability';
88
import { SlackProvider } from '@mastra/slack';
@@ -28,7 +28,7 @@ export const mastra = new Mastra({
2828
storage,
2929
workspace: builderWorkspace,
3030
agents: {
31-
builderAgent,
31+
builderAgent: createBuilderAgent(),
3232
weatherAgent,
3333
},
3434
tools: {
@@ -96,14 +96,14 @@ export const mastra = new Mastra({
9696
tools: true,
9797
agents: true,
9898
workflows: true,
99-
stars: true,
99+
favorites: true,
100100
skills: true,
101101
model: true,
102102
browser: true,
103103
avatarUpload: true,
104104
},
105105
skill: {
106-
stars: true,
106+
favorites: true,
107107
},
108108
},
109109
configuration: {

.claude/skills/builder-smoke-test/references/agents.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ Notes (don't assert under `--auth off`):
4444

4545
- `visibility` will be `"public"` regardless of request (see auth-on path).
4646
- `authorId` will be `null` (no caller).
47-
- `starCount` will be `0` (no caller-scoped star rows).
47+
- `favoriteCount` will be `0` and `isFavorited` will be `false` (no caller-scoped favorite rows).
4848

4949
### 2. Get the agent
5050

@@ -179,7 +179,7 @@ curl -s -X PATCH "$BASE/stored/agents/$AGENT_ID" \
179179
- [ ] Owner: 200, response `metadata.avatarUrl` is the data URL you sent (or a server-rewritten URL)
180180
- [ ] Non-owner authenticated user: 403 (ownership check inside `assertWriteAccess`)
181181
- [ ] Auth off: behaves as owner (no caller → bypass)
182-
- [ ] Oversized blob (>512 KB) is rejected with a structured 400 from `validateMetadataAvatarUrl`
182+
- [ ] Oversized blob (>512 KB) is rejected with **`413 Payload Too Large`** from `validateMetadataAvatarUrl` (not `400`)
183183

184184
## Builder defaults at create
185185

.claude/skills/builder-smoke-test/references/auth.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,18 +49,19 @@ themselves or dictate values for you to write.
4949

5050
### 0. Auth ON — extract the session cookie for curl
5151

52-
The WorkOS session cookie is `httpOnly`, so `curl` cannot mint it via `/api/auth/login` and `document.cookie` cannot read it in the browser. **Do this before any other auth-on step that uses `curl`.** Don't fall back to "UI only" — every snippet below uses `-H "Cookie: $COOKIE"` and this is how you get the value.
52+
The WorkOS session cookie is `httpOnly`, so `curl` cannot mint it via `/sign-in` and `document.cookie` cannot read it in the browser. **Do this before any other auth-on step that uses `curl`.** Don't fall back to "UI only" — every snippet below uses `-H "Cookie: $COOKIE"` and this is how you get the value.
5353

54-
The scaffold ships a debug route gated by `SMOKE_TEST_COOKIE_LEAK=1` that echoes back the request's Cookie header.
54+
The scaffold ships a debug route gated by `SMOKE_TEST_COOKIE_LEAK=1` that echoes back the request's Cookie header. `scaffold.sh` writes this line into `.env` automatically whenever the `--workos-*` flags trigger auth-on mode, so you should not normally need to add it by hand.
5555

5656
> **Ordering gotcha.** The `apiRoutes` array is built **once** when `mastra dev` boots, from `process.env.SMOKE_TEST_COOKIE_LEAK`. If the flag isn't set in `.env` before that boot, `GET /smoke-test/cookie` returns `404` even though it appears in this doc. If you see a 404 here, the fix is always "stop `mastra dev`, confirm the line is in `$PROJECT_DIR/.env`, restart" — never try to enable it at runtime via curl or browser. Verify with `grep SMOKE_TEST_COOKIE_LEAK "$PROJECT_DIR/.env"` before restarting.
5757
5858
Recipe:
5959

6060
```bash
61-
# 1. Add the leak flag to $PROJECT_DIR/.env (only for the smoke test)
62-
echo 'SMOKE_TEST_COOKIE_LEAK=1' >> "$PROJECT_DIR/.env"
63-
# 2. Restart `mastra dev` so it picks up the env change.
61+
# 1. Confirm the leak flag is in $PROJECT_DIR/.env (scaffold.sh writes it for auth-on).
62+
grep -q '^SMOKE_TEST_COOKIE_LEAK=1' "$PROJECT_DIR/.env" \
63+
|| echo 'SMOKE_TEST_COOKIE_LEAK=1' >> "$PROJECT_DIR/.env"
64+
# 2. Restart `mastra dev` so it picks up the env change (only needed if step 1 wrote anything).
6465
# 3. In the browser, sign in via WorkOS (navigate to $BASE/agent-builder).
6566
# 4. In the same browser session, navigate to $BASE/smoke-test/cookie
6667
# and copy the response body (it's the raw Cookie header).

.claude/skills/builder-smoke-test/references/defaults.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ When the Agent Builder is enabled, `applyBuilderDefaults()` fills in workspace,
44

55
Reference: `packages/core/src/agent-builder/ee/apply-builder-defaults.ts` and the scaffolded project's `src/mastra/index.ts` (the `builder.configuration.agent` block).
66

7+
> **Visibility under `--auth off`.** Some examples below pass `"visibility": "private"`. With `--auth off` the server has no caller to attribute ownership to and forces `visibility: "public"` (and `authorId: null`) regardless of what you send. That is expected; don't fail the step on it. Under `--auth on`, `"private"` is preserved.
8+
79
## Source-of-truth: builder config in the scaffolded project
810

911
```ts
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# Favorites
2+
3+
Test favorite/unfavorite functionality for stored agents and skills.
4+
5+
Favorite endpoints are documented in `packages/server/src/server/schemas/favorites.ts` (toggle response) and the agent/skill response schemas in the same directory (GET response). Refer to those for exact field names and types; assert against the schema, not against fields baked into this doc.
6+
7+
Both favorite and unfavorite are idempotent — calling them twice returns the same body the second time. Favorites are gated by the `favorites` builder feature (404 if disabled) and require auth (401 under `--auth off`). (This file was formerly named `stars.md`; the feature was renamed `stars``favorites` across the stack. See PR #16749 — STACK-3.)
8+
9+
> **Field-name asymmetry.** The toggle endpoint (`PUT|DELETE /stored/{type}/:id/favorite`) returns `{ favorited, favoriteCount }`. The GET endpoint (`/stored/{type}/:id`) exposes the caller's favorite state as `isFavorited` (alongside `favoriteCount`). When asserting "is favorited" on GET, check `isFavorited`, not `favorited`.
10+
11+
## Auth requirement
12+
13+
**This section requires `--auth on`.** Favorites are scoped per caller (the row in `stored_favorites` is keyed on `(entityId, authorId)`). With `--auth off`, there is no caller to attach the favorite to and the route returns either `401 Authentication required` or `404 Not Found` depending on how the route is registered for the current build — both mean "unreachable under auth-off". Treat any non-2xx as the expected outcome.
14+
15+
### Running with `--auth off`
16+
17+
Favorites are **fully unreachable under `--auth off`**. The PUT/DELETE endpoints return a non-2xx (typically `401 Authentication required`, sometimes `404 Not Found` depending on build), and the Studio + Agent Builder favorite buttons render with a "Sign in to favorite this agent/skill" tooltip. Do the sanity check below, mark this section as `Skipped (requires --auth on)`, and move on. Do **not** try to create agents and favorite them — it will not work and is not expected to work.
18+
19+
```bash
20+
# Sanity: confirm favorites are gated by auth
21+
curl -s -o /dev/null -w "%{http_code}\n" -X PUT $BASE/stored/agents/$AGENT_ID/favorite
22+
# → 401 or 404 (unreachable under auth-off)
23+
curl -s -o /dev/null -w "%{http_code}\n" -X DELETE $BASE/stored/agents/$AGENT_ID/favorite
24+
# → 404
25+
```
26+
27+
- [ ] Both calls return a non-2xx status, either `401` or `404` (both mean "unreachable under auth-off")
28+
- [ ] Skip the rest of this file; report the section as `Skipped (requires --auth on)`
29+
30+
## Prerequisites (auth-on)
31+
32+
You need a logged-in session (`$SESSION` should be a `Cookie:` header) and a stored entity to target.
33+
34+
**If you have `stored-agents:write` / `stored-skills:write`** (owner, admin, member), create test entities:
35+
36+
```bash
37+
# Test agent
38+
AGENT_RESP=$(curl -s -X POST $BASE/stored/agents \
39+
-H "$SESSION" \
40+
-H 'Content-Type: application/json' \
41+
-d '{
42+
"name": "Favorite Test Agent",
43+
"instructions": "Test agent for favorite testing",
44+
"model": {"provider": "openai", "name": "gpt-4o-mini"}
45+
}')
46+
AGENT_ID=$(echo "$AGENT_RESP" | jq -r '.id')
47+
48+
# Test skill
49+
SKILL_RESP=$(curl -s -X POST $BASE/stored/skills \
50+
-H "$SESSION" \
51+
-H 'Content-Type: application/json' \
52+
-d '{
53+
"name": "Favorite Test Skill",
54+
"description": "Test skill for favorite testing",
55+
"instructions": "Favorite test instructions."
56+
}')
57+
SKILL_ID=$(echo "$SKILL_RESP" | jq -r '.id')
58+
```
59+
60+
**If you don't have write perms** (viewer), use the rows from `seed-multi-user.sh` (run it from SKILL.md execution flow step 4 if you haven't):
61+
62+
```bash
63+
SKILL_ID=smoke-seed-public-skill # public, owned by user_seed_other
64+
# For agents, skip steps 1–3 and run the skill steps only — the seed script does not
65+
# seed stored agents. Note "agent favorite CRUD: not exercised in non-admin runs" in the report.
66+
```
67+
68+
## Steps
69+
70+
### 1. Favorite an agent
71+
72+
```bash
73+
curl -s -X PUT $BASE/stored/agents/$AGENT_ID/favorite -H "$SESSION" | jq .
74+
```
75+
76+
- [ ] HTTP `200`
77+
- [ ] Body is `{ "favorited": true, "favoriteCount": <n> }` with `n >= 1`
78+
79+
### 2. Verify the agent is favorited
80+
81+
```bash
82+
curl -s $BASE/stored/agents/$AGENT_ID -H "$SESSION" | jq .
83+
```
84+
85+
- [ ] `isFavorited` is `true` on the GET response
86+
- [ ] `favoriteCount` matches the value from step 1
87+
88+
### 3. Unfavorite the agent
89+
90+
```bash
91+
curl -s -X DELETE $BASE/stored/agents/$AGENT_ID/favorite -H "$SESSION" | jq .
92+
```
93+
94+
- [ ] HTTP `200`
95+
- [ ] Body shows the agent is no longer favorited for the caller and `favoriteCount` decreased by 1
96+
- [ ] Re-fetching the agent reflects the unfavorited state
97+
98+
### 4. Favorite a skill
99+
100+
```bash
101+
curl -s -X PUT $BASE/stored/skills/$SKILL_ID/favorite -H "$SESSION" | jq .
102+
```
103+
104+
- [ ] HTTP `200`
105+
- [ ] Body is `{ "favorited": true, "favoriteCount": <n> }`
106+
107+
### 5. Verify the skill is favorited
108+
109+
```bash
110+
curl -s $BASE/stored/skills/$SKILL_ID -H "$SESSION" | jq .
111+
```
112+
113+
- [ ] `isFavorited` is `true` on the GET response
114+
- [ ] `favoriteCount` matches step 4
115+
116+
### 6. Unfavorite the skill
117+
118+
```bash
119+
curl -s -X DELETE $BASE/stored/skills/$SKILL_ID/favorite -H "$SESSION" | jq .
120+
```
121+
122+
- [ ] HTTP `200`
123+
- [ ] Body is `{ "favorited": false, "favoriteCount": <previous - 1> }`
124+
125+
### 7. Idempotent favorite (favorite twice)
126+
127+
```bash
128+
curl -s -X PUT $BASE/stored/agents/$AGENT_ID/favorite -H "$SESSION" | jq .
129+
curl -s -X PUT $BASE/stored/agents/$AGENT_ID/favorite -H "$SESSION" | jq .
130+
```
131+
132+
- [ ] Both calls return `200`
133+
- [ ] Both bodies are identical (`favoriteCount` does not increment on the second call)
134+
135+
### 8. Idempotent unfavorite (unfavorite twice)
136+
137+
```bash
138+
curl -s -X DELETE $BASE/stored/agents/$AGENT_ID/favorite -H "$SESSION" | jq .
139+
curl -s -X DELETE $BASE/stored/agents/$AGENT_ID/favorite -H "$SESSION" | jq .
140+
```
141+
142+
- [ ] Both calls return `200`
143+
- [ ] Both bodies are identical (`favorited: false`, `favoriteCount` unchanged on the second call)
144+
145+
### Cleanup
146+
147+
```bash
148+
curl -s -X DELETE $BASE/stored/agents/$AGENT_ID -H "$SESSION" -o /dev/null -w "%{http_code}\n" # → 200
149+
curl -s -X DELETE $BASE/stored/skills/$SKILL_ID -H "$SESSION" -o /dev/null -w "%{http_code}\n" # → 200
150+
```
151+
152+
## Checklist
153+
154+
- [ ] Auth-off path: PUT/DELETE favorite return non-2xx (`401` or `404`); no other assertions
155+
- [ ] Auth-on: favorite agent (200 + `favorited: true`)
156+
- [ ] Verify agent favorited on GET
157+
- [ ] Unfavorite agent (200 + `favorited: false`)
158+
- [ ] Favorite skill (200 + `favorited: true`)
159+
- [ ] Verify skill favorited on GET
160+
- [ ] Unfavorite skill (200 + `favorited: false`)
161+
- [ ] Idempotent favorite (second body identical)
162+
- [ ] Idempotent unfavorite (second body identical)

.claude/skills/builder-smoke-test/references/infrastructure.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,10 @@ curl -s -H "$SESSION" "$BASE/editor/builder/infrastructure" | jq '.workspace'
6666

6767
- [ ] `type` is `"id"` (matches `workspace: { type: 'id', workspaceId: 'builder-workspace' }`)
6868
- [ ] `workspaceId` is `"builder-workspace"`
69-
- [ ] `filesystemProvider` and `sandboxProvider` populated
70-
- [ ] `config` is an array of `{key, value}` pairs
69+
- [ ] `name` is present (e.g. `"Builder Workspace"`) and `source` reflects builder metadata
70+
- [ ] `registered` is `true`; `hasFilesystem` is `true`; `hasSandbox` reflects scaffold config
71+
- [ ] `filesystemProvider` populated (e.g. `"local"`); `sandboxProvider` may be `null` when no sandbox is configured
72+
- [ ] `config` is an array of `{key, value}` pairs — may be empty `[]` when the workspace block doesn't expose tunables
7173

7274
If you change the inline workspace block in the scaffolded project's `src/mastra/index.ts` and restart:
7375

.claude/skills/builder-smoke-test/references/model-policy.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ models: {
2727
### 1. Settings exposes the policy
2828

2929
```bash
30-
curl -s "$BASE/editor/builder/settings" | jq '.agent.models // .configuration.agent.models'
30+
curl -s "$BASE/editor/builder/settings" | jq '.configuration.agent.models'
3131
```
3232

3333
- [ ] `allowed` is an array with the two entries above

0 commit comments

Comments
 (0)