v1.0.0
[1.0.0] — 2026-06-22
The 1.0 release. Iris is stable, documented, and benchmarked end to end: every package is versioned
1.0.0 under the open-core license split, and the same verify loop that wins on a toy app stays the
cheapest way to observe a real production dashboard.
The headline is the "lean responses" pass — same observations, fewer tokens. On the cross-tool
detection benchmark Iris's average observation cost drops 959 → 815 tokens with detection unchanged at
1.0 and zero false positives, lifting Verification Efficiency past the best external tool (12.27 vs
10.55) while remaining the only tool that catches every regression. Re-verifying a saved suite costs
47 tokens with no model and 0% flake, up to 2,574× cheaper than re-driving it with an LLM.
Added
- Honest, reproducible benchmarks with a small-app vs real-app story. A committed benchmark image
set (re-run efficiency, the two-apps small-vs-real comparison, the per-tool cost on the real Syrin
dashboard, and a capability matrix) rendered from a public source pipeline (assets/benchmarks+
a shared design system), with the methodology written up indocs/benchmarks.md.
On a real production dashboard Iris observes a page for 1,023 tokens vs Chrome DevTools MCP's 1,357
and Playwright MCP's 2,193, and is the only tool that asserts success from the app's own signal. - Documentation set — an architecture overview, the benchmarks explainer,
an expanded getting-started, and a Mintlify configuration so the docs
publish as a site. - Open-source project hygiene —
CONTRIBUTING.md,CODE_OF_CONDUCT.md, issue and pull-request
templates, plus contributor / stargazer / forker recognition in the README.
Changed
iris_actcollapses a clean action to its consequence — the effect block now omits fields at
their uninformative default (an absentdispatched/targetMatched/visible/enabledmeanstrue;
an absentfocusMoved/occludedBymeansnull; an absentoccluded/scrolledIntoView/
valueChanged/defaultPreventedmeansfalse), so a successful click returns justdomMutatedWithin
and any real signal still surfaces. No information is lost — absence always means the boring value.- MCP tool results serialize as compact JSON by default — the agent-facing
textcontent drops the
two-space indentation (the typedstructuredContentis unchanged), ~40% cheaper on the structured
payloads that dominate. SetIRIS_ENCODING=prettyfor the previous indented form;IRIS_ENCODING=toon
remains the densest tabular encoding. iris_act_and_waitreturns a reaction digest, not the full timeline —traceis now
{ window_ms, summary }(the counts that answer "what did the app do?") plus asincecursor; the full
per-event timeline is oneiris_observe { since }away when the counts aren't enough. On a large DOM the
dropped events array was the bulk of the loop cost — a verify loop on a 5,000-row grid falls from ~531 to
~279 tokens with the consequence still asserted from therow:approvedsignal.
Fixed
- Multiple apps on one machine no longer collide or orphan the daemon. Several Next.js / React apps
(or browser tabs) can run at once: the@syrin/iris-nextintegration now defaults to a unique per-tab
session id (SESSION_AUTO) instead of a shared constant, so two Next apps never silently evict each
other. A bridge/daemon port collision now fails fast with a clear error instead of hanging forever
and leaving an orphaned process — thelisten()calls finally handleEADDRINUSE. - License files now carry a real copyright. Filled the Apache-2.0 appendix in every SDK package
license so no[yyyy]/[name of copyright owner]placeholders remain.
Security
- Daemon mode now enforces the documented auth contract.
iris serve/ the MCP daemon previously
built its bridge without forwarding the pairingtoken, bindhost, or origin allow-list, so
IRIS_TOKEN/IRIS_HOST/IRIS_ALLOWED_ORIGINSwere silently ignored in daemon mode. They are now
honored identically to the in-process path. (Residual risk was bounded — the daemon is loopback-pinned —
but the advertised control is now actually enforced.) - Every security-critical environment variable is a single named constant (
IrisEnvin
@syrin/iris-protocol). A typo in an inline'IRIS_TOKEN'string could previously have disabled auth
silently; the names now live in exactly one place.