Atelier Studio v1.6.0
Atelier Studio 1.6.0
Atelier Studio 1.6.0 gives the chat a new kind of answer. An agent can now put a living panel into the conversation — a slider you drag, a simulation you run, a curve you scrub — instead of a static image or a wall of numbers. Around that headline, this release is mostly about making the app quieter and faster: a long session no longer grows without bound, the shell stops re-rendering on every streamed token, and a first gallery scan no longer blocks a rebuild. It also closes the distance between Atelier and the CLIs it drives — steering a Codex turn now behaves exactly as Codex allows, and figures produced by an agent are checked for geometry before you ever see them.
Highlights
- Ask for a widget and get one inside the thread: an interactive HTML panel rendered in a closed iframe, themed with your own tokens, whose state survives scrolling and whose file survives a session reload.
- Let any CLI provider produce those panels — the instruction rides the message, so even a small routed model reaches for the tool instead of writing an HTML file to disk.
- Keep a long session bounded: inactive threads release their events and reload from the journal when you come back.
- Feel a shorter startup and a calmer stream — settings load on demand, the top bar and rail no longer re-render on every delta, and the streaming fade is capped at the last forty words.
- Steer a running Codex turn with the same semantics as the CLI: a stale turn id is retried, a review or compaction turn is queued instead of doubled, and no fallback silently loses your MCP servers.
- Have every agent-made matplotlib figure checked for overlapping labels, text crossing a spine, and text falling off the canvas — the agent fixes it before handing the figure over.
- Know where a figure came from: script, command, environment, and conversation, captured as a side effect of the turn that produced it.
Living widgets in the thread
A new MCP tool, atelier_widget, lets an agent display an interactive panel directly in the conversation.
- The HTML travels over the local capability bridge rather than the tool's output, so it escapes the 64 KiB truncation and never re-enters the model's context — the CLI receives an identifier.
- The panel is written to the app directory under a hashed thread id and served over an authenticated loopback route. A thread you delete takes its widgets with it; beyond 200 files per thread the oldest are purged.
- The runtime wraps the agent's fragment in a shell it controls:
sandbox="allow-scripts"alone (opaque origin — no storage, no cookies, no parent navigation) and a CSP ofdefault-src 'none', withform-actionandbase-urideclared explicitly becausedefault-srcis not a fallback for either. - Three bridge functions are defined for the panel's script:
sendPrompt(text)proposes a message in the composer and lets you approve it — a widget never spends a turn on its own;saveState(object)andwindow.onRestore(state)keep controls where you left them across scrolling. - The card reuses the existing code-block chassis, reserves its declared height before the frame exists so the thread never jumps, replays the theme without remounting, and degrades to a sober line — never a red error — when a widget fails to start or its file is gone.
- A capability guide,
atelier_widget_guide, carries a full manual the agent reads once per session: complexity budgets, the design system with real tokens, dataviz legibility rules, ten panel forms with skeletons, eight advanced interaction patterns drawn from the explorable-explanations tradition, accessibility, and named anti-patterns. - Eight widgets per turn maximum, 128 KiB per panel, height clamped to 120–900 px. A malformed call no longer burns one of the turn's slots.
Performance
- Inactive threads are evicted from memory and restored from the journal on return, so a long session stops growing without bound. An agent thread open in the Atelier pane is exempt — it was being evicted with no path to reload it.
- Settings load their JavaScript and CSS on demand; the startup bundle shrinks by that much.
- The top bar and the rail are memoised, and the callbacks they receive are stable, so a streamed delta no longer re-renders the shell.
- The streaming fade is bounded to the last forty words instead of animating hundreds of elements, and the 300 ms follow net runs only during an active turn.
- The active turn's margin is set by a class rather than a
:has()selector, which a browser re-evaluated on every mutation of a virtualised list. - Streaming code blocks no longer insert an LRU entry per frame,
splitCodeSegmentsworks in slices, andToolOutputLineparses each output once instead of once per frame. - Gallery thumbnails are generated in a bounded pool, so the first scan of a large project no longer blocks a rebuild; the LaTeX studio renders PDF pages on demand with eviction instead of keeping a canvas for every page.
- A hidden terminal stops blinking its cursor.
Codex parity
turn/steerrefusals are now distinguished. A staleexpectedTurnIdcarries the real one in the server's message, so the steer is retried against it instead of starting a second turn. A review or compaction turn — which can never be steered — has the message queued throughthread/queue/addrather than doubled or dropped.- A steer that falls back to a normal turn keeps its MCP capability; previously the thread resumed with no Atelier servers declared, and the agent silently lost its tools mid-session.
- The capability token is stable per thread while its grant lives, which restores the ACP fast paths for Grok, Kimi, and Opencode — a resumed thread no longer replays its whole history on every turn. Its TTL now slides with activity, under an absolute lifetime cap.
- Strict MCP configuration follows whether a thread is linked, not whether Atelier declares a server, so an ordinary Claude thread keeps your personal MCP servers.
/compactno longer announces completion at the moment it starts:thread/compact/startbegins a turn, and both providers already report the real compaction through their own stream.- Model switching happens the way Codex expects —
thread/settings/updatebefore the turn — which is what triggers auto-compaction when history exceeds the new model's window.
Figures
- Every agent turn that produces a
.png,.svg, or.pdfwrites a provenance sidecar next to it: the scripts touched, the commands run, the prompt, the thread, the provider and model, the snapshot and HEAD, and a best-effort environment. The gallery viewer shows it. - A geometric quality control ships with the app and is required by prompt: after each
savefig, the agent verifies that no visible text overlaps another, crosses a spine, or falls off the canvas, and that the written image has the dimensions the script asked for — then fixes and re-saves until it passes. - The check compares text per axes rather than across the whole figure, excludes legend entries from each other, ignores tick labels sitting on their own spine, and filters the phantom ticks matplotlib creates outside the axis limits and never draws.
ATELIER_FIGURE_QC=offdisables it for batch pipelines. - The LaTeX studio gained a table view for CSV files.
Correctness and robustness
- Sequence allocation is shared across all seven writers; three concurrent writers could previously collide, and
next_sequencenow reads the journal outside the global lock. - Spawned gallery servers die with the app on exit, interrupted atomic writes are swept at boot, the thumbnail GC keeps SVG thumbnails alive, and temporary directory nonces are atomic so pool workers cannot collide.
- Widget state is measured in UTF-8 bytes rather than UTF-16 units, a floating-point height is clamped instead of refused, and only one widget iframe is ever mounted at a time.
- A Quick Ask turn that fails now says so instead of falling silent.
Platform: macOS on Apple Silicon.
The packaged app includes Node.js 22 and the gallery runtime. No
separate Node.js or Python installation is required for the app.
Claude Code CLI (2.1.139 or newer) and Codex CLI remain external
prerequisites for their respective providers.
If macOS Gatekeeper blocks an unsigned download, run:
xattr -cr "/Applications/Atelier.app"