Changelog
Generated from CHANGELOG.md in the project repository. Never maintained twice.
Unreleased
- changedPages: the project site uses the current shared theme (0.12.12).
- changedContributors: the site builds with chartlet
0.23.0and the recordings are rendered with castwright0.6.0; the architecture diagram is drawn 605 pixels wide, the width chartlet asks for.
0.14.0
9 November 2026
- addedUpdates:
--updateslists outdated packages for bun (from its table) and yarn classic (yarn outdated --json, listing only). Unreadable output is an error, never "everything current". Yarn Berry stays unsupported. Details: Updates. - addedCLI:
opi --completions <bash|zsh|fish>prints a completion script for flags, workflow names and the script names of the current project. Setup: Installation. - addedJSON:
--jsonwith--health,--security,--updatesand--check <workflow>prints one JSON document with a versioned schema instead of the text report; exit codes are unchanged. - changedPages: the project site uses the current shared theme (0.12.6).
- changedTerminal: runemark 0.10: an empty
NO_COLORno longer switches colour off andTERM=dumbdoes, and the selection menu follows the console's symbol theme and supports Home, End, PgUp and PgDn. - fixedUpdates: package names and versions from a package manager's report that start with
-or contain control characters are dropped or defanged before they are shown or passed on, and names are handed topnpm update --latestafter--. - fixedUpdates: Yarn Berry now says it has no
outdatedcommand and points toyarn upgrade-interactive, instead of claimingopicannot read its output. - fixedUpdates: an unreachable registry with yarn classic shows the error text instead of yarn's raw JSON error line.
- fixedCLI:
--list-namesskips script names that contain control characters. - fixedInstall:
Cargo.tomlcarries[package.metadata.binstall]matching the release archive names, socargo binstall opifetches the release binary instead of compiling. - securityJSON: the
outputof aSecretscheck is withheld in--json, since a secret scanner may print the secrets it found. Schema: JSON output. - securitySources: a password or token in a dependency URL is masked (
user:***@host) in the text report and in--json.
0.13.4
1 November 2026
- fixedSBOM: where
npm sbomrefuses a project becausepackage.jsonhas noversion,opi --sbomsays so instead of passing on npm'sEINVALIDPURLTYPEline.
0.13.3
1 November 2026
- fixedSecurity: the remedy for an npm finding names the version
npm audit fixwould install, instead of the vulnerable range (update to <=4.17.23for lodash, nowupdate to 4.18.1). - fixedSecurity: the license line of an npm project is read from
package-lock.json, so it no longer fails wherepackage.jsonhas noversionandnpm sbomrefuses the project. - fixedSecurity: a project without dependencies shows
Licenses — no dependenciesinstead of an empty line.
0.13.2
31 October 2026
- fixedSecurity: the secret scan lists the findings that fail it before high-entropy guesses, so a long list of guesses no longer hides them behind the twenty-line cap.
0.13.1
29 October 2026
- addedDocs: Hooks and CI has a script that runs Health and Security across a folder of repositories.
- changedSecurity: the bundled secret scan skips files Git ignores, and a high-entropy string is a warning instead of a failure.
- changedSite: the start page leads with two equal entry points, running scripts and checking the project, followed by what opi reads per ecosystem, the four areas and the workflows; the recordings are from 0.13.0.
- changedDocs: Hooks and CI loads its recordings from the site instead of raw.githubusercontent.com.
- fixedHealth:
tscruns only where the package has atsconfig.json, instead of failing with its help text. - fixedHealth: the Rust documentation check names the library in a package with a library and a binary, where
cargo rustdocrefused to start.
0.13.0
29 October 2026
- addedSecurity: bundled nosecrets scanning covers projects without an installed scanner, respecting repository configuration and fingerprint ignores.
- addedWorkflows:
--checksselects checks and builds per workflow in.opi/checks.json;--check deployruns deployment checks without executing the deploy script. - addedWorkflows: commit checks inspect staged secrets, whitespace, conflict markers and oversized new files without changing the working tree.
- changedDocs: Hooks and CI shows
opiin pre-commit and pre-push hooks, CI jobs and deploy steps, with a recording of the commit workflow as a pre-commit hook. - changedDocs: Installation names
cargo binstall opi, which fetches the release binary instead of building it. - changedSite: "What each area checks" gives Health, Security, Updates, Clean and Scripts an icon-tile summary before the interactive demo.
- securitySite: Astro 7.4.4 brings patched vite, zod, sharp, undici, source-map-js, smol-toml and fast-uri into the project page's build.
0.12.1
27 October 2026
- changedDependencies:
runemark0.9.1 andserde_json1.0.154.
0.12.0
27 October 2026
- addedReleases: the binaries are built with
cargo auditable, socargo audit bincan check a downloaded one, and each release carries a CycloneDX SBOM,opi-v<version>.cdx.json, with an attestation against every archive. The README says how to verify both. - addedSecurity: the license line of
opi --securityalso covers npm and bun projects (fromnpm sbom) and Cargo projects (fromcargo metadata), production dependencies only, with the same notable licenses as for pnpm. - addedSecurity:
opi --securityadds aDependencies (osv)section fromosv-scanner, which reads the npm, pnpm, yarn, bun and Cargo lockfiles against the OSV database. It runs alongsidenpm audit,cargo auditand the others and shows only the packages they did not report; withoutosv-scannerthe section says so. - addedSecurity:
opi --securitylists the installed dependencies that declarepreinstall,installorpostinstallscripts and whether the project allows them — pnpm'sonlyBuiltDependencies/ignoredBuiltDependencies, bun'strustedDependencies, npm'signore-scripts. Scripts nothing has decided on are named. - addedSecurity:
--securitylists dependencies that come from git, a tarball URL or a path outside the workspace, read frompackage-lock.json,pnpm-lock.yaml,yarn.lock,bun.lockandCargo.lock, with the source each was resolved from. - addedSecurity:
opi --securitylists theuses:references in.github/workflowsthat name a tag or branch instead of a 40-character commit SHA, with file and line. Local and Docker references are left out. - addedReleases: every release archive carries a signed build provenance attestation, and the release has a combined
SHA256SUMS. The README says how to verify a download withgh attestation verify. - addedRust:
cargo rustdocruns a second time with--all-featureswhere the manifest has a feature to turn on. A link from an always compiled item to one behind a feature resolves in the one feature set and not in the other — onrunemark,--all-featurespassed while the default set reported three errors. - addedRust: a package below the project root that belongs to no workspace, tied to the root by a path dependency, gets a test run of its own under its package name. Every workspace flag missed
runemark's Node binding, so its tests ran in CI and nowhere else. A manifest wired to nothing stays out, likeopi's owndemo/fixtures/pulse. - addedSBOM:
opi --sbom [dir]writes a CycloneDX JSON per ecosystem —sbom-npm.cdx.jsonvianpm sbomorpnpm sbom,sbom-cargo.cdx.jsonviacargo cyclonedx— todiror to.opi/sbom/in the project (which carries its own.gitignore), and names the tool to install where one is missing. With apackage-lock.jsonthe npm document is read from the lockfile alone, so it needs nonode_modules. - addedDocs: the pages describing the codebase — project state, architecture, constraints, conventions, decisions — are on the project page, under The project, instead of being linked as raw markdown on GitHub. They already carried page frontmatter; the content glob never matched a file sitting directly in
docs/. Details: Project state. - changedDocs: the flow in Architecture is a chartlet diagram rather than a mermaid block, which the theme renders as highlighted source. It comes with a focus control, a data table and a light and a dark variant. Details: Architecture.
- changedDocs: the recordings on the project page's start page are readable at their size. The hero recording is made at about 55 columns for its column and at 43 for phones instead of shrinking the README's 95-column GIF, and the scenes under One key away have 50-column variants for phones.
- changedContributors: the site builds with chartlet
0.21.0instead of0.19.0, whose flow charts took neithersameRanknornotes— the two manifest discoveries stand side by side now, and the note on parsing sits beside them. - changedContributors:
demo/record.shrecords every scene in a fresh copy of the fixtures, so no scene sees the Cargo.lock or pre-push hook an earlier one left behind; it also finds the binary under a shared cargo target directory and pins castwright0.5.0. All recordings are made again with opi0.11.0. - fixedDocs: the README describes the health recording as five checks, the number it shows, instead of six.
- fixedDocs: the changelog shows its whole content on the project page again. The theme's parser ends an entry at the first blank line, so every entry written as several paragraphs lost all but the first — the measurements, the reasoning and the limits, which is most of what the entries said. Each entry is one paragraph now, and nothing is left outside a list item.
- fixedRust: the Docs check runs at a virtual workspace root.
cargo rustdocrefuses a manifest without a package, so Docs now runs once per member with-p <member> --all-features.
0.11.0
26 September 2026
- addedWorkflows: a push workflow,
opi --check push: every detected check, then the build, on a working tree that is clean and not behind its upstream branch. The build is the project's ownbuildscript (each member's in a workspace whose root has none) andcargo build --workspace --locked, run after the other checks and one at a time.releasebuilds too;commitstays fast. - addedWorkflows:
opi --hooksinstallsopi --check pushas the pre-push hook — in.husky/pre-pushwhere the repository has husky, otherwise wherever git keeps its hooks. Idempotent; an existing hook keeps its lines. - addedList: task runner files beside the manifest are named in the line under the heading (
also Makefile) —Makefile,justfile,Taskfile.yml, amise.tomlwith tasks. Named only, never read or run. - addedSecurity: three supply-chain lines for npm projects: registry signatures (
npm audit signatures, fails the run on a mismatch), the minimum release age (minimumReleaseAge/min-release-age, asked withconfig get), and a license overview for pnpm (pnpm licenses list --prod) naming copyleft and unlicensed packages. The last two only report.
0.10.0
25 September 2026
- addedHealth: a Lockfile check, in
opi --healthand both workflows: whether the lockfile still matches the manifests, asked of the package manager that wrote it with a command measured to change nothing. yarn gets none. Details: What is detected. - addedUpdates: bun projects are offered Choose in bun's own list, which hands over to
bun update --interactiveand runs the commit checks afterwards.bun outdatedprints a table and ignores--json, so there was nothing to offer before. Details: Taking the updates. - addedSecurity: yarn's audit output is read — a third shape beside npm/pnpm's and bun's, and the one manager that prints nothing at all when it finds nothing. Like bun it names only the vulnerable range, so its findings carry no remedy. Details: Three shapes behind one question.
- addedUpdates: yarn is still not read here. Yarn Berry dropped the
outdatedcommand entirely, so there is nothing to parse. - addedRust: an optional fifth Cargo check,
docs.rs:cargo docs-rs, where the subcommand is installed.Docsasks whether a crate documents cleanly; this asks whether the registry will render what the author meant. Details: What cargo docs-rs adds. - changedDocs: the manifest's
documentationfield points at casoon.github.io/opi instead of docs.rs, whose build fails for every binary-only crate. The link on crates.io led to an error page; it now leads to the documentation. Details: Crate. - fixedSecurity: a failed audit is no longer reported as clean. An audit stopped by a network error or a broken lockfile prints no report;
opinamed the reason but still ended with "Nothing to act on." and exited 0. Details: Exit codes. - fixedContributors: process tests in
tests/process.rsrun the built binary against stand-in package managers and check the argv, working directory and exit code at the boundary rather than the logic behind it. They found the audit exit code above.
0.9.0
23 September 2026
- addedUpdates: Decide per package offers every finding as a ticked line, majors among them — the case the two bulk lines cannot reach, since both skip majors on purpose. The safe ones start ticked and the majors do not. pnpm only, like raising ranges. Details: Taking the updates.
- addedRust: a fourth Cargo check,
Docs:cargo rustdoc -- -D warnings. rustdoc renders a doc comment as HTML, so a bare<iframe>in one ends the page. docs.rs served a truncated crate for months before anyone noticed. Details: Why rustdoc is a health check.
0.8.0
20 September 2026
- addedUpdates:
opi --updatesoffers to take what it found, and runs the commit checks on what comes back. The choice is staying inside the declared ranges against raising them, never majors, pnpm only. This reverses "updates are never applied", whose reason did not survive being measured. Details: Taking the updates. - addedUpdates: Rust is answered as well, through
cargo outdated. Two sections rather than one merged list, because "safe to take" orders within an ecosystem and not across two. Rust's section carries no next step, sincecargo updatewrites the lockfile. Details: Updates. - addedSecurity: bun's audit is read instead of saying it cannot be — a second shape behind the same call, and one that names only the vulnerable range, so its findings carry no remedy. Details: Three shapes behind one question.
- addedInstall:
install.sh, and release binaries for it to install — macOS and Linux,aarch64andx86_64, picked by platform and verified against their published checksum. Details: Install script. - fixedUpdates: a pnpm workspace's packages are seen. Asked at the root alone, pnpm answers
{}where that root declares no dependencies of its own, so--updatesreported "everything is current" over stale packages — a false acquittal, which is worse than no answer. Details: Limits. - fixedUpdates: a warning printed ahead of the JSON no longer breaks the read. pnpm writes its own warnings to stdout, so a slow registry put
‼ WARN‼ Request took 11084ms: …in front of the document and the area answered "could not read pnpm's output". It only showed up when the network was slow enough, which is why the first round of testing missed it. - fixedUpdates: a project without a
package.jsonno longer getsopi checks updates only for npm, which stopped being true. - fixedSecurity: the dependency question is answered for Rust as well, through
cargo audit, in its ownDependencies (rust)section. No severity is shown, because cargo-audit's JSON carries none. Details: Rust. - fixedSecurity: npm is no longer run in a project that has no
package.json, in--securityor in--updates. The npm fallback holds a value even where nothing signalled npm, so a Rust-only project gotnpm audit --jsonrun in a directory with no manifest. Both areas now say there is nothing here they can audit, which is the one thing an empty section cannot say. - fixedProject: in a Cargo workspace,
opistarted inside a crate works on the workspace rather than on that crate.opi --cleanhad been looking fortarget/inside the crate, where it is not. Details: Workspaces. - fixedProject: a Bun project is recognised by
bun.lock, not only by the binarybun.lockbit stopped writing in 1.2. Only the old name was in the lockfile table, so a Bun project without apackageManagerfield fell through to the npm fallback — andopi buildrannpm run buildin a repository that has no npm in it. - fixedUpdates: bun's and yarn's output is reported as unreadable instead of failing on it. Both were parsed as npm's shape, so the screen ended in a parse error that read like a broken project rather than a missing feature.
--securityhad this guard from the start.
0.7.0
20 September 2026
- changedList: workspace packages share one
Packagestab instead of taking one each, with a divider in front of it. One tab each does not scale, and it put two different questions side by side as peers. Every tab is an action now, except the one the divider marks as something else. Details: Tabs for long lists.
0.6.1
20 September 2026
- fixedCrate:
0.6.0did not compile on Rust1.85, the version this crate declares. The cause was in runemark0.7.0, which used aletchain — stable only from1.88— for the tab digits. Requires runemark0.7.1.
0.6.0
20 September 2026
- addedList: past 15 entries or 5 groups the start screen shows the groups as a row of tabs and lists only the active one.
←→,Taband the digits1–9switch groups,/still searches every group, andopi ↵still runsdev. Details: Tabs for long lists. - addedList: a line under the heading says what was found:
43 entries · 10 groups · 3 packages. Two of those three are no longer on screen at once once the groups are tabs, and packages are named only where there are any. - addedCrate: both need runemark
0.7(Layout::Tabs,Menu::with_summary), where the interactive path lives.
0.5.3
19 September 2026
- fixedSecurity: the audit's severity counts are legible without colour. They carried a tone, which is nothing in a pipe or in CI, so
high: 1read exactly like a clean count; they now render as[FAIL] high: 1(runemark 0.6).
0.5.2
19 September 2026
- changedSecurity: the dependency audit and the update list render as runemark
Reports. The split between safe and breaking updates is now two groups rather than a sentence under a flat list, severity counts are metrics, and an advisory's fixed version range is a remedy. - changedHealth: health, the workflows and the secret scan keep printing their tool's own output, which was settled by trying the alternative: a relayed blob in one
Findingcollapses the tool's structure, and oneFindingper line flattens its indentation and counts lines as if they were findings.
0.5.1
19 September 2026
- fixedDocs:
opi --helpsaid entries come frompackage.json, which stopped being the whole truth whenCargo.tomlwas added in0.5.0. It now names both, and mentions the<member>/<script>form, which was undocumented. - fixedDocs: a full pass over the README and
docs/against the code turned up eleven statements the implementation no longer supported — among them atazeadapter that was never built, a diff preview before writing that does not exist, anopi.healthkey that is not read, and a claim that raw mode is restored on a signal, three lines below the sentence explaining that it is not.
0.5.0
19 September 2026
- addedRust: Rust projects.
Cargo.tomlis discovered the same waypackage.jsonis, and its commands join the same list, groups and search. Health gainscargo fmt --check,cargo clippyandcargo test; clean gainstarget/. Details: Cargo projects. - addedProject: a repository can be both at once, and neither wins. Measured across 231 directories: 133 carry a
package.json, 51 aCargo.toml, and twelve both. - addedProject: a repository with only a
Cargo.tomlis now a project. 39 of them were previously turned away with "No package.json found". - addedProject: .NET is deliberately not built: it appeared in none of those directories on its own, and building for a marker nobody has is what retired Knip and taze earlier.
0.4.0
19 September 2026
- addedScripts: per-script metadata in the
opikey ofpackage.json:description,group,favoriteandconfirm. None of it is required. Details: Per script. - addedScripts:
descriptionthere wins overscripts-infowithout invalidating it. Both may name the same script; that is how a project says something toopiwithout changing whatnrandnpm-scripts-inforead. - addedScripts:
groupreplaces the group a script's name implies. A nameopialready knows takes that group's fixed place in the order, so configuration refines the meaning-first arrangement rather than dropping out of it. - addedScripts:
favoritelifts a script out of its group into a Favorites group at the top. Sorting it first *within* its group would barely show — measured on a real project, five of ten groups held two entries. A favourite in a workspace member stays with its member: lifting it into the root's Favorites would lose which package it belongs to. - addedScripts:
confirmasks before running. Without a terminal it refuses rather than assuming yes, since skipping the question where it cannot be asked would remove the protection in exactly the case it exists for.--yessays it out loud instead.
0.3.0
19 September 2026
- addedHealth:
H/--healthruns every check the project's tools can answer, concurrently.opireimplements none of them: it detects the tool, runs it, and relays the result. Checks run per workspace member, in the member — a monorepo keeps TypeScript and its test runner in the packages, and pnpm does not hoist their binaries. - addedSecurity:
S/--securityscans for secrets and parses the package manager's audit into package, severity and the version that fixes it. - addedUpdates:
U/--updateslists what is outdated, split into safe and major. A pre-1.0 minor counts as breaking, as does a version that does not parse. Applying updates is deliberately left to the package manager: rewritingpackage.jsonand a lockfile — which with pnpm catalogs may not even hold the versions — is not a guess worth making. - addedClean:
C/--cleanshows removable artefacts with what each costs, and removes build output without ever bundlingnode_modulesalong with it. - addedWorkflows:
--check commitand--check releaserun named subsets plus repository gates: a clean tree and an untagged version before a release. - addedList: the five areas each take a hotkey in the list and a flag on the command line — never a bare word, since
health,cleanandreleaseare script names in real projects. - changedList:
deploy,release,clean,setupand similar standalone names now have Deploy and Maintenance groups instead of the catch-all, which halves it. - changedList: npm's own lifecycle scripts are hidden —
prepareappeared in 49 of 133 measured projects — but remain runnable by name. - changedHealth: two adapters in the plan were replaced by what the measurements found: Knip was present in 1 of 133 projects against fallow's 11%, and
tazein none at all, while every package manager shipsoutdated.
0.2.0
19 September 2026
- addedList:
/filters the list as you type. Groups with nothing left disappear and the cursor sits on the best match (runemark 0.5.1). Details: Searching. - addedList: the footer shows
/ search, so the key is discoverable rather than folklore.
0.1.1
19 September 2026
- changedList: a workspace member's script is no longer listed when the root defines one by the same name. The root wins that name on the command line anyway, so listing both offered a choice the interface could not honour. Details: Workspaces.
- fixedList: entries are fitted to the terminal width instead of wrapping to column zero, which destroyed the two-column layout (runemark 0.4.2). Found by running
0.1.0against a real project. Details: Tabs for long lists.
0.1.0
19 September 2026
- addedList: an interactive list of the project's scripts, grouped by the prefix before the first
:and labelled fromscripts-info. Group order is meaning-first, not alphabetical. A list taller than the terminal scrolls. This is the first release that does something:opimakes a project'spackage.jsonscripts immediately runnable, while the maintenance areas are designed but not built. - addedScripts:
opi <script>runs one directly, forwarding any further arguments. Scripts take precedence over built-in names, so a project with a script calledhelpkeeps working. Details: Unix only. - addedProject: package manager detection from the
packageManagerfield or a lockfile, searching upwards. Where neither exists the npm default is marked as a fallback rather than presented as a detection. - addedProject: monorepo support: the nearest
package.jsonis found by searching upwards, and a workspace root also offers each member's scripts under the member's name.opi blog/devaddresses a member, since root and member scripts share names in practice. - addedScripts: suggestions for a mistyped script name. Details: Parsing rules.
- addedScripts: lifecycle hooks npm runs on its own are hidden when their main script exists.
0.0.1
18 September 2026
- addedCrate: a placeholder release, reserving the crate name on crates.io and establishing the repository skeleton. The binary prints its version and a development notice; no functionality is implemented.