Releases: mifunedev/openharness
Releases Β· mifunedev/openharness
Release list
v0.7.0
Added
- Add
oh sandbox install docker: a wizard writes a sandbox registry entry under${OH_HOME:-~/.oh}/sandboxes/<name>/and boots it from any directory, with no project checkout. (#950) - Add
oh sandbox list [--json], reporting each registry entry's name, runtime, container status, and bound repo. (#950) - Add
--sandbox <name>tooh config show|setandoh secret set|list, which read and write a registry entry instead of the project root. (#950) - Add
microsandboxto the tool catalog:oh tool install microsandboxinstallsmsbunder${NPM_USER_PREFIX:-$HOME/.local}from a pinned installer. (#950)
Changed
- BREAKING:
oh updateis the bootstrap: it equips an empty checkout with.oh/andcrons/, writes nothing else, and never prompts. (#950) - BREAKING:
oh shell|stop|restart|logs|ps|destroytake an optional sandbox name, resolving name, then the single entry, then the entry containing the cwd. (#950) oh destroy <name>removes the registry entry afterdown -v, so the sandbox name becomes free again. (#950)docs/deployment-prebuilt-image.mdbecomes theoh sandbox install dockerpage: running the published image is now the default, and--repois the bind-mounted-checkout case. (#950)
Removed
- Remove boot provisioning and every install switch:
oh harness install <id>andoh tool install <id>are the only door. A fresh sandbox has no harness and noherdr. (#948) - BREAKING: Remove
oh init.oh sandbox install dockerowns sandbox configuration andoh updateowns the control-plane payload. (#950) - BREAKING: Remove
oh runtime. The runtime catalog lives underoh sandbox, andmsbis installed withoh tool install microsandbox. (#950) - BREAKING: Remove the
.oh/templates/scaffold payload. The CLI writes noAGENTS.md, provider config, or.gitignoreline beyond.env. (#950) - Remove
gvisorfrom the runtime catalog; the isolation-tier landscape lives indocs/rfcs/rfc-runtime-support.md. (#950)
v0.6.0
Added
- Add
spec-no-agent-handoff,spec-no-advisor-session-coupling,cleanup-no-agent-session-coupling,headless-tmux-preserved; renameadvisor-monitored-looptospec-single-owner(#928). - Add
.oh/skills/wiki/scripts/knowledge-impact.sh, the single dependency-aware invalidation primitive:--verifiedfor/wiki lint,--changedfor the/spec executeknowledge gate. (#926) - Add
evals-20260901-suite-tree-cleananddocs-20260901-followup-artifact-cited: no probe may redirect into the repository, and a criterion met by a follow-up must cite its URL. (#926) - Add ten tier-A probes covering the knowledge surface, the planning recall and reconciliation gates, the RUNNING contract, structured completion, and the retired vocabulary. (#926)
- Add
/escalate: an unattended session delivers a human-addressed escalation to the operator's Slack channel. An unavailable channel no-ops loudly rather than failing the session. (#919) - Add
.oh/logs/, gitignored by default with a tracked README, for records that outlive the session that wrote them;/escalateappends every attempt toescalations.jsonl. (#919) - Add
escalate-contract.sh, a tier-A probe: a no-op names its reason, is recorded, and--dry-runmakes no network call. (#919) - Add gate 5 to
/audit implementation: fail a promotable change while its diff can still be smaller. Measures net lines and per-function CCN on changed TypeScript viauvx lizard. (#912) - Add
audit-slop-gate.sh, a tier-A probe holding gate 5's termination contract: a finding needs a concrete smaller alternative, and the loop ends on the cap or a non-reducing round. (#912) - Add
/wiki compile, akind: patterncorpus layer, and an append-onlyskill-impact.mdledger, so a/retrolesson becomes a page/builderreads before proposing. (#916) - Add a
--patternsmode to/wiki querythat filters onkind:, reads up to five pattern entries, and ranks them by term-hit count before recency. (#916) - Add a fault-injection requirement to the probe contract: a probe is not green until its REGRESSION branch has been driven against a broken input. (#916)
- Add capability task
CB-005scoring whether a lesson reaches a validated skill change; two runs score 0.67 then 1.33, moving the suite mean to 1.44 over a changed task set. (#916) - Add
/architect, an inline architecture-decision skill that classifies significance, grounds analysis in repository sources, and returns one Architecture Brief (#929). - Add six tier-A probes covering the
/architectcontract, roles-as-skills, the retired builder agent type, the/delegateworker boundary, the absent agent catalog, and RFC/ADR reuse (#929).
Changed
- BREAKING: Move durable repository knowledge to a tracked
.oh/knowledge/surface βsource/,patterns/,raw/tracked,local/ignored β with no compatibility alias. (#926) - BREAKING: Make
/spec planrecall tracked knowledge and re-ground it before the PRD;prd.mdcarries Knowledge Context, Expected Knowledge Impact, and Plan Reconciliation. (#926) - BREAKING: Derive final knowledge impact in
/spec executefrom the actual diff plus page dependencies, resolving every impacted page to UPDATED, REVERIFIED, or NOT-AFFECTED. (#926) - BREAKING: Replace age-based wiki staleness with source-change freshness: a
kind: repopage pinsverified_atand goes needs-review when a declared source changed after it. (#926) - BREAKING: Model
/spec executeas PLANNED -> RUNNING -> READY | DRAFT-BLOCKED(gate), with RUNNING derived fromprd.jsonand mirrored into/tmp/spec-<slug>.state. (#926) - Re-open
/spec execute's promotable gate when a push lands aftergh pr ready: the verdict binds to one head, so a moved head is re-audited or returned to draft. (#926) - Reduce
/wiki lintto six correctness checks and demote/compactto an optional non-gating step that runs only after evidence, retro, and pattern compilation. (#926) - Reduce
/spec retroto an explicit wrapper around/retro --task <slug>, which/retronow accepts;/retrostays report-only and/wiki compilestays the durable pattern writer. (#926) - BREAKING: Move eleven settings out of the compose
environment:block into oh.json, read through theohCLI; a hand-edited.devcontainer/.envno longer carries them (#920). - Make
/specship by default: an unrecognized first token routes to a newshipnode that runsplanthenexecute, so/spec <plan-path>produces a ready-for-review PR (#914). - BREAKING: Persist the sandbox home through one
/home/sandboxmount, not eleven per-tool volumes; setstorage.homePathfor a host path, else<name>_workspace(#898). - Shrink the sandbox image ~540 MB: drop build caches from the baked home seed, stage the seed once via a builder stage, and keep untracked build output out of the build context (#900).
- BREAKING: Stop baking Claude Code, Codex, and Pi into the image; boot installs them into the home mount, so a first boot needs network and runs 60-180s longer (#904).
- BREAKING: Stop baking Herdr and cloudflared into the image; both become
kind: "default"tools installed into~/.local/binat boot from a pinned, checksum-verified binary (#906). - BREAKING: Stop baking OpenCode, Hermes, and Grok Build into the image;
oh harness install <id>installs them into~/.localas the sandbox user (#908). .oh/logs/carries anAGENTS.mdwith aCLAUDE.mdsymlink instead of aREADME.md, matching the directories whose contents are produced apart from the root context. (#924)- BREAKING:
/spec executeno longer launches a coding agent; the agent that runs it is the single implementation owner through the final PR gates (#928). - Task identity and
RUNNINGstate depend on.oh/tasks/<slug>/alone, never on a terminal session, tab, or pane (#928). /delegatekeeps work in the active session when phases share substantial context and spawns provider-native workers only for self-contained, isolated, or parallel work (#929)./spec planjudges architecture significance once and routes a significant topic through/architectbefore planning (#929).docs/glossary.mddefines coding agent, skill, worker/subagent, rule, and RFC/ADR as five distinct terms (#929)./t3launches the headlesst3 serveinstead of the local-GUIt3, and gains--tailscale, apairaction for a second device, and adoctorpreflight (#858).
Fixed
- Fix
/wiki lintgenerating the corpus index from the working tree instead of the git-tracked set, which made any untracked scratch entry awiki-readme-index.shregression. (#916) - Fix three unresolved
related:and[[slug]]links in therecursive-language-modelswiki entry, and add the/wiki lintcheck that would have caught them. (#916) - Provision the default harnesses into
/home/sandbox/.localat boot, gated byOH_PROVISION_HARNESSES, sooh harness installalso works from inside the sandbox (#902). - Add
oh-home-mount.sh, a tier-A probe holding the single-$HOME-mount contract: one mount per compose file, the baked/opt/home-seed, and the checkout prune that replaces-xdev(#898). - Assert boot-provisioned harnesses in the boot smoke and reject a baked default harness in
verify-sandbox-image.sh, so CI exercises the install path (#904). - Add
oh tool list --defaultsand generalize the boot provisioner over both catalogs asprovision-defaults.sh(OH_PROVISION_DEFAULTS) (#906). - Fix
oh harness installhanging on a sudo password prompt inside the sandbox: every harness now installs as the sandbox user,...
v0.5.1
Fixed
tsconfig.build.jsonexcluded onlysrc/__tests__/**, soprepublishOnlytypecheckedsrc/lib/__tests__/and failed on the absentvitest, blocking the npm publish after the image had shipped.
v0.4.0
Removed
- Remove
harness.yamlentirely. Configuration collapses to.devcontainer/.envplus theohCLI. Deleted:harness.yaml.example,.oh/templates/harness.yaml, the 163-line awk parser.oh/scripts/harness-config.sh, the 251-line.oh/cli/src/lib/harness-yaml.ts, their two test files, theharness-yaml-schema-parityprobe, and themake harness-configtarget. The layer never earned its place: every key it mapped already existed as a compose env var with a default, and it was invisible on the VS Code "Reopen in Container" path, which names.devcontainer/docker-compose.ymldirectly and so reads only.devcontainer/.env. A key set inharness.yamlsilently did nothing there. - Remove the derived
.devcontainer/.harness.yaml.envartifact and the second--env-filethat carried it. The wrapper now passes exactly one env-file β the same one compose auto-loads on the VS Code path β so the two doors cannot disagree by construction.
Added
- Add
.oh/scripts/migrate-harness-yaml.sh: a one-shot automatic migration so no existing install silently loses a setting. It runs from.oh/scripts/docker-compose.shand.oh/scripts/install.sh, so it fires on every lifecycle verb; it translates the 21 allowlisted keys into.env(uncommenting template lines in place), movescompose.overridesinto.oh/config.jsoncomposeOverrides[], renames the file toharness.yaml.migrated, and prints every value it carried over β including both sides of any value it replaced. Absent aharness.yamlit exits 0 immediately. It is self-contained, carrying its own copy of the deleted parser, so the whole compatibility story is one file to delete in a later release. - Add
.oh/cli/src/lib/env-file.tsβ the one.envreader/writer, replacinglib/harness-yaml.ts. Reads go through the existingloadEnvInto, so no fifth env parser was added; writes carry over the uncomment-in-place discipline. Config reads are now plain filesystem reads:oh sandboxandoh shellspawn zero subprocesses to resolve configuration, where every read used to shell out to the vendored parser. - Add three probes replacing the deleted parity probe:
env-schema-parity.sh(the two.example.envtemplates carry the same keys, and every var anydocker-compose*.ymlinterpolates is documented β this closes a real gap:DOCKER_SOCKET,SANDBOX_SSH,SANDBOX_SSH_PORT,OH_SANDBOX_IMAGE,OH_PULL_POLICYandSKIP_PNPM_INSTALLwere consumed but documented nowhere),harness-yaml-migration.sh(append / uncomment-in-place / preserve / overwrite, plus a silent second run), andcompose-config-path-parity.sh(the wrapper path and the VS Code path resolve the same service β the parityharness.yamlmade impossible).
Changed
.devcontainer/.example.envis now the schema document, carrying all 25 keys with their defaults and prose, lifted fromharness.yaml.example. Its "Migrated to harness.yaml" block is gone..oh/templates/.devcontainer/.example.envis brought to key parity β anoh initrepo shipped a template documenting three vars.- The installer's config writes always run.
install.shput its entire config block insideif [ ! -f .devcontainer/.env ], so re-running it over an existing install wrote nothing; with.envas the only surface that would have become a total no-op..envis now seeded when absent and the writes always follow, each idempotent and one line wide. Host detections (timezone, git identity) still only seed a fresh file, so a re-run never silently overwrites a hand-edited value. .oh/scripts/docker-compose.shdrops fiveharness.yamlresolution ladders (hermes-dashboard, docker-socket, ssh.enabled, ssh.port, sandbox.name) and thecompose-overridesloop; each collapses onto the.envfallback that was already the next line. The overlay-flist is byte-identical before and after, verified against a recorded baseline..oh/scripts/oh-pathloses itspaths.<name>ladder: the precedence is now<NAME>_DIRenv β.oh/<name>.oh init's wizard writes one file. It used to split non-secret answers toharness.yamland secrets to.env; both now land in.envin a single write, through the same line editor, so the operator's answers appear as uncommented lines inside the documented template.- CI path filters and their probes move from
harness.yaml.exampleto.devcontainer/.example.env(ci-harness.yml,sandbox-boot-guard.yml,harness-ci-core-paths.sh,sandbox-boot-guard-ci.sh).oh-init-headless-config.shretargets to the.example.envtemplate and additionally asserts--yeswrites no.envat all. .gitignorekeeps/harness.yamland.devcontainer/.harness.yaml.envfor one more release so a stale local artifact from a pre-0.4.0 checkout is never committed, and adds/harness.yaml.migrated.
v0.2.0
Added
- Add
oh harness <list|install|status>to install optional harnesses into a running sandbox without a rebuild, persisting the choice toinstall.<key>for the next build (#821). - Add
oh runtime <list|install|status>, reporting the container runtime in use and gating a MicroSandbox install on the measured glibc and/dev/kvmblockers. It selects no runtime (#823). - Add
oh tool <list|install|status>for sandbox tooling that is neither an agent CLI nor a runtime, makingagent-browserinstallable without a rebuild behind a ~1 GB download gate (#824). - Add
oh stop|restart|logs|ps, closing the lifecycle gap wheremakehad verbs the CLI did not, and publish onemakevsohmapping doc that the other docs link to (#825). - Document running Open Harness on MicroSandbox by pointing
msbat the published image, and re-scope the microsandbox blockers as devcontainer measurements that say nothing about the reader's host. - Add a "which door am I?" table plus two guard probes:
harness-yaml-schema-parity.shandoh-init-headless-config.sh. - Add
ssh.enabled/ssh.portandsandbox.docker_socketprompts to theoh initwizard, the two settings most likely to need hand-editing. - Require
.oh/tasks/<slug>/evidence.mdbefore/spec executeundrafts a PR, and refuse an untracked one, so the reviewer gets the build's answer back to the plan they approved (#817). - Add a "why this is better" question to the reviewer evidence contract, ahead of the four correctness questions, with unmeasured benefits labelled as such (#817).
- Add
protected-path-deletion.sh, which reads.claude/protected-paths.txtat the merge base and fails when a listed path is deleted without a justification in a committedevidence.md(#817). - Add
memory-probe-claims-resolve.shandcontext-tier-size-budget.shto hold the memory ledger's enforcement claims and the always-on context budget (#817).
Changed
- Run
/evalonce per cycle instead of three times:/spec executepublishes a commit-keyedeval-result.jsonthe downstream gates read, cutting 318 probe executions to 110 (#817). - Promote
progress.txtinto the PR body, so the build narrative reaches the reviewer instead of ending at theSTATUS: COMPLETEsentinel (#817). - Write
install.sh's non-secret answers toharness.yamlrather than the lower-precedence.devcontainer/.env, keepingDOCKER_SOCKETin.envas a documented exception. - Lead the README and quickstart with the two scripted installers and demote the untested manual clone sequence into the collapsed section, merging its two duplicate copies into one.
Fixed
- Match the release-notes heading with
index()instead of a regex built by string concatenation, so extraction does not depend on whether the runner'sawkis mawk or gawk (#820). - Fix the build session launching headless: the prompt travels as argv instead of stdin and no arm carries
--print, so the child no longer answers once and exits (#817). - Stop
| teein the launch path taking the child's TTY; tmux attachespipe-paneafter the pane exists and foreground mode inherits the caller's stdio (#817). - Fix
firstmate.sh --killexiting 1 silently while leaving the session running, the lock claimed, and noFIRSTMATE-INCOMPLETEline appended (#817). - Stop the
/auditboundary exporting its lifecycle identity to the agent it launches, which made probes grade their caller and flipped one tree's verdict between runs (#817). - Rewrite 76 unbacked
probe:claims in the memory ledger to explicitprobe: nonevia a tracked idempotent script (#817). - Correct the MicroSandbox runner walkthrough: set
entrypoint:explicitly, without which the seed and provider linking never run; drop the unsubstitutedGH_TOKEN; and re-rank the untested inferences so the boot-breaking one leads. - Collapse the two disagreeing
harness.yamlline editors into onesetKeyInSectioninlib/harness-yaml.ts; the wizard's section-blind copy silently dropped answers for keys absent from the template. - Reconcile
.oh/templates/harness.yamlwithharness.yaml.example, restoring thesandbox.docker_socket/image/pull_policy,paths.worktrees,crons,autopilot,slack, andcomposekeys that had no home to be written into. - Correct
harness.yaml.example's claim thatpull_policyreaches the VS Code "Reopen in Container" path β it does not, and no key in the file does.
Removed
- Remove the critique/approve gate; the operator's approval of
prd.mdis the commitment gate, and no critic agents are spent per plan (#817). - Collapse three build executors to one, deleting
.oh/scripts/ralph.shand every executor toggle rather than reducing them to a single accepted value (#817). - Absorb
/ship-specinto/spec executeand delete the skill, so the build mechanics read top to bottom in one file with no deferral (#817). - Delete
.oh/prompts/,.pi/prompts/advisor/, and the First Mate charter, leaving.oh/skills/firstmate/templates/session-prompt.mdas the only description of the build workflow (#817). - Delete
/teachand its pipeline step;evidence.mdcarries the model to the reviewer, and the wiki half was already a gate in step 5 (#817). - Delete the DeepWiki comparison from the wiki gate, which regenerates on no schedule the gate can depend on, and rename the schema section to state its own requirements (#817).
- Delete four
STATUS: SPEC-*tokens with no executable consumer and drop the groom triad from the per-cycle path (#817).
v0.1.0
Fixed
- Stop
/prompt-minerfrom mining markers against a censored statistic.scoreSessioncomputedclamp(base + bonus, 0, 100), butbaseis already capped at 100 by construction andbonusadds up to 15, so every low-friction ground-truth session lands on the ceiling: 15 of 37other-stratum sessions (41%) sat at exactly 100 on the 2026-08-13 run. The marker gate promotes on a standardized mean difference in that score, so the clamp β not the data β was deciding robustness verdicts. Measured onlenWords β₯ 25in stratumother:d = 0.332capped with 19 of 37 leave-one-out folds under the 0.3 bar, versusd = 0.423uncensored with 0 of 37 folds under the bar. The engine now emitsscoreUncapped = base + bonusas an additive sibling ofscoreon everysessions[]andunranked[]record;scoreitself is unchanged, still clamped, and still the ranking and display scale.manifest.ceilingSaturationadds a per-stratum{ atCeiling, total }census over the rankable population, rendered under the existing## Manifestheading.references/markers.md,SKILL.md,references/report-schema.md, andreferences/scoring.mdnow all namescoreUncappedas the correlation scale, closing the ambiguity that produced the manuald_cap/d_uncworkaround. A stability guard keeps the net change stricter rather than looser: each marker record carrieseffect_size(uncensored, authoritative) alongsideeffect_size_capped, and a marker whose two scales disagree on sign β or where exactly one clears the 0.3 bar β is reportedUNSTABLE, is not promotable on either scale, and yields no memory proposal or auto-filed issue. That guard would have blocked the 2026-08-09referencesSkillpromotion already identified as a clamp artifact. This does not close #730 (cross-window irreproducibility); no window, threshold, or cross-run rule is touched. (#778) - Anchor the
memoryname in.oh/scripts/oh-pathto the main worktree, so one durable ledger serves the whole checkout instead of one per branch.oh-pathresolved every name against the parent of its own.oh/, which inside a linked git worktree is the worktree root;.oh/memory/MEMORY.mdis gitignored, so a new worktree started without one and.oh/scripts/ensure-memory-file.shseeded an empty stub there. Every build session in this harness runs in a worktree, so the ledger was structurally invisible to exactly the sessions that produce and consume lessons, and each/retrowrote into a file deleted with its branch β five of the seven lessons written in sessionc10a1f34never reached the checkout's ledger, including the one that session had just re-derived. Measured across the live worktrees at the time: main checkout 86 lines, the incident worktree 17 (an auto-seeded header plus its own writes), the other six absent. Every other name (crons,evals,tasks,context,worktrees) stays branch-scoped, because a probe or a task must resolve the worktree it is testing; the journal is the exception. Absolute values fromMEMORY_DIRorharness.yaml β paths.memoryare still honored verbatim β only relative values change which root they measure from β and the env βharness.yamlβ default precedence is untouched. Resolution degrades to the previous root whenever git cannot answer (no git binary, not a repository, a damaged.git, or output naming a non-directory), so a freshoh initbeforegit initis unaffected and a git failure can never abort a caller running underset -eu./retrocomputed the resolved path atSKILL.md:235and then discarded it, passing the relative literal.oh/memory/$TODAY/log.mdtolocked-append.sh, so the resolver fix alone would not have reached the harness's most frequent memory writer; its log and ledger writes now use the resolved path. The docs that called the tier "local-per-instance" are corrected to name the checkout as the unit and to state that an empty ledger means the file was just created rather than that a fact went unrecorded β naming the unit wrong is why the same defect was worked around twice at individual call sites (#152, #693) without anyone fixing the resolver. This does not make memory portable across clones, operators, or providers:MEMORY.mdstays gitignored, and that broader question is left open rather than answered by a side effect. Pinned by.oh/evals/probes/memory-dir-shared-across-worktrees.sh, which builds a real linked worktree and runs that worktree's own copy ofoh-pathβ invoked from the main checkout the fixed and unfixed scripts print the same path, which is how the defect stayed invisible β and asserts the shared anchor, the absence of any worktree-local resolution, the unchanged branch-scoping of the other names, and the verbatim absolute override. It reads git topology and paths only, neverMEMORY.mdcontent or other untracked state, so a fresh CI clone and a developer worktree return the same verdict. Verified by rejection: against the unfixed script it fails on exactly the two assertions under test with the other five reporting zero, and swapping only the script inside one fixed worktree flips the result, which attributes the exit code to the anchor block rather than to its neighbours (#768). - Stop
/retrofrom logging promotion counts it cannot yet know..oh/skills/retro/SKILL.mdordered its steps Β§6 propose-then-confirm gate β Β§7 write approved changes β Β§8 append the log entry, but Β§8 is unconditional and rendersrender-log-entry.sh --memory <n> --identity <n>β promotion counts. For any run that is notauto-approvethe agent's turn ends at the gate, because it must hand control back to the operator to get an answer, so the entry was written while the counts were still unknowable and became wrong the instant the operator approved..oh/memory/<UTC-date>/log.mdis append-only, so it could not be corrected in place: on 2026-08-13 the 06:02 entry recordedPromoted: 0 to MEMORY.md, three lessons were then approved, and a separate superseding line had to be appended at 06:03. The defect survived becauseauto-approveβ the invocation used by.oh/prompts/advisor/implement.ymlandpr.ymlβ collapses the gate into a single turn, so the common path never exercised it. The helper now refuses the guess rather than relying on step order alone:--result GATE-PENDINGrequires--memory pending --identity pendingand exits64on an integer,pendingis rejected on any other result, and a new--resolves HH:MM(valid only with--result OP) renders the join line back to the entry it resolves.SKILL.mdΒ§6 is now 6a filter duplicates β 6b append theGATE-PENDINGentry β 6c print the proposal block, with the append placed before the block that ends the turn and an explicit "nothing placed after it is guaranteed to run"; Β§8 appends the resolving entry and derives its counts from the lines actually appended in Β§7 rather than from the size of the proposal list. The alternative shape sketched on the issue β defer the append until the gate resolves β was rejected because a run abandoned at the gate never resumes, so it would leave zero trace and trade the unconditional-log guarantee away to fix a count; rescuing it requires writing something at the gate anyway, which is this shape.retro-deterministic-contract.shgains eight assertions, each with a unique767-<id>message, verified by rejection against eight fixtures that each break exactly one thing and then attributed by mutation β deleting the assertion makes the same broken tree pass. Two of them cover the step order separately, because anchor reordering and anchor deletion fail differently and the deletion case is the dangerous one:grep -n β¦ | cut -d: -f1yields the empty string on no match and(( "" < 100 ))is true in bash, so an unguarded compare passes on a file whose anchor was removed. Scope is deliberately narrow βreport-schema.md,memory-protocol.md,validate-retro-report.shandcheck-memory-duplicates.share byte-unchanged. What this does not fix: the count is still the agent's self-report, so a miscount remains reachable; the change closes when the number is asserted, not whether the arithmetic is right (#767). - Make the
/stechecker's clean exit name the two defects it cannot see. Measured on the skill's first production use:ste-check.shexited0with zero findings on prose carrying a condition placed after the action it guards and a sentence opening with a pronoun that names no antecedent β questions 4 and 7 of the skill's own 10-question check, both caught by hand seconds later. A green run reads as approval, so the exit-0line now states both escapes and points atSKILL.md, and the "checker misses" paragraph names them alongside missing actors and invented values. No detector was added, deliberately. A question-4 detector fires on approvedafterspecimens inreferences/examples.md(lines 58, 86, 99, 140, 310, 324) and would turn--blocks afterred, breaking the committed regression fixture; a question-7 detector cannot separate a bare pronoun from one whose antecedent sits in the previous sentence, because the checker reads one line at a time, and it would flipreferences/rules.mdred too.ste-checker-contract.shgains a section-7 assertion pinning the disclaimer, verified by rejection against three mutations β the bare pre-change line, and each half removed on its own.references/examples.md,references/rules.md, andreferences/dictionary.mdare untouched, and no new rule identifier joins the six. - Keep the firstmate execution-context probe pane alive across its own read, so the...
v2026.8.7
Added
Changed
- Set the default Pi driver to
openai-codex/gpt-5.6-lunawithmaxreasoning while retaining Sol, Terra, and Luna in the model selector (#700). - Release every push to
mainormasteronly after validation, using retry-safe UTC CalVer reservations, immutable CalVer/sha-<full-SHA>GHCR tags, canonical-branch digest promotion forlatest, gated CLI publication, and post-image GitHub Release finalization (#689). - Expose the supported GPT-5.6 variants in Pi's model selector (#684).
- Expand Advisor planning with a designer lens and make implementation/PR prompts explicitly finish with delegated audits and retrospectives (#680).
Fixed
- Stop the cron reaper from reading a
git statusfailure as evidence of uncommitted work.inspectFallbackWorktreereturneddirty: truewhenevergit status --porcelainexited non-zero, so a worktree directory whose.git/worktrees/<name>admin entry had vanished was preserved as "needs manual salvage" on every single fire β 15 consecutive days forcron-prompt-miner-0718-0500, which also erodedWORKTREE_DIRTY's value as a triage signal by burying any real one under identical noise. Adds a distinctWORKTREE_ORPHANEDoutcome that removes the directory (git worktree removefails once the admin entry is gone, andgit worktree prunehandles only the inverse case). The orphan is identified structurally β a.gitfile whosegitdir:target no longer exists β rather than by matchinggit statusstderr, which is locale-dependent; every other status failure still preserves the worktree, since it cannot be shown that there is nothing to salvage (#694). - Resolve the
prompt-minerdaily-log write root to the main worktree instead of the ephemeral one.render-log-entry.shusedgit rev-parse --show-toplevel, which under the cron'sworktree: truereturns the linked worktree β so every Step 5 log entry was written into.oh/worktrees/cron/<session>/and destroyed when the runtime reaped it (fired 07-10, 07-14, 07-19, hand-recovered each time). Adopts theAUTOPILOT_LOG_ROOTβCRON_WORKTREEβ toplevel resolution already proven at.oh/crons/prompt-miner.md:102and documented at.oh/crons/README.md:120, preserving precedence for callers that do export the variable. Guarded byprompt-miner-log-root-worktree.sh, which builds a real linked worktree and asserts the entry lands in the main one β a fixture test cannot catch this class of bug (#693). - Make
prompt-minerable to mine a marker at all, and stop it mining a wrong one. Three changes: (1)withinWindownow admits a session whose activity span overlaps the window instead of one that starts inside it β events are merged across resumed files bysessionId, so a long-lived session kept its originalfirstTsand vanished from a windowed query despite being worked in continuously; (2) subagent (isSidechain) turns are excluded from every signal β they carry the parent'ssessionIdandrole: "user", so a delegate briefing was counted as a human turn, and at 45,167 sidechain vs 42,679 non-sidechain lines this corruptedcorrectionDensity/turnBloat/toolErrorRatefor precisely the delegating sessions most worth mining; (3) the daily cron's window is decoupled from its cadence (--hours 24β--hours 336), because the marker gate needs β₯10 sessions in one stratum and a 24h corpus cannot supply that. Largest stratum by window, measured live: 24h β 4, 168h β 6, 336h β 18. The engine's hardcoded single project directory is deliberately not changed β the 23 directories it would add are this cron's own worktree sessions, whose first prompts have one distinct length and two distinct hashes, so they would cross the corpus floor while being incapable of producing a marker (#692). - Make the
prompt-minerengine run when invoked through the.claude/skillsdirectory symlink thatSKILL.mdStep 1 and the daily cron both prescribe. Node resolves symlinks forimport.meta.urlbut not forprocess.argv[1], so the old entrypoint guard silently no-opped β exit 0, zero stdout, nothing written β and both existingprompt-minerprobes hardcode the real.oh/path, leaving them structurally blind to it. Swaps in the symlink-safe basename guard already used byrlmandweigh, and addsprompt-miner-symlink-entrypoint.sh, which invokes the engine through a real symlink and rejects the comparison β in either operand order β on any executable line under.oh/skills/**/*.mjs. Does not change theNO-CORPUSoutcome β see #692 (#663). - Index
.oh/docs/rfcs/rfc-runtime-support.mdfrom.oh/docs/README.md, which had left a quarter of the RFC/ADR corpus unreachable from the index humans enter through, and repoint the dangling.claude/rules/context bullet in thecriticandimplementeragents at.oh/context/IDENTITY.mdβ that directory was removed by the B-state M4 rules collapse (#686). - Make Slack bridge admin commands discoverable and functional by declaring
/help,/trusted,/channels,/enable,/disable,/revoke, and/toggletoolsin.pi/install/slack-manifest.json, pinning bridge-side Socket Mode command handlers, and separating Slack commands from Pi's/msg-bridgesurface in docs (#354).
Removed
Deprecated
Security
v2026.8.3
Added
Changed
- Set the default Pi driver to
openai-codex/gpt-5.6-lunawithmaxreasoning while retaining Sol, Terra, and Luna in the model selector (#700). - Release every push to
mainormasteronly after validation, using retry-safe UTC CalVer reservations, immutable CalVer/sha-<full-SHA>GHCR tags, canonical-branch digest promotion forlatest, gated CLI publication, and post-image GitHub Release finalization (#689). - Expose the supported GPT-5.6 variants in Pi's model selector (#684).
- Expand Advisor planning with a designer lens and make implementation/PR prompts explicitly finish with delegated audits and retrospectives (#680).
Fixed
- Stop the cron reaper from reading a
git statusfailure as evidence of uncommitted work.inspectFallbackWorktreereturneddirty: truewhenevergit status --porcelainexited non-zero, so a worktree directory whose.git/worktrees/<name>admin entry had vanished was preserved as "needs manual salvage" on every single fire β 15 consecutive days forcron-prompt-miner-0718-0500, which also erodedWORKTREE_DIRTY's value as a triage signal by burying any real one under identical noise. Adds a distinctWORKTREE_ORPHANEDoutcome that removes the directory (git worktree removefails once the admin entry is gone, andgit worktree prunehandles only the inverse case). The orphan is identified structurally β a.gitfile whosegitdir:target no longer exists β rather than by matchinggit statusstderr, which is locale-dependent; every other status failure still preserves the worktree, since it cannot be shown that there is nothing to salvage (#694). - Resolve the
prompt-minerdaily-log write root to the main worktree instead of the ephemeral one.render-log-entry.shusedgit rev-parse --show-toplevel, which under the cron'sworktree: truereturns the linked worktree β so every Step 5 log entry was written into.oh/worktrees/cron/<session>/and destroyed when the runtime reaped it (fired 07-10, 07-14, 07-19, hand-recovered each time). Adopts theAUTOPILOT_LOG_ROOTβCRON_WORKTREEβ toplevel resolution already proven at.oh/crons/prompt-miner.md:102and documented at.oh/crons/README.md:120, preserving precedence for callers that do export the variable. Guarded byprompt-miner-log-root-worktree.sh, which builds a real linked worktree and asserts the entry lands in the main one β a fixture test cannot catch this class of bug (#693). - Make
prompt-minerable to mine a marker at all, and stop it mining a wrong one. Three changes: (1)withinWindownow admits a session whose activity span overlaps the window instead of one that starts inside it β events are merged across resumed files bysessionId, so a long-lived session kept its originalfirstTsand vanished from a windowed query despite being worked in continuously; (2) subagent (isSidechain) turns are excluded from every signal β they carry the parent'ssessionIdandrole: "user", so a delegate briefing was counted as a human turn, and at 45,167 sidechain vs 42,679 non-sidechain lines this corruptedcorrectionDensity/turnBloat/toolErrorRatefor precisely the delegating sessions most worth mining; (3) the daily cron's window is decoupled from its cadence (--hours 24β--hours 336), because the marker gate needs β₯10 sessions in one stratum and a 24h corpus cannot supply that. Largest stratum by window, measured live: 24h β 4, 168h β 6, 336h β 18. The engine's hardcoded single project directory is deliberately not changed β the 23 directories it would add are this cron's own worktree sessions, whose first prompts have one distinct length and two distinct hashes, so they would cross the corpus floor while being incapable of producing a marker (#692). - Make the
prompt-minerengine run when invoked through the.claude/skillsdirectory symlink thatSKILL.mdStep 1 and the daily cron both prescribe. Node resolves symlinks forimport.meta.urlbut not forprocess.argv[1], so the old entrypoint guard silently no-opped β exit 0, zero stdout, nothing written β and both existingprompt-minerprobes hardcode the real.oh/path, leaving them structurally blind to it. Swaps in the symlink-safe basename guard already used byrlmandweigh, and addsprompt-miner-symlink-entrypoint.sh, which invokes the engine through a real symlink and rejects the comparison β in either operand order β on any executable line under.oh/skills/**/*.mjs. Does not change theNO-CORPUSoutcome β see #692 (#663). - Index
.oh/docs/rfcs/rfc-runtime-support.mdfrom.oh/docs/README.md, which had left a quarter of the RFC/ADR corpus unreachable from the index humans enter through, and repoint the dangling.claude/rules/context bullet in thecriticandimplementeragents at.oh/context/IDENTITY.mdβ that directory was removed by the B-state M4 rules collapse (#686). - Make Slack bridge admin commands discoverable and functional by declaring
/help,/trusted,/channels,/enable,/disable,/revoke, and/toggletoolsin.pi/install/slack-manifest.json, pinning bridge-side Socket Mode command handlers, and separating Slack commands from Pi's/msg-bridgesurface in docs (#354).
Removed
Deprecated
Security
v2026.7.26
Added
- Install Herdr by default as a persistent multi-agent terminal workspace (#651).
- Add bounded local PDF, DOCX, PPTX, and XLSX normalization to
/wiki ingestthrough Microsoft MarkItDown's pinned upstream CLI, preserving immutable source provenance without a wrapper command (#650). - Add the explicit nine-target
/auditdispatcher, deterministic focused/queue PR classifier, correlated full campaigns, and shared locked ablation recovery (#646). - Adopt
cc-safety-net@1.0.6as the cross-provider destructive-command guard (claude, codex, and pi) β a PreToolUse hook that semantically blocksgit reset --hard,rm -rf,git push --force, and peers underbypassPermissions/approval_policy=never; the binary is baked into the image at build time (exact pin, zero boot-time registry access), with aCC_SAFETY_NET_OFF=1kill-switch that disables the claude/codex bash hooks without config edits, a new.oh/scripts/git-maintenance.shshim so hook-mediated harness automation keeps its legitimate destructive-git operations, and acc-safety-net-wiringeval probe guarding the wiring (#654). - Add the First Mate role charter at
.oh/context/rules/first-mate.mdand the git-tracked.oh/prompts/advisor/prompt pack, with a newarchitectcrew agent for solution-shape planning (#660).
Changed
- Default agent-browser desktop sessions to a 1280Γ720 viewport (#674).
- Refresh the default Claude model, durable review-loop guidance, and Cloudflared public-surface verification instructions (#672).
- Relicense from MIT to Apache License 2.0 with patent grants and trademark clarity; prior MIT releases remain available under MIT and the hosted Console stays proprietary (#666).
- Make Herdr the canonical first interactive workspace after sandbox entry, with setup and agents organized inside persistent panes and a pinned, checksum-verified CLI (#653).
- Protect the consolidated
/auditowner in place of the supersededharness-audit,skill-lint,eval-lint, anddrift-checkentry points, staging their removal in the separate audit-consolidation implementation (#647). - BREAKING: Consolidate artifact authoring under
/builder <agent|skill|command|rule> <name-or-request>with one authoritative reference per type (#643).
Fixed
- Harden audit consolidation with real GitHub CI normalization, executable run/root/log lifecycle, focused watchdog classification, non-mutating implementation gates, and race-safe ablation recovery fixtures (#646).
Removed
- BREAKING: Remove superseded audit-family entry points and the
auditoragent. Migration:/pr-auditβ/audit pror/audit prs;/harness-auditβ/audit harness;/context-auditβ/audit context;/skill-lintβ/audit skills;/eval-lintβ/audit eval-quality;/drift-checkβ/audit drift;/audit <slug>β/audit implementation <slug>; auditor campaigns β/audit full(#646). - Remove the legacy
agent-builder,skill-builder,command-builder, andrule-builderagents and the superseded/skill-builderentry point; migrate callers to/builder(#643). - Retire the dead
RISKY_BASHarray and its bash branch from pi's.pi/extensions/path-guard.tsβ it was a no-op in both headless and TUI modes, now superseded by cc-safety-net's fail-closed pi extension;SENSITIVE_PATHSand the/guardcommand are retained (#654).
Deprecated
Security
- Add a reproducible, audit-gated
pi-langfuse@1.5.7installer that overrides its vulnerable OpenTelemetry SDK tree to patched@opentelemetry/sdk-node@0.220.0(#664). - Pin the transitive
postcssdependency (reached viavitest > vite) to the patched^8.5.18viapnpm.overrides, clearing GHSA-r28c-9q8g-f849 and unblockingpnpm run security:auditon every PR (#668). - Move every pinned GitHub Action off the deprecated Node 20 runtime β
actions/checkout@v7,actions/setup-node@v7,pnpm/action-setup@v6,actions/cache@v6,softprops/action-gh-release@v3,docker/setup-buildx-action@v4,docker/login-action@v4β and unpin the major in thepnpm-audit-ci-gateprobe so future runtime bumps do not read as regressions (#670).
v2026.7.15
Added
Changed
Fixed
- Keep the cron-watchdog temp file (
/tmp/cron-watchdog.sh) root-owned so a container restart (docker start) can rewrite it, and make the optional cron supervisor non-fatal underset -e; previously the root entrypoint could not overwrite the sandbox-chowned file on the second boot (EACCES on runtimes withoutCAP_DAC_OVERRIDE), which crash-looped the node (#640).