opiv0.14.0

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.0 and the recordings are rendered with castwright 0.6.0; the architecture diagram is drawn 605 pixels wide, the width chartlet asks for.

0.14.0

9 November 2026

  • addedUpdates: --updates lists 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: --json with --health, --security, --updates and --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_COLOR no longer switches colour off and TERM=dumb does, 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 to pnpm update --latest after --.
  • fixedUpdates: Yarn Berry now says it has no outdated command and points to yarn upgrade-interactive, instead of claiming opi cannot read its output.
  • fixedUpdates: an unreachable registry with yarn classic shows the error text instead of yarn's raw JSON error line.
  • fixedCLI: --list-names skips script names that contain control characters.
  • fixedInstall: Cargo.toml carries [package.metadata.binstall] matching the release archive names, so cargo binstall opi fetches the release binary instead of compiling.
  • securityJSON: the output of a Secrets check 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 sbom refuses a project because package.json has no version, opi --sbom says so instead of passing on npm's EINVALIDPURLTYPE line.

0.13.3

1 November 2026

  • fixedSecurity: the remedy for an npm finding names the version npm audit fix would install, instead of the vulnerable range (update to <=4.17.23 for lodash, now update to 4.18.1).
  • fixedSecurity: the license line of an npm project is read from package-lock.json, so it no longer fails where package.json has no version and npm sbom refuses the project.
  • fixedSecurity: a project without dependencies shows Licenses — no dependencies instead 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: tsc runs only where the package has a tsconfig.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 rustdoc refused 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: --checks selects checks and builds per workflow in .opi/checks.json; --check deploy runs 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 opi in 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: runemark 0.9.1 and serde_json 1.0.154.

0.12.0

