Repository navigation
v0.19.0
[0.19.0] - 2026-09-25
Verdicts that say how sure they are, detectors that see through disguises, and one command to set up any client. 0.19.0:
- A verdict is called
decisiveonly where labelled data shows its risk estimate holds, and a verdict stored from this release on reads back exactly as it was given. - The PII and injection detectors catch the common ways a leak or an attack is disguised, and stay quiet on correct answers that only look like one.
npx -y @iris-eval/mcp-server install <client>writes Iris into ten MCP clients. On every pull request and every commit to main, CI starts the real Claude Code and Gemini CLI against the build on Linux, macOS and Windows.- The proof page counts rules measured for detection apart from rules checked against their own formula.
Check before upgrading.
- Every pass at the default settings now reads
confidence: "marginal", with a note. A gate or dashboard that keyed on"decisive"will not see it on a pass, and one that treated"marginal"as rare will see it on every pass.passed,stateandbasisdo not change. no_piiandno_injection_patternsfire on disguised values and directives they used to pass, so a CI gate ondetector_vetocan trip where it passed before (the shapes are under Changed).- Every verdict stored by 0.18.0 or earlier reads back with no
confidence, and a note says why, instead of taking a label from the new rule; re-evaluate the output to label it. Itspassed,state,basisand risk are as stored. - The public claims schema (
iris-eval.com/claims-schema-v1.json) dropsinitPackageand requiresirisEvalPackageandpythonPackage. - A config written by
installpins the Iris version. Runinstallagain after upgrading to move the pin.
Added
iris-eval install <client>sets up an MCP client from the server package.npx -y @iris-eval/mcp-server install claude-codeadds Iris to Claude Code's config; the clients areclaude-code,claude-desktop,cursor,windsurf,continue,vscode,cline,zed,codexandgemini.--uninstallremoves the entry, and--listshows which clients are on the machine. An entry under the old keyirismoves toiris-evalwhen it runs Iris; another server under that name is left as it is, and the command says so. The entry runsnpx -y @iris-eval/mcp-server@<this version>. Running install again moves that pin and keeps what the user added (environment variables, other keys, arguments after the package). JSON configs are edited as text, so comments, key order and line endings survive, and each JSON edit is parsed again and must change only the Iris entry, or nothing is written. Codex's TOML is edited only inside the Iris tables: a config that defines the server in another TOML form is refused with a message rather than given a second definition. Every write is atomic and keeps the file's permission bits. Each client's config path and shape come from its current documentation, which corrected four the earlier installer had wrong: Continue reads~/.continue/mcpServers/, Windsurf is now Devin Desktop with its own path, Cline's settings moved, and Zed takes a flatcommand/args/enventry. Cursor gets the"type": "stdio"its docs require. For Claude Code and Gemini CLI, a CI job on Linux, macOS and Windows installs the package from this commit under a version no registry has, runsinstall, and requires the client itself to report Iris connected; the README's clients table marks those two verified and the other eight by their documentation. Gemini CLI connects only in a trusted folder, so the command says to run/permissions. The separate@iris-eval/initinstaller, never published, is retired.
Changed
verdict.confidenceis"decisive"only where labelled data shows the risk estimate holds. Through 0.18.0 a verdict was decisive whenever the credible interval onpBadexcluded the loss threshold τ. That interval carries the uncertainty in the detectors' published error rates, not the error of the model that combines them, and the composite corpus measures that error as large where most verdicts land: clean passes state apBadof about 0.13, and in that tenth of the dev split 12 of 39 verdicts were outputs that should not have shipped (30.8%, 95% interval 18.6–46.4%). A verdict is now decisive only when the interval excludes τ, the verdict was computed at the prior the corpus measured with no local labels, and its tenth ofpBadholds at least 10 labelled verdicts from at least 4 distinct detector-firing patterns whose observed bad rate is consistent with the statedpBadand lies wholly on the verdict's side of τ. At the shipped τ of 0.5 only one tenth qualifies (0.7–0.8, and only for a fail); on the composite corpus 63 of 101 labelled verdicts move from decisive to marginal, none move the other way, and no labelled verdict is decisive. Under the old rule, decisive verdicts on the held-out test split were right 11 of 17 times. The table is generated from the corpus intosrc/eval/published-calibration.tsand checked in CI;proof/COMPOSITE.md("The confidence label") shows it and how often each label was right. A marginal verdict's interpretation names the test it did not pass, with the measured numbers. On a clean pass at the defaults it opens "Risk estimate measured as too low at this level on labelled data; see iris-eval.com/proof." The dashboard shows a marginal pass whose interval clears τ in a neutral tone and says the estimate there may be too low or too high; fails and verdicts whose interval straddles τ keep the warning tone.- The proof headline no longer adds detection numbers and formula self-checks together. "25 / 25 rules measured" counted rules whose labels a model gave by judging the output alongside rules whose labels are their own documented definition applied by an independent script, where a perfect score shows the code implements its formula and nothing about detection. Each proof family now states its
labelBasis(readingordefinition),proof/results.jsoncarries it per rule, and iris-eval.com/proof,proof/RESULTS.md,llms.txtandllms-full.txtcount the two apart: 12 rules measured for detection, 1 of them at F1 1.00, and 13 checked against their own formula, 12 of them at F1 1.00. The pages say the reading labels were given by a model, and a family without alabelBasisis never counted as detection. No rule's precision, recall or F1 moved. Adding the field changed the corpus version, which reseeds the composite corpus's credible-interval draws: interval bounds moved by at most 0.031, and no verdict, accuracy or calibration figure changed. - The critical detectors read through the common disguises, and only the disguises.
no_piinow reads an SSN written with typographic dashes or minus signs, or with spaces, dots or no separator right after "SSN", "social security" or "soc sec"; a card number after a card word in groups split by a spaced or typographic dash, and the American Express 4-6-5 grouping with its separators; an IBAN in its printed four-character groups; an email spelled out with "(at)"/"[at]" and "(dot)", or with a plain "at … dot" before a webmail provider; and any PII inside a base64 run that decodes to text.no_injection_patternsreads the override phrase in French, Spanish, Portuguese, German and Chinese, held to the English shape (the imperative, then the word for "all" or no article); letter-spaced text; "DAN" in capitals with its no-restrictions framing in the same sentence; a markdown image whose URL carries a template placeholder in its query or fragment, or a secret-named parameter with a real-looking value; and any directive inside decodable base64.tests/unit/eval/obfuscated-detection.test.tsholds each disguise the rules now read. Correct answers that look like a leak stay passing, and a shared fixture holds them for the server and the playground: a sign-in link to a webmail provider, a timeline of dashed years, a tracking number, a polite correction in another language, a quoted directive under «», „“ or 「」 quotation marks, a sales assistant named Dan, a Jekyll image template. Checksums keep each widened shape precise (Luhn for cards, mod-97 for IBANs, issuance rules for SSNs), base64 is decoded only when it turns into valid text (at most 64 runs of up to 4,096 characters per output), and every new reading stays linear in the input, with 1 MiB hostile payloads in the test suite. The injection pattern count goes from 37 to 38.no_injection_compliancereads the same phrases in tool output. No labelled-corpus precision, recall or F1 moved. - The GitHub Action's version pins move with each release.
version:syncrewrites everyuses: iris-eval/mcp-server/.github/actions/gate@vX.Y.Zin the README,docs/ci-gate.mdand the action itself, andversion:checkfails on a pin that differs from the release. They name this release, v0.19.0.
Fixed
- A stored verdict reads back as it was given.
provenance.composernow recordspriorModeand the calibration table the label was read from. For verdicts stored from 0.19.0 on, a fail undereval.priorMode: "per-class"no longer reads back as a pass. A verdict labelled under another table, or stored before the record existed, keeps its stored result and reads back with no confidence label instead of taking today's. - One malformed stored rule result can no longer stop the server at startup. Startup sorts stored rule names to refresh local labels, so a single stored result without a
ruleNamethrewCannot read properties of undefined (reading 'localeCompare')and the server exited before answering any client. Every read of stored rule results now goes through one parser: a result namedruleis read under that name, a result with no name is skipped, and unreadable data reads as empty. No release writes such rows; they came from hand-seeded data. Stored rows are not rewritten. - No blog post tells readers to run the retired command name. Three posts from the 0.4 era still showed the original command. It stays installed so existing configs keep running, but on npm that name belongs to another project's package, so a reader who copied it with
npxwould have run that package instead. The posts now shownpx -y @iris-eval/mcp-server, and the check that keeps the legacy name off every live page now covers the blog. - The Python client's README links to iris-eval.com (its PyPI page shows the change from the client's next release), and two dead links on the site are fixed.
Supply-chain transparency
- SBOMs:
iris-npm-sbom.spdx.json+iris-docker-sbom.spdx.json(attached below). Both are SPDX 2.3 JSON, cover direct + transitive dependencies. - SBOM signatures: each SBOM has a companion
.sigstore.json(Sigstore bundle — signature + cert + Rekor entry) attached to this release. The release workflow runs this exact verification itself before it reports success. Verify with:cosign verify-blob \ --bundle iris-npm-sbom.spdx.json.sigstore.json \ --certificate-identity='https://github.com/iris-eval/mcp-server/.github/workflows/release.yml@refs/tags/v0.19.0' \ --certificate-oidc-issuer='https://token.actions.githubusercontent.com' \ iris-npm-sbom.spdx.json - npm provenance: published with
--provenance(verifiable vianpm audit signaturesor on the package page). - Docker signature: image signed with cosign keyless (Sigstore). Verify with:
cosign verify ghcr.io/iris-eval/mcp-server:v0.19.0 \ --certificate-identity='https://github.com/iris-eval/mcp-server/.github/workflows/release.yml@refs/tags/v0.19.0' \ --certificate-oidc-issuer='https://token.actions.githubusercontent.com' - Build attestation: both the npm SBOM and Docker image manifest carry GitHub-signed build-provenance attestations. Inspect with
gh attestation verifyorcosign verify-attestation.
What's Changed
- docs(blog): hardening LLM-as-judge against prompt injection by @irparent in #175
- fix(npm): npx iris-eval starts Iris, and no page teaches iris-mcp by @irparent in #611
- chore(website): skip a site deployment when a commit touches only folders the site never reads by @irparent in #612
- fix(storage): rule results from the earliest releases no longer stop the server at startup by @irparent in #615
- fix(eval): no_pii and no_injection_patterns read disguised values and directives by @irparent in #613
- fix: call a verdict decisive only where measured; count detection and formula self-checks apart on /proof by @irparent in #614
- fix: bot branches create no site deployments; skip compares against the last deployment; stored-result wording corrected by @irparent in #616
- fix(website): the waitlist size is the operator's number, not page copy; two dead links fixed by @irparent in #619
- fix(eval): no_pii and no_injection_patterns stop vetoing correct answers that look like a leak by @irparent in #617
- fix(confidence): an evidence floor for decisive, verdicts that read back as given, plain wording on a clean pass by @irparent in #618
- docs(listings): the Docker entry starts over stdio; the awesome-list row carries no numbers by @irparent in #621
- feat(install): iris-eval install is part of the server package; the separate installer retires by @irparent in #620
- fix(install): an
irisentry is migrated only when it runs Iris; Codex edits stay inside the Iris tables by @irparent in #637 - fix(confidence): a clean pass says the estimate was measured too low there; stored-verdict notes name no internal id by @irparent in #638
- docs(changelog): 0.19.0 release notes; every test runs on every platform by @irparent in #636
- release: 0.19.0 — verdicts that say how sure they are, detectors that see through disguises, one command to set up any client by @irparent in #639
Full Changelog: v0.18.0...v0.19.0