Open in Studio
open_in_studioSave the model as a kernelCAD project AND show it: persists a project revision, returns the interactive Studio viewer (MCP Apps / ChatGPT outputTemplate), and includes a PNG preview in the SAME tool result (image content + previewUrl when available). ONE VIEWER PER PROJECT PER RESPONSE: every call renders a new viewer card. Do all validation with evaluate_script first, then call open_in_studio exactly once, after validation succeeds; reuse the returned URL, revision and preview, and never call it again after a successful result in the same response. Re-calling with unchanged code for the same project returns that revision instead of writing a new one. CONTINUE, DO NOT DUPLICATE: to change a model you already saved, pass project: '<slug>' from the last result (or from list_my_projects) — this adds a revision to that project. Without project, the save goes to the project this chat already saved, or to your project with the same title (case, punctuation and v2/rev3/(1) ignored) from the last 24 h. Views, poses, colours and options of one design are revisions of ONE project — keep the same title and slug. Pass new_project: true only when the user wants a separate design. A different cookbook (execute_cookbook, or open_in_studio of that cookbook's unchanged source) starts its own project; pass project to add a revision, or continue_design: true to keep revising the design this chat is already saving. The result starts with the slug to pass next time, a /p/?version= link for this revision, and that revision's title. Use this when the user wants to SEE or share the model — do NOT call get_latest_render afterwards for the happy path; the preview is already here when previewDelivered is true. Pass the full .kcad source as code (optional if you just called evaluate_script — omitting reuses that last evaluated source). Code that fails evaluate_script (for example overlapping same-material members or floating pieces) is refused; fix it first. Multi-body assemblies must declare connectors + mates/joints before publish — otherwise evaluate_script fails with mechanism.orphan-part (disconnected components). Use type: 'axis' + revolute mates for shafts/hinges/gears; type: 'frame' + fastened for rigid mounts; or arm.revolute/.prismatic/.ball/.fixed. Connector types are only frame|axis|planar|ball. Status fields: ok=true means publish succeeded (under CDN, meshStatus ready/building; ok=false + meshStatus=failed means hard mesh persist failure — do not claim the viewer is ready). previewDelivered=true means this result carries a displayable PNG — only then may you tell the user a preview was shown. meshStatus mirrors get_project (ready|building|failed|missing). Under CDN, open_in_studio waits up to ~20s (OPEN_IN_STUDIO_MESH_SYNC_BUDGET_MS) for the revision mesh before returning; heavier publishes usually land meshStatus=ready. If still meshStatus=building + meshReady=false: TRANSIENT — meshUrl is the expected CDN pin; embed retries 404s. Poll get_project({slug}) until ready (it shows no viewer) — do not re-call open_in_studio, and never treat building as permanent failure/404. ALWAYS pass code when you have it (avoid no_code_to_reuse); evaluate_script reuse is a fallback. Paint phases: projectSaved / meshReady / previewDelivered are set here; viewerPainted is ONLY true after widget ack (model context / widgetState) — never claim paint from this tool alone. Do NOT call get_model_mesh or get_latest_render for interactive paint. INDEPENDENT OF EXPORT/STEP: call this for shaded paint even while export is running, timed out, or returned export.deferred — mesh paint does not wait on STEP. Never block open_in_studio on a STEP download. Pass include_preview:false to skip the rasterizer (save + viewer URLs only). Trigger phrases: "open it in Studio", "let me see it", "show me the model"; also call once after you finish a build, and once per response after each meaningful revision while iterating. ORGANIC/CAR SUCCESS GATE: for final likeness claims pass likeness_profile:"automotive" (and body_bbox/wheels/still_verdicts, or a prior verify body-likeness pass for this code). If the gate fails, ok:false with DX reference.likeness.publish-blocked|gate-required — do not claim success. Omit likeness_profile for WIP previews only. Declare dimensions in the source with shape.dimension({ kind, from, to, label }) (label is a name; the measured value is appended) and they show on the model in every viewer; add ?dims=1 to a /p link to force dimensions on. MARK & FIX: a user message starting Edit kernelCAD project <slug> (revision N): "<note>". Targets: #1 feature "<id>" ... comes from pins the user tapped in the viewer. Feature/part ids are the script's own feature and part names (assembly part names, named shapes); points are world mm. Call get_project with that slug, change only the named features near those points, keep everything else, then open_in_studio with project set to the same slug. Hosted: lib.fromSTEP / fromSTL / fromDXF / fromSVG and referenceImage accept "asset:" (from request_upload), an https:// URL or a data: URI as the path.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| code | No | The full .kcad source of the model to open in Studio (the script you have been editing). Optional: omit to reuse the source from your most recent evaluate_script call. | |
| slug | No | Older name for `project`. Use `project`. | |
| title | No | Optional human-readable title for the model (shown in Studio). Defaults to "Model from Claude". | |
| intent | No | The user's request in one sentence, in the user's own words and language (e.g. 'M4 bracket for a 25 mm tube, print on Bambu A1'). Helps kernelCAD improve; leave out personal data. | |
| wheels | No | Wheel centres + radii for likeness gate [{ center:[x,y,z], radius }]. | |
| project | No | Slug of the project to update (from the last open_in_studio result, a "Saved to your projects" note, list_my_projects, or a /p/<slug> link). Adds a new revision to that project instead of creating a new one, and live-updates the user's open Studio tab. | |
| body_bbox | No | Body AABB { min:[x,y,z], max:[x,y,z] } mm — for likeness_profile gate when no session attest. | |
| anon_token | No | Anonymous owner token returned as `anonToken` by an earlier open_in_studio result. Pass it on every open_in_studio call, also in a new chat, so all your anonymous projects stay together and move to the user's account when they sign in. Omit when you have none. | |
| cabin_bbox | No | Optional cabin AABB for likeness gate. | |
| parameters | No | Optional list of the model's editable parameters, so Studio can render parameter controls. Each item is one control derived from the .kcad params. | |
| attachments | No | Complementary project files referenced by relative path from the .kcad source. | |
| new_project | No | Pass true only when the user wants a separate, new design. Default: continue this chat's project, or your project with the same title from the last 24 h. Still wins over a matching title or cookbook. | |
| require_stills | No | Forwarded to body-likeness gate (default true). | |
| still_verdicts | No | Agent still checklist for likeness gate [{ code, passed, finding, view? }]. | |
| continue_design | No | Pass true to add a revision to the design this chat is already saving, even when this call is a different cookbook or title. Ignored when `project` is set. | |
| include_preview | No | Default true: render an iso PNG preview into this same tool result (reuses the server render cache when this source was already rendered). Set false to skip rasterization and return save/viewer URLs only. | |
| likeness_profile | No | Hard success gate for organic/car bodies. When set, open_in_studio returns ok:false unless body-likeness is publishReady (inline body_bbox/wheels/still_verdicts, or a prior verify body-likeness pass for this exact code). Omit for WIP previews. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| ok | No | Whether publish succeeded. Under CDN mode, false when mesh persist hard-failed (meshStatus:failed) — never ok:true with meshUrl silently omitted. | |
| url | No | Revision-pinned /p/<slug>?version= Studio link for the revision this call saved. | |
| slug | No | The project slug. Pass it back as `project` to save the next change to this project. | |
| title | No | Title stored for this revision (not a later revision of the same project). | |
| animUrl | No | CDN transforms-only animation bake URL when the script declares animationView(). ChatGPT embed Play/scrub uses this — no live session remesh. | |
| meshUrl | No | Revision-matched mesh artifact URL when available — prefer this over re-executing CAD in the embed. When meshStatus is building, this is the expected CDN URL (retry until ready). | |
| updated | No | True when an existing project was updated; false when a new one was created. | |
| version | No | Immutable Studio revision persisted by this call. Read it with get_project_revision using this slug and version. | |
| embedUrl | No | Read-only, chrome-free /embed/<slug> viewer URL — drop into an <iframe> to embed the live model in any site or widget (no login). Includes meshUrl when a revision mesh artifact is available. | |
| meshHint | No | When meshStatus=building: transient OCCT/CDN write — poll get_project or re-open_in_studio; never imply permanent 404/failure. Present under CDN when building. | |
| meshError | No | Sanitized persist/repair error when meshStatus is failed. | |
| meshReady | No | True only when meshStatus===ready. building+meshUrl means embed is still polling. | |
| paintHint | No | Agent guidance: do not claim interactive paint until viewerPainted. | |
| meshStatus | No | ready | building | failed | missing — explicit CDN artifact state (never silently omit meshUrl under CDN mode). | |
| previewUrl | No | HTTPS URL of the PNG preview when storage signed successfully. | |
| assetHashes | No | ||
| previewHint | No | ||
| previewView | No | ||
| serverBuild | No | Deploy identity so connector vs server mismatch is observable. | |
| hasAnimation | No | True when animUrl is present (animationView timeline baked at publish). | |
| previewBytes | No | ||
| previewWidth | No | ||
| projectSaved | No | True when the project/revision was persisted. Not the same as viewerPainted. | |
| project_note | No | Which project was updated or created, its URL, and how to keep working on it. | |
| previewCached | No | ||
| previewHeight | No | ||
| previewStatus | No | included = PNG + URL; included_inline = PNG only; unavailable = save ok but no preview; skipped = include_preview:false. | |
| viewerPainted | No | Always false on tools/call. The Studio widget sets viewerPainted:true via updateModelContext after a correlated model_displayed ack. | |
| attachmentCount | No | ||
| previewDelivered | No | True when this result includes a displayable PNG (image content and/or previewUrl). Only then may the agent claim a preview was shown to the user. |