27 October 2026

  • addedReleases: the binaries are built with cargo auditable, so cargo audit bin can 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 --security also covers npm and bun projects (from npm sbom) and Cargo projects (from cargo metadata), production dependencies only, with the same notable licenses as for pnpm.
  • addedSecurity: opi --security adds a Dependencies (osv) section from osv-scanner, which reads the npm, pnpm, yarn, bun and Cargo lockfiles against the OSV database. It runs alongside npm audit, cargo audit and the others and shows only the packages they did not report; without osv-scanner the section says so.
  • addedSecurity: opi --security lists the installed dependencies that declare preinstall, install or postinstall scripts and whether the project allows them — pnpm's onlyBuiltDependencies / ignoredBuiltDependencies, bun's trustedDependencies, npm's ignore-scripts. Scripts nothing has decided on are named.
  • addedSecurity: --security lists dependencies that come from git, a tarball URL or a path outside the workspace, read from package-lock.json, pnpm-lock.yaml, yarn.lock, bun.lock and Cargo.lock, with the source each was resolved from.
  • addedSecurity: opi --security lists the uses: references in .github/workflows that 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 with gh attestation verify.
  • addedRust: cargo rustdoc runs a second time with --all-features where 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 — on runemark, --all-features passed 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, like opi's own demo/fixtures/pulse.
  • addedSBOM: opi --sbom [dir] writes a CycloneDX JSON per ecosystem — sbom-npm.cdx.json via npm sbom or pnpm sbom, sbom-cargo.cdx.json via cargo cyclonedx — to dir or to .opi/sbom/ in the project (which carries its own .gitignore), and names the tool to install where one is missing. With a package-lock.json the npm document is read from the lockfile alone, so it needs no node_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.0 instead of 0.19.0, whose flow charts took neither sameRank nor notes — the two manifest discoveries stand side by side now, and the note on parsing sits beside them.
  • changedContributors: demo/record.sh records 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 castwright 0.5.0. All recordings are made again with opi 0.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 rustdoc refuses 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 own build script (each member's in a workspace whose root has none) and cargo build --workspace --locked, run after the other checks and one at a time. release builds too; commit stays fast.
  • addedWorkflows: opi --hooks installs opi --check push as the pre-push hook — in .husky/pre-push where 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, a mise.toml with 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 with config 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 --health and 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 --interactive and runs the commit checks afterwards. bun outdated prints 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 outdated command entirely, so there is nothing to parse.
  • addedRust: an optional fifth Cargo check, docs.rs: cargo docs-rs, where the subcommand is installed. Docs asks 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 documentation field 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; opi named the reason but still ended with "Nothing to act on." and exited 0. Details: Exit codes.
  • fixedContributors: process tests in tests/process.rs run 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 --updates offers 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, since cargo update writes 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, aarch64 and x86_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 --updates reported "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.json no longer gets opi checks updates only for npm, which stopped being true.
  • fixedSecurity: the dependency question is answered for Rust as well, through cargo audit, in its own Dependencies (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 --security or in --updates. The npm fallback holds a value even where nothing signalled npm, so a Rust-only project got npm audit --json run 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, opi started inside a crate works on the workspace rather than on that crate. opi --clean had been looking for target/ inside the crate, where it is not. Details: Workspaces.
  • fixedProject: a Bun project is recognised by bun.lock, not only by the binary bun.lockb it stopped writing in 1.2. Only the old name was in the lockfile table, so a Bun project without a packageManager field fell through to the npm fallback — and opi build ran npm run build in 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. --security had this guard from the start.

0.7.0

20 September 2026

  • changedList: workspace packages share one Packages tab 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.0 did not compile on Rust 1.85, the version this crate declares. The cause was in runemark 0.7.0, which used a let chain — stable only from 1.88 — for the tab digits. Requires runemark 0.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. ← →, Tab and the digits 1–9 switch groups, / still searches every group, and opi ↵ still runs dev. 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: 1 read 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 Finding collapses the tool's structure, and one Finding per line flattens its indentation and counts lines as if they were findings.

0.5.1

19 September 2026

  • fixedDocs: opi --help said entries come from package.json, which stopped being the whole truth when Cargo.toml was added in 0.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 a taze adapter that was never built, a diff preview before writing that does not exist, an opi.health key 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.toml is discovered the same way package.json is, and its commands join the same list, groups and search. Health gains cargo fmt --check, cargo clippy and cargo test; clean gains target/. Details: Cargo projects.
  • addedProject: a repository can be both at once, and neither wins. Measured across 231 directories: 133 carry a package.json, 51 a Cargo.toml, and twelve both.
  • addedProject: a repository with only a Cargo.toml is 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 opi key of package.json: description, group, favorite and confirm. None of it is required. Details: Per script.
  • addedScripts: description there wins over scripts-info without invalidating it. Both may name the same script; that is how a project says something to opi without changing what nr and npm-scripts-info read.
  • addedScripts: group replaces the group a script's name implies. A name opi already knows takes that group's fixed place in the order, so configuration refines the meaning-first arrangement rather than dropping out of it.
  • addedScripts: favorite lifts 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: confirm asks 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. --yes says it out loud instead.

0.3.0

19 September 2026

  • addedHealth: H / --health runs every check the project's tools can answer, concurrently. opi reimplements 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 / --security scans for secrets and parses the package manager's audit into package, severity and the version that fixes it.
  • addedUpdates: U / --updates lists 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: rewriting package.json and a lockfile — which with pnpm catalogs may not even hold the versions — is not a guess worth making.
  • addedClean: C / --clean shows removable artefacts with what each costs, and removes build output without ever bundling node_modules along with it.
  • addedWorkflows: --check commit and --check release run 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, clean and release are script names in real projects.
  • changedList: deploy, release, clean, setup and 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 — prepare appeared 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 taze in none at all, while every package manager ships outdated.

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.0 against 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 from scripts-info. Group order is meaning-first, not alphabetical. A list taller than the terminal scrolls. This is the first release that does something: opi makes a project's package.json scripts 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 called help keeps working. Details: Unix only.
  • addedProject: package manager detection from the packageManager field 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.json is found by searching upwards, and a workspace root also offers each member's scripts under the member's name. opi blog/dev addresses 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.