v0.51.6
Four tracks moved in this release. One opens a market, one was carried almost entirely by people outside the core, one gave the team back its afternoons, and one continued the long work of making the loop stop overstating what it finished.
Track 1 — DeepSeek Harness (dsh): the door to a market we could not previously enter
There is a version of this project's history in which Ouroboros only ever spoke one vendor's language. It would have been easier, and it would have quietly decided on the user's behalf which models were allowed to think.
dsh — alias deepseek_harness — is now a first-class completion backend (#2143). It drives DeepSeek Harness's automation ACP server for the entire in-process completion path: interview, seed, QA, evaluate. Everything the Socratic loop needs to converge a specification can run on DeepSeek.
This is a go-to-market change, not only an integration. A developer working where DeepSeek is the practical default — where Anthropic and OpenAI endpoints are not a realistic dependency — can now run the full specification-first loop end to end on infrastructure they already have, and pay for it in a currency they already use. Specification-first development should not require a particular passport.
What landed:
DshAcpClientsubclasses the existing ourocode ACP client through three narrow launch seams. dsh speaks the same ACP wire Ouroboros already implements, so this reuses proven machinery instead of growing a second protocol stack — the ourocode suite passes byte-identically.- dsh's
session/newindexesparams.mcpServers.lengthunconditionally and rejects a non-empty list, so the client always sendsmcpServers: []. Documented, not papered over. DshLLMAdapterreports an honestdsh-compositionsentinel rather than fabricating a model id in audit metadata. The ACP wire carries no model parameter — dsh's Cordis composition file owns provider and model selection — and an audit trail that invents a value it cannot observe is worse than one that admits the gap.- Security.
OUROBOROS_DSH_CLI_PATHandOUROBOROS_DSH_CONFIG_PATHboth join the untrusted.envdenylist. The config path selects which Cordis composition a spawned Node process loads, and composition rows execute arbitrary plugin code — so it gets the treatment an executable path gets, not the lesser treatment a "config file" would normally receive. - Verified against the real binary. A from-source build of deepseek-harness completed spawn →
initialize→session/new→session/promptdispatch into dsh's LLM layer, failing only at the expected terminal point: no API key on the verification machine. Everything short of the paid model call is proven, and we are stating that limit plainly rather than rounding it up. - The full adoption analysis — what dsh has, what is worth borrowing, how to collaborate upstream — is in
docs/research/deepseek-harness-adoption.md.
Track 2 — Contributors
Six people outside the release author shipped into this version, and between them they closed most of the gap between "Ouroboros is installed" and "Ouroboros is actually going to work on your machine."
@tmdgusya — zcode model-config readiness (#2147, closes #2148). setup and status health used to report every check green on a machine where the first workflow step would then fail mid-execution, because the ZCode CLI resolves its model from a config file the desktop app never writes. The new probe mirrors the CLI's own acceptance rules and names the exact gap — including the case where an object-form model.main is silently dropped by the CLI's parser, which is how an apparently complete config keeps failing.
@lee3Q — installation surface doctor (#2034). ouroboros doctor install reports every active surface: Python package, Codex plugin and cache, Claude Code plugin and cache, user-level MCP config, ZCode bridge. It repairs nothing, by design. ooo --version was never proof that every client integration was current, and now there is a read-only command that says so with paths and versions instead of vibes.
@sumin220 — update nudge reachability (closes #2066), and the legacy identity seam (#1899). The plugin MCP descriptor is now version-pinned and synced by the same release-prep pass as plugin.json, so a plugin update deterministically changes the uvx cache key; the SessionStart notice moved to stdout, the channel that actually enters agent context; and mcp serve appends the cached notice to its server instructions, so Codex, OpenCode, Kiro and every other MCP host finally receives it. The notice reads only the local cache, never the network, and can never delay or fail server startup. Separately, #1899 moved the pre-anchor project-identity path behind one observable seam with a finite, dated support window — sessions started before the Project Map anchor keep their resume authority, one decision point emits a structured local event when the legacy path activates, and removing the seam after the window requires a documented breaking change naming the last identity-compatible release. Log absence never authorizes deletion.
@bokjk — native Windows Codex Desktop HTTP task persistence RFC (#2101). Backed by preflight evidence gathered on real Windows 11 rather than assumed from documentation: RestartOnFailure did not relaunch on exit code 7 or on 0xC0000005, while RegistrationTrigger with one-minute repetition did. The RFC therefore promises evidence-backed periodic launch attempts instead of claiming failure-aware restart — and replaces HKCU Run with one explicit opt-in, least-privilege Scheduled Task contract.
@dj-wishket and John — hooks fail-open and trust boundaries (#2111 and follow-ups). Hooks now fail open when the plugin cache root disappears, align Codex development fail-open behavior, and reject untrusted packaged fallback roots. A hook that hard-fails on a missing cache directory blocks the user from working; a hook that trusts an arbitrary fallback root is worse. Both edges are now closed.
Track 3 — Test and CI performance
The suite had grown expensive in a way that taxes every contributor on every push. Eleven changes went after it, and none of them weakened a contract: every retry count, every degradation path, every ratio assertion still holds. What was removed was waiting.
CI shape (#2142). Every PR previously ran the full suite three times — 3.12, 3.13, 3.14 — with coverage instrumentation, roughly 15 minutes and three runners per PR. PRs now gate on the 3.12 floor without coverage; pushes to main keep the full matrix, the litellm-free dependency profile, and Codecov upload. PR gate ~15 min → ~4–6 min, three runners → one. Version-specific regressions move from PR-time to merge-time detection, still strictly before release.
Wall-clock in the suite itself:
install.shruntime-selection tests were the largest CPU sink at ~80s, because macOS charges a ~0.3s system scan on the first exec of every newly created executable and the harness wrote fresh stubs per test. Caching the stubs took the worst test 7.59s → 0.64s and the file ~80s → ~33s (#2134).- The codex help-probe contract tests stalled a real 5s each on the probe budget; injecting
HELP_PROBE_TIMEOUT_SECONDStook 5.01s + 5.01s + 3.02s → all sub-second, with the production default unchanged. The contract under test was that an overrun means uncertainty, not how long the overrun lasts (#2136). - Retry-ladder tests slept through the real production backoff. Mocking only those sleeps took each affected test ~3.0s → ~0.01s while still asserting the retry attempt counts (#2137).
- The picker projection budget benchmark — the single largest time block in the unit suite, two parametrizations alone at 16.6s and 15.9s — halved its bulk event count to 50k. It asserts ratios, not absolutes (#2133).
- Fingerprint tests stub git identity and version probes (#2138); conftest renders logged exceptions with plain tracebacks instead of rich ones (#2132);
api_retrybackoff is overridable for shell tests (#2135).
And tests that stopped breaking for the wrong reason. Documentation contract tests now assert durable anchors — section headings, command and tool invocation strings — instead of verbatim prose, some of which had been pinned to specific line-wrap positions (#2131). Removing a documented command still fails the suite; rewording around it no longer does. test_detached_auto_docs.py shrank 969 → 518 lines while keeping every behavioral test. Copy-paste variants in the orchestrator and auto suites were folded into parametrized tables (#2139, #2140, #2141), and the install one-liner test now checks every documented one-liner rather than only the first (#2130).
Track 4 — auto stops overstating what it finished
The loop's account of its own work is load-bearing. Four changes made it more honest.
- The Seed QA gate is advisory rather than a dead end (#2119), and now carries a bounded, normalized transport diagnostic in the durable advisory event so a transient evaluator failure leaves evidence instead of silence (#2144).
- Retired persisted phases explain their migration path before the production watchdog can rewrite the result as a generic timeout (#2145). A migration notice reported as "timed out" sends the operator to the wrong problem.
runsuccessors are delegated to the run job's own chain (#2120), andautono longer calls a Seed complete when it never ran a verified product (#2127).
Toward 1.0.0
The remaining distance is not measured in features. It is measured in how many claims this system makes that it cannot back — and this release retired several: in the install surface, in the health report, in the audit metadata, and in the loop's own account of what it finished. Meanwhile the door widened, and more of the work now arrives from outside this desk.
That is what 1.0.0 requires. There is less of it left than there was.
Full Changelog: v0.51.5...v0.51.6
What's Changed
- docs(readme): add one-line install above the hero demo table by @Q00 in #2122
- fix(test): check every documented install one-liner, not just the first by @Q00 in #2130
- fix(auto): stop calling a Seed that never ran a verified product by @Q00 in #2127
- feat(auto): delegate run successors to the run job's own chain by @Q00 in #2120
- fix(auto): make the Seed QA gate advisory instead of a dead end by @Q00 in #2119
- fix(hooks): fail open when plugin cache root disappears by @dj-wishket in #2111
- test(conftest): render logged exceptions with plain tracebacks in tests by @Q00 in #2132
- test(persistence): halve picker budget benchmark bulk size to 50k by @Q00 in #2133
- test(scripts): cache install.sh test stubs to dodge macOS first-exec scans by @Q00 in #2134
- ci(pr-hygiene): make api_retry backoff overridable for shell tests by @Q00 in #2135
- test(providers): inject codex help-probe timeout instead of waiting it out by @Q00 in #2136
- test: mock retry-backoff sleeps, keep the retries by @Q00 in #2137
- test(evolution): stub git identity and version probes in fingerprint tests by @Q00 in #2138
- test(orchestrator): fold copy-paste variants into parametrized tests by @Q00 in #2139
- test(auto): parametrize domain inference phrase-to-class cases by @Q00 in #2141
- ci(test): gate PRs on the 3.12 floor; full matrix and coverage on push by @Q00 in #2142
- test(cli): table-drive the runtime-only backend setup tests by @Q00 in #2140
- refactor: put the pre-anchor legacy identity path behind one observable seam by @sumin220 in #1899
- feat(cli): add installation surface doctor by @lee3Q in #2034
- test(docs): assert durable anchors instead of prose in docs contract tests by @Q00 in #2131
- fix(auto): retain Seed QA evaluator diagnostics by @Q00 in #2144
- RFC: native Windows Codex Desktop HTTP task persistence by @bokjk in #2101
- feat(providers): add DeepSeek Harness (dsh) ACP completion backend by @Q00 in #2143
- fix(auto): preserve retired phase migration over watchdog by @Q00 in #2145
- fix: deliver the update nudge to plugin users by @sumin220 in #2090
- feat(cli): surface zcode CLI model-config readiness in setup and health by @tmdgusya in #2147
New Contributors
- @dj-wishket made their first contribution in #2111
- @tmdgusya made their first contribution in #2147
Full Changelog: v0.51.5...v0.51.6