Repository navigation
Releases: onushq/onus
Release list
Onus v0.11.0
The manifesto's gaps, closed: every agent call checked and logged, scoped Onus Cloud tokens, escalations and a blocked channel, risk inputs and a learned model that only raise lanes, held-out suites from the map, a behaviour diff, coverage, the production loop, a human lane that waits for an owner, and one provenance record per change.
- The door log and Onus Cloud's calls reach the provenance of changes made through Onus Cloud and CI (
onus help provenance): an agent attaches its task's slice of the door log to its pull request withonus_cloud_attach_evidence(doorLog: true; the server cuts the slice from its own log) oronus cloud evidence <pull> --door-log --task <task>(--runis now optional). The slice is the run of entries from the task's first to its last (newschemas/door-log.schema.json). Throughonus mcp --tokenit carries the door's inspection of the token it holds, never the token, so a change made through Onus Cloud by an agent that never escalated has its token on record (newtoken.source: attached, ranked below every other source). Onus Cloud passes these on once it keeps them; an older one refuses a door log on its evidence route.onus ci prgains--audit FILE, andonus provenance --auditreads the slice as well as a whole log. The chain is checked over the slice from its first entry; the record keeps the task's entries withdoors.source: attachedand whether they verified. A slice that does not verify is recorded as not intact, with the entries of the task it names and the reason in thedoorsgap; one of another task keeps no entries and the gap names both tasks. A slice is the agent's word, since anyone can build one that verifies: thedoorsgap stays, narrowed to say so. Its decisions on escalations count only when it verifies and is the change's, and Onus Cloud's decision is recorded over them whatever its state, theescalationsgap naming any disagreement. A door log that does not verify, a slice or a whole log, no longer gives the token or the task. A door log that holds nothing of the change's task, or reaches a run that does not know the task, leaves thedoorsgap;onus ci prgains--task.onus ci prandonus provenancegain--calls FILE: Onus Cloud's log of the calls made under the task token (newschemas/cloud-calls.schema.json; the API's{"calls": [...]}withcreatedAtandcredentialIdis read too). The record sums them up indoors.calls, markedsource: onus-cloud: totals, the counts for each route and scope by decision, the token ids, and every denial (at most 100). Calls that name no task are counted as the change's and shown asuntasked; with no task known, thedoorsgap says every call given was counted. Calls alone leave thedoorsgap, narrowed: they are Onus Cloud's word, not the agent's door log.onus ci pr --submission FILEtakes the agent's own submission: the record keeps its token (token.source: agent-submission) and the escalations it lists, when it is for one of the pull request's commits.- The action gains a
submissioninput, and otherwise finds one on the records branch atsubmissions/<pull request number>.jsonorsubmissions/<head commit>.json, forci prand, through the newonus provenance --agent-submission FILE, for the provenance rebuilt at close. Both take only its token and escalations, and only when it is for one of the pull request's commits.onus ci records pullcopies those into the records folder, and a push keeps whatever else is on the branch.onus help cisays what the action cannot know: the token itself, the door log, and what Onus Cloud keeps. - Onus Cloud keeps the slices agents attach and passes one cut at the head with
--audit(the change's task's, and the first attached, so a later slice cannot displace the agent's), the calls made under the change's scoped token with--calls, and, when no escalation or slice gave the door's inspection, the scoped token's own with--token-inspection. Its pages label the token sourcesagent-submissionandattached. Known gap: an attached slice is the agent's word, so thedoorsgap stays in every hosted run, narrowed to say so. - None of this input stops
ci pr, and a door log or calls file that cannot be read stopsonus provenanceneither: each is a warning and a gap. Only the fields named are read from a call; the API's others (path,userAgent,credentialName) never are. A call with atoken, or a field read that looks like one (an Onus Cloud token or API key, a PASETO, a Biscuit), is left out with a warning that names the field, never the value. - A token from the agent's submission is marked
token.source: agent-submissionand ranks below the door's word (audit,inspection): it is plain JSON, possibly from the records branch, so the record takes it on its word. The escalations it lists are recorded as granted until Onus Cloud says otherwise, and theescalationsgap says they are its word. An attached slice cut at a commit that is not one of the change's (itshead), or that names none, gives neither the task, the token nor any decision, and thedoorsgap says so. A door log is attached only to the pull request whose head in Onus Cloud is the worktree's commit, so an agent cannot attach its slice, and the other tasks' entries in it, to another change.
- Provenance records the escalations and token Onus Cloud kept (
onus help provenance):onus ci prandonus provenancetake--escalations FILE, Onus Cloud's escalations with their decisions (newschemas/escalation-decisions.schema.json), and--token-inspection FILE, the door's inspection of the task token ({task, rights, expires}, never the token). So a change made through Onus Cloud has itstokenandescalationson record instead of as gaps.- Each escalation keeps its decision, who made it and when, and Onus Cloud's id as
cloudId. It is joined to the request the submission or the door kept. Itsreasonis the decider's, never why the agent asked. - The
tokencomes from the inspection, widened by what Onus Cloud granted to the task, with the new sourceinspection. A token verified by the run, a submission's scope or the door log comes first. - Only the change's escalations are kept: those on its pull request, listed by its submission, kept by an earlier record, or filed at one of its commits, its branch or its pull request's head ref (new
refandcommit); others only when they share the change's task. An escalation that names none of these never sets the change's task or its token. - A final decision from the submission or the door log stands against one Onus Cloud has not made. When both are final and differ, Onus Cloud's is recorded and the
escalationsgap names the disagreement. - An empty list from Onus Cloud is on record, so
escalationsis not a gap. An escalation that cannot be read is left out with a warning and a gap that names the field, never the value. An inspectionci prcannot read is named in thetokengap. Only a token given in place of its inspection stopsci pr, before anything is written. onus provenance --escalationsstill reads a folder of requests, and fails on a path that does not exist. With a file and--submission-id, it reads the kept requests too.--verifychecks the new fields like any other. Dates that do not exist, such as month 13, are no longer read as times.
- Each escalation keeps its decision, who made it and when, and Onus Cloud's id as
- Area history for one repository (
onus help production):onus signals areas --repository owner/namecounts only that repository's changes, and the signals tied to no change, as a classification of one of its changes reads them. Onus Cloud keeps one records folder per organisation and shows each repository its own areas this way. - The action waits for a review in the human lane, and an owner's approval is the one that counts (
onus help ci,onus help lanes): withrecords: true, the action lists the pull request's reviews with the GitHub CLI, and the members of each owning team when its token can read them, and passes them toonus ci pr --reviews. It asks the ownersonus ci prnames to review (GitHub's requested reviewers), each once per pull request. While a human-lane change has no review that counts, the job fails (new inputwait-for-review, defaulttrue; new outputreview:waitingorapproved). It also runs onpull_request_review, and after an approval re-runs the failedpull_requestcheck for the head, so the human lane waits without Onus Cloud too. Addpull_request_reviewto the workflow's events and make the job a required check. The newlanes.approvalsays whose approval counts:owner(the default when the change has owners) counts only a person named as an owner or a member of an owning team;member(the default when nobody owns it) counts anyone with write access. The rule and the owners are read at the base commit: the owners of each changed file's component in the base onus.yaml (an explicit--configinside the repository is read at the base too), else CODEOWNERS at the base, rather than the report'shints.owners, which come from the head. So a change can neither loosen the rule nor name its own approver. Newonus ci ownersprints those owners, so a host can look up owning teams first. The rule applies in the human lane only; other lanes keep every approval with write access, for provenance. When an owner cannot be checked (a team whose members the reviews file does not list, or an email), or no owner but the author could approve, anyone with write access counts and the review'snotesays why. A name GitHub refuses to ask is a warning and a line in the comment. Reviews on closed pull requests do nothing. The--reviewsfile may now be{"reviews": [...], "teams": {"@org/team": [logins]}}. Thereviewanswer gainsapprovalandnote; the pull record and the outcome keepapproval, and the provenance record `approv...
Onus v0.10.0
Track records that fill themselves in, and agents that work through Onus.
- Agents hand work in through MCP (ADR 0012,
onus help agents):onus mcpaddsonus_env_create,onus_env_run,onus_envs,onus_env_destroy,onus_evidence,onus_run_test,onus_submit,onus_judge,onus_escalate,onus_escalation,onus_lanesandonus_outcomes. Agents cannot record outcomes, grant escalations, mint tokens or choose their scope;--no-actionsleaves the tools out. Submissions are kept in.onus/submissions/and shown inonus ui; granted escalation tokens are kept beside their request for the agent to collect. - Outcome records kept by CI (ADR 0013,
onus help ci): withrecords: true, the GitHub Action classifies every pull request with its agent setup's track record, records the outcome when it closes and reverts when the default branch moves, all on anonus/recordsbranch of the repository. People record approvals, audits and incidents with/onus approve <row>,/onus audit ok|missand/onus incident <note> involved: …comments (write access only); an approval re-runs the check. The agent setup is read from anOnus-Agent:trailer, the branch name, the bot author or aCo-authored-bytrailer. Newonus ci pr|closed|comment|push|recordscommands do the work and run in any CI system. An incident now counts against its agent setup even after the change is reverted. - An outcomes dashboard in
onus ui: readsorigin/onus/recordswhen there is no local file, and shows changes by week and lane, each agent setup's progress toward auto-merge, and the pull requests in flight. - A better map in
onus ui: pan and zoom, a layout by folder beside the layers, focus on a component with one or two steps of neighbours, filters for imports, calls and types, a side panel for the selected component, and a treemap of the repository by folder and size.
Install
brew install onushq/tap/onus
curl -fsSL https://onushq.com/install.sh | shOr in a workflow: uses: onushq/onus/action@v0.10.0. Each archive is attested: gh attestation verify <archive> --repo onushq/onus.
Onus v0.9.0
A web interface for everything Onus does.
onus ui: a web interface for the repository, embedded in the binary and served on 127.0.0.1 behind a per-session token (ADR 0011,onus help web-interface): a dashboard with the component graph, a command palette (⌘K), and light and dark themes. It covers the component graph and every component, symbol and file (dependents, dependencies, tests, invariants and the impact of a change); reports of uncommitted work and of any two refs; the lane policy, submissions, classification and the judge; environments, runs and the evidence store; outcomes, incidents and reverts; root keys, task plans, minting, inspecting and narrowing tokens; escalations; the audit log; onus.yaml; and the guide.- JUnit results are counted by their
<testcase>elements, so reporters that write no suite totals (such as Node's) are counted. - Lane and judge reasons quote row titles instead of wrapping them in backticks, which broke the code spans inside them.
Install
brew install onushq/tap/onus
curl -fsSL https://onushq.com/install.sh | shOr in a workflow: uses: onushq/onus/action@v0.9.0. Each archive is attested: gh attestation verify <archive> --repo onushq/onus.
Onus v0.8.0
Phase 5 complete: environments, the evidence store, traces, the production loop and contract-level scopes (ADR 0010, onus help environments).
- Environments:
onus env create|run|list|destroybuilds a container from a commit andenvironment:in onus.yaml (or the devcontainer). Setup runs once per lockfile and is kept as a warm image; a seed command loads synthetic data. There is no network unless the task's token names hosts, and then only through an egress proxy that allows exactly those hosts. Secrets the token names come fromONUS_SECRET_<NAME>and are redacted from everything stored. - The evidence store: each run leaves a manifest and its artifacts (the log, JUnit XML, OTLP traces) under their sha256 in the repository's git directory;
onus evidence list|showreads it.onus env runprints a test run foronus submit --evidence, and the judge checks it against its manifest. - Traces feed the map:
--traces <otlp.json>ononus map,diffandreportaddstracedcall edges from OpenTelemetry spans, such as an event bus dispatching to a handler. - The production loop:
onus outcomes ingest-revertsfinds reverts in git history,onus outcomes incidentrecords incidents, and--result rolled-backrecords flags turned off and rollbacks. Reverted changes leave an agent setup's record, a recent incident stops it from auto-merging, andonus outcomes backloglists where held-out tests should go. - Contract-level scopes: plans can name
writeComponents(notifications.internal),readContractsandescalateBefore: ["contract:*"];onus token mint --reporesolves them through the map, and the gateway refuses changes to guarded contract files without a granted escalation.
Fixed
onus run-testand the judge's re-runs saw an empty tree with container engines that run in a VM (colima, podman machine), which do not share the host's temporary directories. The commit's files are now copied into the container instead of mounted.
Install
brew install onushq/tap/onus
curl -fsSL https://onushq.com/install.sh | shOr in a workflow: uses: onushq/onus/action@v0.8.0. Each archive is attested: gh attestation verify <archive> --repo onushq/onus.
Onus v0.7.0
Phase 4 complete: risk lanes and the verifying judge (ADR 0009, onus help lanes).
onus submitbundles a change for review: the intent, Onus's report, changed paths, test runs to re-run, the token's scope, escalations, approvals and the agent setup, and nothing of the author's reasoning.onus classifyputs a change in a lane (auto-merge,judge,human,blocked). The lane comes from a policy in onus.yaml (lanes:) and hard floors no policy can lower: secrets, out-of-scope writes and unapproved weakened tests are blocked; sensitive code, rules of the game and intent mismatches go to a person. New agent setups cannot auto-merge, and a share of auto-merges is audited by a person.onus judgeverifies before it judges: it re-runs the evidence in containers, then checks intent, contracts and tests, then runs held-out checks. An optional taste reviewer can raise concerns but never approve. The verdict is approve, reject (with reasons the agent can act on) or escalate.- The action's
lanes,apply-laneandauto-mergeinputs show the lane, label the pull request, fail blocked changes and enable GitHub's auto-merge. onus outcomes record|summarytrack outcomes per agent setup and judge configuration, including the audit miss rate and the human-lane share.
Install
brew install onushq/tap/onus
curl -fsSL https://onushq.com/install.sh | shOr in a workflow: uses: onushq/onus/action@v0.7.0. Each archive is attested: gh attestation verify <archive> --repo onushq/onus.
Onus v0.6.0
Phase 3 complete: scoped tokens, enforcing doors and evidence-based escalation (ADR 0008, onus help scopes).
- Task tokens:
onus token keygen|mint|attenuate|inspect|checkmint Biscuit tokens from task plans (writes, reads, hosts, secrets, refs, ttl). Holders can narrow a token for a sub-agent but never widen it.onus scope suggestproposes reads from the map, leaving out sensitive components. - The git gateway:
onus gateway servegives each task a mirror holding only what it may read. It refuses pushes that change anything outside the write scope, with an error that says how to ask, and replays accepted commits onto the real repository with a credential the agent never holds. A red-team test suite is the gate: zero out-of-scope writes. - Read scope for the map:
onus mcp --tokenanswers only about files the task may read. - Escalation:
onus escalaterecords a structured request with graded evidence, the blast radius and sensitive labels.onus escalation decidegrants low-risk requests automatically when a failing test is reproduced byonus run-test(a container with no network);grantanddenyare for people. - Audit: every decision is a hash-chained JSON line;
onus audit <log>checks the chain.
Install
brew install onushq/tap/onus
curl -fsSL https://onushq.com/install.sh | shOr in a workflow: uses: onushq/onus/action@v0.6.0. Each archive is attested: gh attestation verify <archive> --repo onushq/onus.
Onus v0.5.0
Phase 2 complete:
onus_impact(onus query impact <target> --change remove|rename|change-signature|add-required-member|change-behavior): before a change, the files that break or need a check, one site each (for a new required member only the implementations, found in the source text), and the tests that exercise the target.onus_invariants(onus query invariants [target]): the invariants onus.yaml declares.onus mcp --http <addr>: the MCP tools over streamable HTTP. Only loopback host names are answered unless--allow-hostadds one; every tool answers the same over stdio and HTTP.scripts/benchmark-references.mjs: compares the map's dependents with the TypeScript compiler's find-all-references. Recall is 1.000 on the fixture and 0.999 on Twenty (benchmark).
Install
brew install onushq/tap/onus
curl -fsSL https://onushq.com/install.sh | shOr in a workflow: uses: onushq/onus/action@v0.5.0. Each archive is attested: gh attestation verify <archive> --repo onushq/onus.
Onus v0.4.1
- From replaying every commit of three SvelteKit and TypeScript monorepos:
- Private declarations that share a name or a small body in different files are no longer reported as renames or moves.
- A type that only gains optional parameters or fields is a compatible change (
contract-type-widened). - Drizzle migrations are recognized, with the indexes they create.
- Awaits merged into
Promise.all, rewritten away or deduplicated are not "removed". - Guards that moved with renamed variables are matched by their shape.
- A new package added to several components is one row.
- Route rows name their component, and first-use rows skip
$appand$env.
--markdown-out <file>writes the Markdown report alongside the JSON, so the action runs each report once instead of twice.- The action's
pluginsinput passes a plugins file (such as the Svelte plugin) without reading it from the analyzed repository.
Install
brew install onushq/tap/onus
curl -fsSL https://onushq.com/install.sh | shOr in a workflow: uses: onushq/onus/action@v0.4.1. Each archive is attested: gh attestation verify <archive> --repo onushq/onus.
Onus v0.4.0
M7 tuning, from an audit of reports on 20 large real pull requests: fewer wrong facts, flags on the changes that need a person, less noise, faster reports. Audited again afterwards, rows with wrong facts went from 7% to under 1% and the reviewers' usefulness score from 2.1 to 3.0 out of 5 (evaluation). A regression corpus (crates/onus-cli/tests/corpus) reproduces each kind of mistake with invented code and keeps it fixed.
- Fewer false alarms:
- A contract change is breaking only when a user or implementation outside the change was not updated. Casts (
as X) no longer count as implementations; published packages and packages with unresolved imports stay breaking. - Types are compared with object and union members sorted, so regenerated code that only reorders is no change.
- An await, guard or throw that moved into another function (a body extracted into a helper) is not reported as removed.
- Tests that moved, or went with the code they tested, no longer read as weakened; the latter get a quiet
tests-removed-with-coderow. - Imports of package subpaths (
pkg/utils) resolve throughexports, mapping build output back to source, so users of shared packages are no longer missed. - Lockfile rows list the installed versions that change, or say none do (patch hashes and checksums are not versions).
- First-use rows skip Node's built-in modules and APIs already used through a namespace.
- A contract change is breaking only when a user or implementation outside the change was not updated. Casts (
- Flags by risk class, each its own row that needs a person: migrations (with what they do to stored data), GraphQL operations (separately when they skip authentication), HTTP routes from file-based routing and controllers, authentication and authorization code, patched dependencies, root build config and infrastructure. Rows that need a person rank first.
- Less noise: generated code is one quiet row per component; config rows name the keys or Dockerfile instructions that changed; build-tool and workspace files have their own classes instead of "runtime configuration"; widespread config edits are grouped by the keys they change.
- Faster reports:
onus reportcompares only the paths git reports as different, writes both trees on all cores, shares parsed facts between the two maps, and with a cached base map extracts only the base's changed files. On a 31,000-file repository a report takes about 22 s instead of 29 s, and about 12 s with the cache.
Install
brew install onushq/tap/onus
curl -fsSL https://onushq.com/install.sh | shOr in a workflow: uses: onushq/onus/action@v0.4.0. Each archive is attested: gh attestation verify <archive> --repo onushq/onus.
Onus v0.3.0
- Sharper reports and
onus_check:- Untyped values are compared key by key (
Schema.struct({...}),z.object({...}), object literals), and union types member by member. - Changes Onus cannot compare are one low-confidence row instead of a "may have changed" row each.
- Production code that uses an API of an already-used package for the first time is reported with the pinned version.
- Breaking contract rows name the implementations and test doubles not updated.
- Changes in components of more than 300 files name their module folders.
- Untyped values are compared key by key (
onus_checkfor agents: it returns a checklist of what to verify before finishing, and states what it does not verify, so a clean result is evidence, not approval.- The map for coding agents (experimental):
onus mcpserves the map of a worktree as MCP tools (onus_status,onus_find,onus_symbol,onus_dependents,onus_dependencies,onus_tests_for,onus_owners,onus_component,onus_file,onus_check), andonus queryasks the same questions from a shell. Every agent and worktree of a repository shares one map server, which follows file changes and re-parses only changed files, sharing per-file facts across worktrees (ADR 0007). An evaluation found no measurable gain from the navigation tools for agents implementing features, so they are marked experimental and Phase 2 focuses ononus_check. onus findranks symbols by how many query words match (name, then fields and parameters, then path), finds the types that declare a field, and always lists matching files, instead of returning nothing unless every word was in one name.- Mapping a large monorepo is about 25% faster (4.6 s to 3.5 s on Twenty's 31,000 files) with byte-identical maps: public methods are found without a quadratic scan, components are matched with one glob set, packs compile once per process, the file walk is parallel and module resolution is cached.
- The Homebrew tap is updated by a reusable
Homebrew tapworkflow that the release calls. Run it by hand to re-sync the tap, or as a dry run to check thatHOMEBREW_TAP_TOKENcan still push. Release notes include thebrew installline.
Install
brew install onushq/tap/onus
curl -fsSL https://onushq.com/install.sh | shOr in a workflow: uses: onushq/onus/action@v0.3.0. Each archive is attested: gh attestation verify <archive> --repo onushq/onus.