Validate lock freshness, preserve the pip runtime capability and N-1 updater bridge, synchronize the uv root version during releases, and align install documentation and regression tests.
Build PyInstaller from a portable-Python venv, exercise the desktop launcher on Ubuntu 22.04, and keep RPM staging valid across filesystems.
Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
Ouroboros now delivers the Claudexor engine it integrates (PR #101 shipped
the integration without the runtime; a user upgrading in-app hit a dead
`claudexord_not_installed` Connect). This lands the owner-locked design:
- one exact pin (`ouroboros/claudexor_runtime_pin.json`, now bound to the
public Claudexor 3.3.7 bytes: build a4b004d7, sha256 fe07b839…, official
Node 24.16.0 for all five platforms) drives seed, download, verify and
next-spawn selection; a filled pin never degrades to a PATH binary;
- hybrid delivery: the release archive ships as an offline seed in new
DMG/tar/zip bundles and downloads foreground-only for upgraded old
installs, strictly inside an explicit user action (Connect, Repair or a
delegated/review start) with visible progress;
- one morphing Connect button (Install/Update/Fix & connect); updates stage
side-by-side and activate at the next natural daemon start or Ouroboros
restart, never hot-swapping a live daemon; a repair never replaces the
serving target of a live matching daemon;
- 3-OS CI gate and release-artifact smokes now exercise the real managed
chain (install → exact probe → owned daemon → delegated run →
identity-bound graceful stop) instead of `npm install -g claudexor@next`;
- Windows fail-fast helper for critical PowerShell 5.1 steps, utf-8-pinned
subprocess decoding, handshake reads the frozen `engine.sha` contract.
Review: triad (fable, sol scope, gemini) + adjudicated batch + confirmation
+ pin confirmation, all SAFE; suites on this base: Python 7775/1 skipped,
web 138/138, delivery tests 17/17, managed fixture smoke end-to-end.
Co-authored-by: Claudexor <noreply@claudexor.dev>
Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
Two structural meta-classes from a terminal-bench forensic audit (BIBLE P2):
1. Typed provider-boundary normalization. An OpenRouter HTTP-200 whose BODY
carries a transient provider error (429/5xx) is no longer misread as a
finish_reason=null "incomplete response": the transport detects the typed
body-error and reroutes ONCE to a HEALTHY endpoint of the SAME model (strips
replayed reasoning_details + drops the allow_fallbacks=false provider pin),
never cross-model. A permanent body error (401/quota/bad_request) fails fast
instead of burning the transient retry budget.
2. Unified terminalization. Provider-death joins the same honest best-effort
finalize+salvage shelf as deadline/budget/round-limit (one tool-less final
that benefits from the reroute -> best_effort; else the last assistant text —
current transcript or durable latest_llm_response_text — is salvaged) instead
of discarding the workspace with a bare error string.
Plus:
- Reviewer-slot SSOT: an ARBITRARY configured reviewer count is honored via
config.adaptive_quorum (no <2 hard gates / [:3] cap). A single configured
reviewer runs as a loud + durable single_reviewer_no_diversity degraded mode
across plan_task, skill trust-gate, commit, scope, and acceptance; a
configured-but-under-quorum multi-scope run blocks under blocking enforcement
and stays advisory under advisory enforcement.
- Acceptance review: a compact anti-derailment improvement capsule (tier + <=3
actions + coach) fed back in BOTH auto and required, bounded to ONE injection
while the REVISED final deliverable is re-reviewed so its verdict (not the
pre-revision one) is authoritative; the full ReviewRunResult always lands on
the objective axis (a parse-degraded slot never poisons a clean quorum).
- Tool robustness: binary stdout decodes tolerantly (errors='replace') at every
command boundary; a present-but-unchanged declared output is a cosmetic
ARTIFACT_OUTPUT_NOTE (not a blocking error or a false registration); vlm_query
reads the active workspace + artifact roots while honoring the protected-
artifact read_bytes policy.
- macOS bundle signing integrity: the signed/notarized .app precompiles + SEALS
its bytecode (build-time compileall with --invalidation-mode unchecked-hash,
replacing delete) so it never writes __pycache__ into its own bundle at runtime
(codesign seal break -> AppTranslocation); sys.dont_write_bytecode is set
before any project import and the bytecode env is forwarded through every
curated-env embedded-python spawn.
Verified: synthetic regression tests per fix class; full suite green; reviewed to
convergence by the real triad+scope gate (6 rounds) + adversarial subagents +
claudexor codex final review (SAFE TO SHIP).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Introduce a derived code-intelligence layer with a read-only query tool, ripgrep-backed search, and clearer post-task self-improvement controls so Ouroboros can navigate larger codebases without regex-heavy guesswork.
Structurally closes the subagent worker-crash, ghost-task, and stuck-spinner
classes across all platforms, makes Ouroboros usable with any single provider
key, and ships node-runtime skill support.
- Workers: macOS/Windows use spawn (Linux keeps fork); central OUROBOROS_IN_WORKER
no-proxy policy removes the macOS _scproxy fork SIGSEGV class. Signal crashes are
terminal (no retry) for all task types.
- Lifecycle: monotonic write_task_result guard (terminal/cancel sticky); live
cancel_task + cancel_requested latch; terminal task_done on every crash/kill/
timeout/cancel path; snapshot restore skips terminal; schedule fail-fast when the
worker pool is disabled. No ghosts, no perpetual spinner (incl. reconnect reconcile).
- Subagent UI: Variant A parent dashboard (in-place rows, child progress/terminal
routed to parent, no duplicate child card).
- Providers: Cloud.ru is a first-class exclusive-direct provider (review/scope
fallback + static pricing). New-user defaults: review claude-opus-4.8, Claude Code
opus[1m]; existing anthropic-only migrate 4.6->4.8.
- Skills: skill_preflight tolerates missing/killed validators; build bundles a
signed Node.js LTS (resolve_bundled_node) for node --check and node runtimes.
- Docs: README OuroborosHub badge/callout; ARCHITECTURE bundled-node + defaults.
Reviewed via multi-model adversarial (2 rounds) + Ouroboros triad/scope review
(converged). Local suite: 3207 passed, 1 skipped.
Consolidate repeated gateway, review, skill lifecycle, marketplace, memory/context, release, and web UI paths while preserving public API shapes, review gates, and runtime contracts.
Verification: python3 -m pytest tests -q --tb=short; external triad review PASS with scope review skipped only for context budget advisory.
Selectively port 5 PR #25 commits into ouroboros (clipboard image
paste, autocorrect-off on chat textarea, integration-test CI tier,
optional macOS code signing & notarization, secrets→env fix for
step-level if-conditions in GitHub Actions. Plus chat bottom
gradient migration from #chat-input-area's background to a dedicated
.chat-bottom-fade sibling layer (z-index 4, pointer-events:none) so
the textarea no longer optically sinks into the dense end of the
gradient. Plus retire ouroboros-three-layer as a dev branch — ouroboros
is now the single dev branch.
(1) Clipboard image paste: web/modules/chat.js registers a paste
listener on #chat-input that scans e.clipboardData.items for image/*,
calls getAsFile(), wraps as File(clipboard-<unix-ts>.<ext>), and
stages via the same pendingAttachment slot the paperclip uses (no
inline upload — uploads when Send/Enter fires). Non-image paste falls
through natively. The paperclip change handler was extracted into a
shared stagePendingFile() helper so both entry points are identical.
The textarea gains autocorrect=off autocapitalize=off
spellcheck=false so code/identifiers/slash-commands are not silently
rewritten by the browser.
(2) Chat bottom-fade layer: web/style.css strips the linear-gradient
background and mask-image from #chat-input-area (which keeps z-index 5),
and adds a new dedicated sibling .chat-bottom-fade (position:absolute;
bottom:0; pointer-events:none; z-index:4; height:200px) below the
input dock. Mobile @media (max-width: 640px) uses
calc(200px + env(safe-area-inset-bottom, 0px)) so the fade fully
covers the iOS-home-indicator safe area at the worst-case input-area
state (attachment + fully-expanded textarea).
(3) Integration tier in CI (Tier 2.5): new integration-test job runs
pytest tests/test_provider_integration.py -m integration on
ubuntu-latest with OPENROUTER_API_KEY/OPENAI_API_KEY/ANTHROPIC_API_KEY
in repo secrets. Triggered on push to main / ouroboros / ouroboros-stable,
on workflow_dispatch, and on tag v*. Locally the pytest
marker plus addopts -m 'not integration' in pyproject.toml exclude
the tests from default runs.
(4) Optional macOS code signing & notarization (Build tier): when
BUILD_CERTIFICATE_BASE64 / P12_PASSWORD / KEYCHAIN_PASSWORD /
APPLE_TEAM_ID are configured as repo secrets, the build job creates
a temporary keychain, imports the Developer ID certificate, and runs
bash build.sh (which signs .app and .dmg via env-overridable
SIGN_IDENTITY). With APPLE_ID + APPLE_APP_SPECIFIC_PASSWORD also
present, build.sh runs xcrun notarytool submit --wait followed by
xcrun stapler staple. Stapler/notarytool failures are wrapped in
if/else (set -e exempt) so transient Apple-CDN flakes become warnings
instead of dropping the macOS DMG from the release. A NOTARIZE_OUTCOME
enum drives a 4-case summary cascade (success / staple_failed /
submit_failed / unconfigured) plus a defensive *) arm. With no Apple
secrets the build falls back to OUROBOROS_SIGN=0 bash build.sh
(identical to v5.0.0). Cleanup keychain step runs with
if: always() && matrix.os == 'macos-latest' &&
env.BUILD_CERTIFICATE_BASE64 != '' so signing material never persists
across runs and the bash-only security delete-keychain invocation
never fires on Linux/Windows shards. The Import step sets
trap 'rm -f "$CERTIFICATE_PATH"' EXIT so the temporary .p12 is
removed on every exit, including a set -e abort mid-import.
(5) secrets→env fix for step-level if (v4.47.1 lesson): GitHub Actions
rejects secrets.* references inside step-level if expressions
(Unrecognized named-value: secrets). All Apple signing secrets
are mapped at the build job's env: block with a
${{ matrix.os == 'macos-latest' && secrets.X || '' }} guard so
non-macOS shards receive empty strings — Linux/Windows never see the
signing material. Step-level if reads env.* instead. New
docs/DEVELOPMENT.md section GitHub Actions: secrets in step-level if
conditions formalizes the rule with worked examples.
(6) Tests: tests/test_chat_logs_ui.py gains 3 new tests
(test_chat_input_disables_autocorrect, test_clipboard_paste_handler_exists,
test_chat_bottom_fade_is_separate_layer); tests/test_build_scripts.py
gains a new TestMacOSSigning class with 7 contract tests (job-level
secrets env mapping with matrix.os guard, no secrets.* in any if-block,
Import step gates on full secret set, Cleanup keychain always() +
matrix.os + env guard, build.sh SIGN_IDENTITY env override, notarytool
+ stapler optional gate, stapler-failure-as-soft-warning regression);
tests/test_provider_integration.py is added new with 6 tuple-aware
tests (OpenRouter / OpenAI / Anthropic × {basic, isolation}) handling
the post-v4.44.0 LLMClient.chat() (msg, usage) tuple plus Anthropic's
list-of-blocks content. The existing
test_chat_floating_overlays_have_readable_glass_backing was updated
for the migrated bottom-fade contract (asserts no backdrop-filter on
.chat-bottom-fade across base + mobile @media rules).
(7) Branch consolidation: ouroboros-three-layer is retired as a dev
branch. ouroboros is now the single dev branch.
.github/workflows/ci.yml (Tier 1 quick-test trigger + path-filter
branches list + build job's OUROBOROS_MANAGED_SOURCE_BRANCH default),
build.sh / build_linux.sh / build_windows.ps1 (each script's
${OUROBOROS_MANAGED_SOURCE_BRANCH:-...} default), and four test files
(test_release_workflow.py, test_launcher_sync.py,
test_git_ops_recovery.py, test_build_repo_bundle.py — 21 occurrences
total) all switch from ouroboros-three-layer to ouroboros. Historical
references in older changelog rows (v4.50.0-rc.7) and in ouroboros/*
module comments about the Phase 2/3 three-layer architecture refactor
are intentionally preserved — those describe the architectural
refactor, not the dev branch name. The remote
managed/ouroboros-three-layer branch is deleted in the same release.
Adversarial multimodel review (gemini-2.5/gpt-5.5/claude-opus-4.7
critics in parallel, full-context, 4 rounds): 32 findings total → 18
fixed, 14 rejected/deferred with explicit per-finding reasoning. All
three critics independently reach SAFE TO COMMIT after round 4.
Ouroboros triad+scope review (production code path
parallel_review.run_parallel_review with full-repo pack, 2 rounds):
4 findings (2 scope-critical + 1 scope-advisory + 1 triad-advisory)
→ all 4 fixed. Round 1 caught matrix-shard secret leak; round 2
caught documentation/runtime command mismatch + cert-file cleanup
gap on set -e failure.
VERSION 5.0.0 → 5.1.0 (MINOR: additive features + UX/CI polish, no
breaking change). Release invariant synchronised: VERSION,
pyproject.toml [project].version, README badge, docs/ARCHITECTURE.md
header — all 5.1.0.
Note on changelog rolloff: the v4.50.0-rc.2 minor entry is rolled
off proactively to keep one slot below the P7 5-minor-row cap. Its
full body remains at git tag v4.50.0-rc.2.
EOF
)
Closes the re-audit cycle. Six non-committing advisory+triad+scope
cycles converged with 0 open findings before this commit.
Extension runtime:
- extension_loader.py stages each load under data/state/skills/<name>/__extension_imports/<uuid>/skill/
to defeat Python module caching on rapid in-place edits; fail-closed if
any symlink in the skill tree resolves outside the reviewed checkout.
- extensions_api.api_extension_manifest reports live-SSOT load_error,
not the stale discovery copy, so index and manifest agree.
- tools/registry.list_non_core_tools() now merges live ext.* tools.
Release / packaging guards (BIBLE.md P7):
- scripts/build_repo_bundle.py fail-closed if no release tag is resolved,
verifies the tag is annotated (git cat-file -t == tag), and that it
points at HEAD.
- build.sh / build_linux.sh / build_windows.ps1 enforce the same three
checks before invoking PyInstaller. Synthetic/fake tags no longer
accepted.
- _validate_source_branch no longer treats an ls-remote-only branch as
usable; requires local ref availability, symmetric with
_ensure_source_sha_tracks_branch.
- release_sync._normalize_pep440 now collapses alpha->a and beta->b per
PEP 440 canonical pre-release spelling.
Onboarding preservation:
- Wizard no longer silently wipes OPENAI_BASE_URL, OPENAI_COMPATIBLE_*,
CLOUDRU_FOUNDATION_MODELS_BASE_URL on re-run. The wizard only resets
keys it actually exposes.
Docs and prompts sync:
- ARCHITECTURE.md describes the bundle-bootstrap model, the
__extension_imports/ staging surface, the build-script release tag
prerequisite, the extension HTTP review endpoint, and
VALID_EXTENSION_ROUTE_METHODS as part of the frozen contract.
- BIBLE.md + prompts/SYSTEM.md release invariant now distinguishes
author-facing spelling (VERSION / README / tag / ARCHITECTURE) from
the PEP 440 canonical form required by pyproject.toml.
- prompts/SYSTEM.md Immutable Safety Files list matches
SAFETY_CRITICAL_PATHS exactly (BIBLE.md included).
- docs/CHECKLISTS.md row 1 explains the author-facing vs PEP 440 split.
Runtime SSOT:
- server.py::_run_supervisor feeds workers.init the manifest-driven
branch names from _runtime_branch_defaults() instead of hardcoded
ouroboros / ouroboros-stable.
- contracts/skill_manifest.py accepts body-only instruction-skill
markdown that starts with a --- thematic break.
Regression coverage added for every real fix above across
test_extension_loader, test_extensions_api, test_build_scripts,
test_build_repo_bundle, test_launcher_sync, test_onboarding_wizard,
test_packaging_sync, test_release_sync, test_contracts, plus a new
test_release_workflow guard for the CI release path.
VERSION carriers synchronized:
- VERSION = 4.50.0-rc.3 (author-facing)
- pyproject.toml = 4.50.0rc3 (PEP 440 canonical)
- README.md badge + Version History row = 4.50.0-rc.3
- docs/ARCHITECTURE.md header = 4.50.0-rc.3
Branch `ouroboros` was seeded from an `.app` bundle snapshot
(`6700358 Initial commit from app bundle`), not from `main`, so the
release pipeline (build scripts, PyInstaller spec, launcher runtime,
vendored Python framework, CI workflow) never landed on this branch.
Import those files verbatim from `origin/main` (76bf13c) so a tagged
push can trigger the existing tag-driven release pipeline.
Imported verbatim from `origin/main`:
- .github/workflows/ci.yml Three-tier CI (push -> quick
tests, stable/tag -> full matrix,
v* tag -> build + GitHub Release
with `prerelease: contains(...,
-rc|-alpha|-beta)`).
- build.sh / build_linux.sh / PyInstaller + Playwright Chromium
build_windows.ps1 / Dockerfile bundling for each target (the four
files `tests/test_build_scripts.py`
assertively requires).
- Ouroboros.spec PyInstaller entry spec.
- entitlements.plist macOS codesign entitlements.
- launcher.py Native launcher that bootstraps
the embedded python-standalone
interpreter and runs the agent as
a subprocess.
- scripts/download_python_standalone.sh / .ps1 / pyi_rth_pythonnet.py
- Python, Python.framework/ Vendored macOS launcher-side
Python 3.10 framework.
- certifi/, jsonschema/, Marker + data files consumed by
jsonschema_specifications/ the runtime-loaded agent deps.
Adapted for Phase 1-6:
- Ouroboros.spec datas now contains ('skills', 'skills') so the
bundled Phase 5 weather reference skill under `skills/weather/`
actually ships inside the .app / .exe / tarball. Without this the
Skills page on a packaged build would show "no skills discovered"
even with the bundled reference in source. Docstring updated to
document the new bundled payload.
Verification:
- `pytest tests/test_build_scripts.py tests/test_release_sync.py`
passes locally (47 asserts; all Playwright + PyInstaller ordering
invariants + release-sync carrier logic hold after the import).
- `python -c "import ast; ast.parse(open('Ouroboros.spec').read())"`
parses.
Not imported from main (intentional):
- `.pytest-tmp-run`, pytest-cache dirs, and other transient files.
- No existing file was overwritten by the checkout; the import is
purely additive on top of the Phase 1-6 tree.