Commit graph

55 commits

Author SHA1 Message Date
Ouroboros
c839e532eb Merge current ouroboros and regenerate combined data inventory
Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
2026-09-20 23:11:14 +03:00
Ouroboros
224f33f81b
feat: add honest desktop notification attention cue (#1158)
* fix(v7.2.2): preserve host message authorship through chat and replay

Host-composed command replies, runtime diagnostics, admission and lifecycle
notices now carry role="system" and a descriptive system_type at their
producer; send_with_budget persists both on progress records and history
replays the recorded voice, so a reload no longer re-narrates host text as
Ouroboros. Model narration, proactive replies, final answers and question
pointers stay model-authored, selected by the existing narration fact rather
than by reading text.

The Host Service named-operation view accepted only direction="out" terminal
rows, so a typed command reply would have stayed pending forever; it now
recognizes either output voice while keeping the exact-origin ownership check.

tests/test_host_message_voice.py scans runtime send calls and literal chat
envelopes with counted, reasoned model/transport exceptions, so a new
unstamped producer or a stale exception fails; computed aliases remain a
documented review duty. The complete personal census of 92 classified sites is
retained as task artifact host-message-census.json.

DESIGN defines authorship, the System row and the markdown asymmetry;
CHECKLISTS item 30 now covers backend UI-message producers, which closes the
stale pointer in the design-system chapter. Pre-existing unkeyed live-header
clearing and the untyped terminal-host-notice contract are unchanged.

Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>

* feat(v7.4.0): add honest desktop notification attention cue

Add an optional launcher request_attention bridge that raises the live desktop window and requests one platform system sound, preserving browser and in-app fallbacks. Document the capability boundary, bump release carriers, and add focused tests.

Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>

---------

Co-authored-by: Ouroboros <ouroboros@local.mac>
Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
2026-09-20 20:03:32 +03:00
Ouroboros
73e10a38a9 Harden delegated workspace authority and bootstrap recovery
Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
2026-09-20 18:14:24 +03:00
Ouroboros
b623a70b0f docs: condense launcher persistence note within module budget 2026-09-19 04:49:31 +03:00
Ouroboros
e309571435 feat: add client-local Light, Dark and System appearance 2026-09-19 04:49:31 +03:00
Ouroboros
6309b29038 Fix subscription sign-in handoff across setup hosts
Share the bounded native external opener between setup and main windows, and route login-card clicks through the existing browser/desktop/Telegram helper. Preserve explicit Copy, modifier clicks, parent-frame handoff and honest missing-host recovery.

Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
2026-09-18 23:22:20 +03:00
Ouroboros
4ea34c1b6c Merge current development into runtime observation fixes 2026-09-18 16:52:00 +03:00
Ouroboros
071ba06370 Keep runtime history and restart observations bound to their actual sources 2026-09-18 16:40:29 +03:00
Ouroboros
a27716eb6c feat(android): carry the experimental host onto the current core 2026-09-13 22:40:38 +03:00
Ouroboros
e8e3af4d85 Route runtime mode changes through the owner endpoint
Use native desktop confirmation without handing new modes to stale mutating bridges, and fall back to the shared UI confirmation for older shells.

Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
2026-09-11 14:35:42 +03:00
Ouroboros
74426b23bc Persist Cyber Pro from the desktop owner flow
Use the existing owner settings writer for the confirmed launcher mode change while keeping the agent boot ratchet intact.

Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
2026-09-11 13:46:47 +03:00
Ouroboros
a3d53963f1 Keep task completion responsive and preserve shared execution 2026-09-09 14:40:45 +03:00
ouroboros-agent
673991ee13 Preserve ordinary skill development and lifecycle state
Integrate the approved lifecycle source tree eb07a1f9853ec07f88fd30e7747256871fa21e55 on target 5c3f47ce6c. Carry the approved lifecycle checklist spans, exact trace-fixture migration, Read-only documentation wording and the two retired-oracle classification rows supplied with the installer stream.

Keep review, grants, dependencies, enablement and execution provenance separate. Reuse the shared lifecycle effect and rollback owners while preserving the selected payload revision and ordinary development capabilities.

Validation: 82 lifecycle/review/rollback neighbor tests and 28 classification/trace tests; whole-tree Ruff F, size manifest, generated inventories and domain checks. Original source trees were not modified. Formal review and publication remain pending.
2026-09-06 20:23:32 +00:00
Ouroboros
9698e2e077 Merge upstream ouroboros 23ab428f into the v7 line: absorb 407 commits into the module split
Second parent is the frozen upstream `ouroboros` head (23ab428f, 407 commits
since the merge base a76961de); first parent is v7.0.0-rc.8 (18b9832e).

Every upstream change lands in v7's owning leaf: S1 transplants keep upstream's
bodies (comments verbatim) under the call-time handle idiom, S2 hand-merges keep
both intents, S3 keeps v7 only with proof (retired 7.0 ABI surfaces, superseded
mechanisms). Per-symbol relocation ledger: docs/archive/v7next/LEDGER_CORRECTIONS.md
(F2 absorption section). Provisional decisions awaiting owner ratification:
D-18 (two-destination symbols), D-19 (acceptance rows follow upstream R2),
D-20 (acceptance_dialogue stays deleted), D-21 (tools/registry.py: facade
import block only).

Docs: upstream ARCHITECTURE/DEVELOPMENT as the base with compact v7 deltas;
bookkeeping moved to docs/archive/v7next. Size-ratchet manifest, domain
manifest and generated inventories regenerated; new leaves: tools/write_shape
walker, gateway/cost_breakdown, tools/core_secret_paths; provider_catalogs.py
and acceptance_dialogue.py removed (v7 owners).
2026-09-04 19:32:55 +00:00
Ouroboros
712bd176a4 Read the headless shutdown predicate once for the teardown reason and exit code
_run_headless_main consulted _shutdown_event twice around a non-instantaneous
stop_agent(): a signal landing in between could journal a crash-fuse exit as
headless_shutdown while still exiting nonzero (or the reverse). Capture the
predicate once before stop_agent() and use it for both; the variable name
carries what the retired comment said, keeping launcher.py at 1600 lines.
The source-string test that pinned the old literal now pins only the
panic_stop reason, whose branch has no behavioural twin; the shutdown versus
crash-fuse split is already proven behaviourally in the same file.
2026-09-02 17:12:38 +00:00
Andrei Kaznacheev
b65db00d92 Record the real teardown reason in the orphan-cleanup journal
_kill_orphaned_children hardcoded "window_close" into the recorded-server
cleanup log, so every teardown — panic stop, headless shutdown, the crash
fuse, startup abort, startup failure — read as a closed window in a
post-mortem. Thread a reason parameter through (default stays
window_close for the window path) and name each call site's actual
trigger; the headless keep-alive teardown discriminates
headless_shutdown from crash_fuse with the same predicate its exit code
already uses on the next line.

The reason is journalled at teardown ENTRY, not only on the
recorded-process row: on normal teardowns stop_agent() has already
consumed that record (logged as stop_agent/agent_exit), so a row-only
reason would usually never land — the adversarial review proved exactly
that with a live harness. Existing teardown-order tests pin the
per-scenario reasons, and a new test pins the journal line with no
record on disk at all.

Closes #153.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-01 23:51:12 +04:00
Ouroboros
9723251f98 persistence: rotate the remaining hot logs behind chain-aware readers (CPL4-C1..C5, C12)
events/tools/supervisor/task_reflections now rotate on the supervisor tick
with the existing rotator; agent_stdout.log is size-capped in the launcher
copy thread (2 MB x 4, mirroring server.log). events.jsonl rotation lands
BEHIND its custody readers: delegate_custody replay/fault-scan/timing/
invocation records, complete_custody_rows, the settled-terminal cursor
(now a monotonic chain offset), the legacy usage import snapshot, the
swarm-fanout rollup and the worker boot verify all read the rotated
archive chain (utils.jsonl_chain_handles: open-live-first + inode dedup,
rotation-race-safe). memory.read_jsonl_tail backfills bounded tails from
the newest archive segments. Hot-store tripwires: events/tools thresholds
become 8 MB rotation-regression tripwires, supervisor/task_reflections
gain rows, and a 100 MB events-chain watch inherits the replay-degradation
signal. skill_review_history readers are byte-bounded (CPL4-C12,
find_history_job_bounded idiom); lifecycle terminal rows already persist
their ordinals, so bounded counters stay exact inside the window.
2026-09-01 17:35:37 +00:00
Ouroboros
2085019152 merge: absorb upstream drift b9f7597f..8d13373b into v7next (F6 rolling sync)
Upstream = semantic truth, campaign = structural truth. Every upstream
semantic delta lands in its campaign owner leaf; upstream duplicate
extractions do not survive as twins:

- acceptance_dialogue.py -> folded into loop_acceptance{,_review}.py
  (A-material paid identity, free replay, identical-refusal terminal,
  dialogue history, inconclusive-dialogue reducer semantics)
- delivery_protocol.py -> folded into loop_delivery.py (hold-control
  literals, RecursionError-degraded and trailing-object protocol parsers
  over the shared strip_protocol_fence normalization)
- chat_delivery_events.py -> folded into events_chat_delivery.py
  (unified _delivery_chat_id incl. chat-0 media, send_links/send_quiz,
  registry merged via **_CDE)
- events review-wave handler retired for telemetry_events.py registry
- python_interpreter.py -> process_interpreters.py (upstream as-is);
  registry/tool_resolution/shell retargeted; interpreter_attestation
  scope in registry_core; node post-gates predispatch
- R5 typed process facts: process_facts.py channel + loop-side merge
  into the typed result_meta; describe_returncode SSOT retargeted
- deadline_utils.deadline_expired public name adopted (rename-class);
  test pins moved off the private spelling
- protected surfaces (BIBLE.md, safety.py, CHECKLISTS.md, registry.py,
  gateway/contracts.py incl. endpoint_index extraction) landed as-is
- web wave, VERSION 6.113.5, package data landed as-is
- size_ratchet_manifest regenerated via scripts/regenerate_size_ratchet.py
  (band rationales recorded for the F6-grown leaves); tools/core.py
  link/quiz/escalate spans moved to core_artifacts.py to stay under the
  giant gate; _run_shell and registry dispatch shaved under the
  function gate via shell_process/registry_core helpers
2026-09-01 11:12:47 +00:00
Anton Razzhigaev
22744c4d3f Honest shell degradation everywhere: mailto, settled browser failures, framed helpers, disposer
Triad-review fixes for the desktop-shell link parity:

- The file helpers (openViaHostBridge/downloadViaHostBridge) now resolve
  the bridge through the shared shell resolver. Inside the framed wizard
  the interceptor saw the parent bridge while the helpers read only their
  own window - a future loopback file link there would have fallen through
  to window.open and re-entered the shim (latent async loop).

- mailto: links classify as external and the launcher accepts them in
  open_external_url (webbrowser.open hands them to the OS default mail
  handler); they were a silently dead surface in the shell.

- The ancient-launcher file class (no file bridge at all) no longer
  passes through to the dead native default: it degrades to the same
  copy-link-plus-toast fallback as external links. The recursion guard
  stays - the helpers are simply never entered in that state.

- open_external_url no longer reports {ok: true} for a browser that
  provably failed to launch: the detached opener records its settled
  result (True/False from webbrowser.open, or the exception) in an
  outcome list, and the bridge method bound-joins it (3s) - a settled
  failure returns {ok: false}, a still-running open keeps the detached
  semantics. The JS side degrades any {ok: false} to copy-link-plus-toast.
  Compensating compaction keeps launcher.py at 1598/1600 (urllib imports
  hoisted to module level; two mechanical line merges).

- The framed document's pywebviewready listener on the PARENT window is
  released on the frame's pagehide via an AbortController (disposer rule:
  in an ordinary browser the event never fires, and reopening onboarding
  must not accumulate closures on the parent).

- ARCHITECTURE: the bridge paragraph now names the two-document install
  (SPA + framed wizard resolving the bridge from its parent) and the
  extended degradation chain.

Tests: mailto classification/routing, settled-failure copy-link fallback,
ancient-launcher copy-link for both the listener and the shim, framed
helpers reaching the parent bridge, parent-listener release on pagehide,
and the outcome-recording contract of the detached opener (True/False/
exception plus the outcome-less fire-and-forget callers).

Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
2026-09-01 05:12:32 +00:00
Anton Razzhigaev
bc1cf19960 Shell interceptor in the wizard document; verb-correct toasts; bridge envelope parity
Review fixes for the desktop-shell link-parity phase:

- The onboarding wizard is its OWN document (the overlay frames /onboarding,
  which loads onboarding_wizard.js), so the SPA's interceptor could not see
  the Agents step's primary "Open sign-in link" (target="_blank") - still a
  silent no-op in the shell. The wizard now installs the same interceptor
  (two-document pattern, like the Alt menu-lock guard). The bridge is
  resolved lazily through one shared helper - the frame is same-origin, and
  pywebview injects window.pywebview only into the top-level window, so a
  framed document reads it from the parent; pywebviewready is armed on both
  windows, and a cross-origin parent resolves to null (not our shell).

- launcher.py open_external_url: same try/except {ok, error} envelope as the
  sibling bridge methods (a thread-start failure must be a bridge error, not
  a JS promise rejection). Compensating compaction in the same file: the
  three confirmation methods now share one _native_confirm staticmethod
  instead of three copies of the same lambda (1591/1600 lines).

- filenameForMime: text/plain maps to the conventional .txt (alias table;
  unknown subtypes still fall back to .bin).

- Failure toasts name the verb that failed: download file / open file /
  open link / save file.

Tests: framed-document parent-bridge resolution, parent pywebviewready
install, wizard source pin, .txt aliasing, verb-correct failure toasts.

Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
2026-09-01 04:50:43 +00:00
Anton Razzhigaev
6eeae750e4 Desktop shell link parity: external/byte bridge routes, one interceptor, Share removed
pywebview creates the desktop window without new-window or download
delegates, so window.open, <a target="_blank"> and <a download> were
silent no-ops in the app while working normally in browsers.

launcher.py (MainApi):
- open_external_url(url): absolute http(s) only, rides the existing
  detached browser opener; same {ok, error} shape as the other methods.
- save_bytes_to_downloads(filename, b64): decodes live base64 payloads
  into ~/Downloads via the shared _unique_bridge_target collision helper.
- The shared loopback file guard now also admits /api/tasks/... paths
  (durable chat-media artifacts); host and exact-port checks unchanged.

web/modules/ui_helpers.js: ONE shell-only interceptor (delegated click
listener for target="_blank"/download anchors plus a window.open shim),
wired from the app bootstrap and installed only when the pywebview
bridge is (or becomes, via pywebviewready) present - ordinary browsers
are untouched. It classifies each URL: loopback file forms ride the
existing host-bridge helpers, any other http(s) rides open_external_url,
data:/blob: payloads ride save_bytes_to_downloads. Bridge methods are
feature-detected per call: on an old packaged launcher the external
class degrades to copy-link plus toast, the bytes class to an honest
unavailable toast, and the file class keeps the native default when no
file bridge exists at all (recursion guard against the helpers' own
window.open fallback).

CONTRACT CHANGE (owner decision, postfix sprint D7): the Share action is
removed everywhere - the chat file dialog and the photo menu lose their
Share buttons and shareSource is deleted. navigator.share/canShare are
unavailable in the embedded WebView and the affordance is redundant next
to Open/Download/Copy. tests/test_files_ui.py deliberately drops the
share/canShare pins and now pins their absence.

docs/ARCHITECTURE.md documents the MainApi bridge contract (methods,
allowlist, interceptor, version-skew chain) in the Web UI section and
drops Share from the chat media description.

Tests: web/tests/desktop_shell_links.test.js (classifier, routing, skew
fallbacks, browser neutrality); chat_media.test.js Share-absence;
test_files_ui.py static pins for the new methods, the /api/tasks/
allowlist branch, and the JS fallback chain.

Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
2026-08-31 23:10:08 +00:00
Ouroboros
ec2cc3d188 v7next F1: domain D18 - launcher Windows-runtime split transplanted, proof-green
The one ledger-derived D18 split: launcher.py's Windows pythonnet/pywebview
preparation (_prepare_windows_webview_runtime, _show_windows_message,
_windows_dll_dir_handles) moves whole to ouroboros/launcher_windows_runtime.py
(MIGRATION_v7 rows 3998-4000). Drift-probe of the reference leaf against tip
monolith bytes was green on every span (ast=tokens=bytes=True, exit 0), so the
leaf is tip bytes; the facade re-exports the same objects and differs from the
reference facade by exactly upstream dc4c0204's delegated-restart hunk.
launcher.py 1582 -> 1484 lines; band re-entry carries an official rationale.

Reference pin test_launcher_reexports_the_windows_runtime_leaf appended to
tests/test_launcher_sync.py (byte-identical to the reference file afterwards).

Everything else the domain owns is classification, recorded in ledger
corrections 13-18: cli.py, ouroboros/__init__.py, launcher_server_reaper.py,
packaged_cli_install.py byte-identical across tip/reference/base;
launcher_bootstrap.py, platform_layer.py pure upstream drift (zero v7 delta);
packaged_cli.py::_save_settings HOT-DEFERRED with the half-absorbed settings
seam; the utils.py O_BINARY and reaper-test cross-OS deltas superseded by
upstream's own class fixes; packaged_runtime/packaging_sync reference deltas
deferred to their owning lanes (D33/F2) or F5 (unrowed).

(cherry picked from commit 6aad318d5a4100662ed6b31877f94d342c409b6f)
2026-08-30 18:38:32 +00:00
Ouroboros
dc4c02047c fix: harden delegated nanny recovery and custody
Require explicit configured-session starts, persist event-only wakes until transcript delivery, bind planned restart adoption to an exact normal-exit transaction, and reconcile every non-panic terminal custody obligation.

Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
2026-08-20 02:44:17 +03:00
Andrew
a70ab0cb54 review r2 (reaper): unbranded enumeration, root-first signalling, EPERM honesty
Panel findings applied. (a) Candidate enumeration moves from 'pgrep -fi
ouroboros' to ONE 'ps -ww -u <uid> -o pid=,command=' read: selection no longer
depends on the install path containing any particular word (REPO_DIR is
configurable), the exact-token matcher is the real filter, and BSD width
truncation is defeated at the source. (b) The proven ROOT is signalled
directly before kill_pid_tree runs — the tree kill's own child enumeration no
longer sits between revalidation and the first signal. (c) Death confirmation
stops trusting the platform's pid_is_alive, which folds every OSError into
'dead': EPERM means the process exists, and a survivor must block the boot
rather than be logged as reaped. (d) A whitespace DATA_DIR on the ps -E
platform gets the same named sweep-disabled warning as a whitespace repo path.
(e) The lifecycle loop's per-branch port sweeps are gone — _pre_generation_
cleanup owns the sweep at the top of every iteration.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-18 16:51:56 +03:00
Andrew
663d92e371 feat: the launcher reaps leftover same-install server generations before every boot
Field incident on a live install: SIGKILLed server generations leaked full
server.py processes that the custody reaper never sees (missing ledger entries
are exactly the defect), and concurrent generations shared the data directory
— every owner restart ended with the incoming generation SIGKILLed ~4s later
by a leftover one, twice collapsing the supervisor loop.

Holding the single-instance pid lock licenses the launcher to reap leftover
generations of ITS OWN install: a new ouroboros/launcher_server_reaper.py
finds same-user processes whose live command line is exactly
'<python> <REPO_DIR>/server.py' and whose live environment carries BOTH
launcher stamps (OUROBOROS_DATA_DIR equal to ours and
OUROBOROS_MANAGED_BY_LAUNCHER=1, read via the new tri-state
pid_environment_assignment_state in process_containment — /proc environ on
Linux, ps -E on macOS). Anything less — unreadable env, missing marker,
different data dir, a command merely mentioning the path — is spared and
named in the log. Proofs are revalidated immediately before the signal, kills
are pid-tree (workers hold their own sessions; a reused pgid reaches
bystanders), passes are bounded, and killed means CONFIRMED dead — a
signalled pid still alive is reported as a survivor, and a sweep aborted
mid-work reports survivors rather than reading as swept-clean. The sweep runs
at main() preflight and at the top of every lifecycle generation (ordered
recorded-cleanup, stray sweep, port sweep); a proven survivor suppresses
start_agent for that generation instead of booting a colliding second server.
Panic and window-close paths are untouched, and the custody ledger is never
consulted. The startup stray check stays report-only and now annotates each
finding same_install or foreign.

Behavioural tests cover the proof rules, spare classes, revalidation, fork
races, bounded passes with fresh survivor reads, the confirmed-dead
distinction, the aborted-sweep contract, and the lifecycle wiring (a proven
survivor suppresses start_agent); no test signals a real process.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-18 16:06:29 +03:00
Andrew
a83adc71fe review r2: disclose the soft deadline on the already-running health poll
Comment-only: the 10s figure reads as hard, but the deadline is checked
before each probe and a straddling probe still runs its own urlopen timeout,
so a couple of seconds of overshoot is possible on this notice path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-18 15:46:04 +03:00
Andrew
59f15995fc review r1: pinned capture before card growth, page-shown re-pin, port-file re-read
Panel findings applied. (a) updateTaskGroupCard captured the pinned state
after in-place mutations of an already-mounted card (summary rewrite, review
unhide, timeline render) — growth that alone can push a pinned reader past
the slack; the capture moves to the top of the function. (b) A .page display
round-trip resets scrollTop to 0 (documented in chat.js for the same
mechanism), which would read as scrolled-up and silently disarm autoscroll
after every page switch — logs now re-pins on ouro:page-shown for the
dashboard/logs combination, mirroring evolution.js, which also covers the
first dashboard show. (c) The already-running notice could open a stale or
absent port-file value when Open races the first launcher's bootstrap; the
branch now polls server health re-reading the file between probes (10s
bound), falling back to the last-read port. (d) Unused import dropped from
the new test (the recorded ruff gate now covers every touched file) and a
stale comment reworded.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-18 15:46:04 +03:00
Andrew
0c4acfd9b7 fix: scope POSIX port sweeps to the listener, sparing connected clients
Both POSIX port-sweep helpers (platform_layer.kill_process_on_port and the
launcher's _kill_stale_on_port) selected pids with a bare 'lsof -ti tcp:PORT',
which also matches ESTABLISHED client sockets. On a browser-mode install the
owner's browser holds exactly such a socket to the UI port, so a panic stop or
a startup sweep SIGKILLed the owner's whole browser — observed on a live Linux
install. The Windows branch already filtered LISTENING; POSIX now matches it
with -sTCP:LISTEN (plus -nP so name resolution cannot eat the 5s timeout),
restoring the invariant documented on _open_browser_detached: the browser is
the owner's application, outside custody.

New tests pin the listener-scoped argv and self-sparing for both helpers; the
packaging pin follows the new argv.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-18 15:46:04 +03:00
Ouroboros
d6bfb1f598 feat(chat): per-message owner surface fact and process presentation posture
Ouroboros advised a desktop-app owner to reload 'the browser tab' because the
runtime had no fact about the client UI: the launcher never exported the
retired OUROBOROS_DESKTOP_MODE flag, and messages carried no sending-surface
provenance at all.

Two additive facts, no device taxonomy (the model classifies raw observables):
- launcher.py exports OUROBOROS_PRESENTATION (desktop_window|browser_fallback;
  absent=web) — the process posture, rendered as runtime_env.presentation.
- The SPA measures raw observables AT SEND TIME (pywebview bridge, ua,
  viewport, matchMedia booleans, captured_at) and attaches client_surface to
  each chat frame; the gateway normalizes it through the closed-key bounded
  ouroboros/client_surface.py SSOT, stamps received_at, carries it in
  task_metadata, persists it as an optional chat.jsonl column, and renders it
  as the owner_client context fact. Non-web ingress gets a host-stamped
  {channel: <source>} fallback; promotion/steering/mailbox carry it, and the
  loop notes a mid-task surface change only when the surface IDENTITY differs
  (viewport resize is not a device change), with a neutral note for the first
  observed fact. SYSTEM.md documents the semantics and the pywebview product
  facts (no Cmd+R, SHA auto-reload).

Adversarial waves 1-2 are folded in: Infinity viewport crash at ws ingress,
strict booleans, no-identity facts never mint change notes, provenance-honest
prompt wording, behavioral producer tests, send-site and received_at pins.
client_surface helpers live in their own module (message_bus/loop/chat.js stay
inside their ratchet sizes).
2026-08-18 05:54:03 +03:00
Ouroboros
1a3e102ddb fix(synthesis): close the honesty and SSOT findings the final gate raised
Five items from the agentic gate (cursor/fable-5) plus one of my own, each
verified against the code before it was accepted:

* README generalized a Terminal-Bench fact to three benchmarks: "in those
  model-matched results it leads Codex, Claude Code, Cursor, and Hermes" is
  true of the TB2.1 rows, while OSWorld's matched pair is against Pointer and
  CL-Bench's comparison is the previous public top. The lead-in one screen
  above already said this correctly; the prose now matches it.
* The same table showed "Hermes: 77.53%" beside k=5 numbers with no stamp.
  The repo's own methodology is explicit — that baseline is k=1, "must NOT be
  compared directly to the k=5 rows; disclose the k asymmetry wherever the
  number appears" — so the cell now discloses it.
* ARCHITECTURE and the banner's own comment claimed per-facet provenance as
  live behaviour ("a refused quota read leaves the catalogue and account facets
  authoritative"). The CLIENT does that; no producer stamps `reads`, and
  claudexor_accounts.py says so in as many words, so today every facet reads
  indeterminate together. Both places now say which half is ready and which
  half is wired.
* launcher.py still explained a restart partly by "the legacy bridge wrote
  settings.json behind its back" — the bridge this sprint deleted.
* launcher_onboarding.py defaulted a missing payload's `ok` to True, i.e. an
  absent answer meant "saved". Unreachable today, but that is the wrong
  default on the one flag that reports whether the owner's settings landed.

And the SSOT gap I owed: family display names had TWO authorities. The Agents
tab preferred the engine's `display_name`; the wizard kept a private map of
three and fell through to the raw harness id, so a renamed or fourth family
would have reached the owner spelled `claude`. `familyLabel` now lives in the
status store — the one module both consumers already import, so nothing drags
the 853-line settings module into the wizard bundle — and the new test pins
both halves: a renamed family is spoken in the engine's words, an unknown one
is never printed raw.

pytest 8402 passed, node 272 passed.

Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
2026-08-09 08:08:56 +03:00
Ouroboros
72bb162fb8 feat(onboarding): serve one wizard from the live gateway on every host
Desktop first-run rendered the wizard BEFORE server.py existed, in a detached
pywebview document with its own js_api bridge. That window could not reach
/api/* at all, so connecting an agent subscription during setup was impossible
and degraded to a dead "configure it later in Settings" pointer, while the web
overlay ran the same steps against a live server through a different save path.

The runtime already supports the state this needs: the server starts the
gateway first and starts the supervisor only when provider configuration is
structurally sufficient (ARCHITECTURE section 2). So no second server, mode or
onboarding state machine is introduced; the launcher simply stops rendering
onboarding itself.

Startup now runs the single-instance lock, the Git check and managed-repo
bootstrap first, because those are preconditions of the server. It then clears
stale server state and ports, starts the lifecycle thread, waits on /api/health
at the authoritative port from data/state/server_port, and only then opens the
setup window on that live server. The crash fuse, exit-code-42 handling, panic
teardown and the Linux browser-fallback probe are untouched.

The wizard becomes a real page. GET /onboarding renders onboarding_template.html
with the setup bootstrap injected and LINKS onboarding.css and
web/modules/onboarding_wizard.js from /static, so wizard steps can import
ordinary web/modules siblings, which an inlined srcdoc string never could. The
blocking overlay frames that same URL, and /api/onboarding stays the readiness
probe: 204 once the structural gate passes. One renderer, one contract, one
validator. The inline bootstrap escapes "<" so a stored provider value cannot
close the script element.

Completion is one HTTP conversation. The page posts POST
/api/onboarding/complete first on every host; 404/405 means that atomic
endpoint is not deployed yet, and the page falls back to today's behaviour
rather than breaking first-run: the desktop setup window through the launcher's
own save, everything else through generic settings plus /api/owner/runtime-mode.
The desktop fallback is retained deliberately, because it is the only path that
may author the fresh-install OUROBOROS_SAFETY_MODE=light, which neither the
shared validator nor the generic settings endpoint can do. Claude-runtime
status/repair, compatible-model discovery and local-runtime controls now use the
ordinary endpoints on desktop too, so those bridge methods are gone; the same
repair already runs at every bootstrap and from Settings.

Neither pre-onboarding normalizer may CREATE settings.json any more. The
launcher already carried that guard; the server's boot normalization now
mirrors it, because it runs BEFORE onboarding on every host and would otherwise
author the first bytes of the file every fresh-install proof is gated on.

When completion reports that a boot-pinned value changed (the runtime-mode
baseline) or that the legacy bridge wrote settings behind the running server's
back, the launcher recycles the managed server through its existing lifecycle
loop instead of leaving a restart nag. The recycle is flagged so it skips crash
accounting, exactly like the agent's own code-42 restart.

has_startup_ready_provider is untouched: a subscription still cannot satisfy the
startup gate (D-1). No version carrier moves. The launcher's share of the flow
moved to ouroboros/launcher_onboarding.py so launcher.py stays the
process/window orchestrator and returns under the module-size gate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
2026-08-09 02:30:06 +03:00
Ouroboros
111bd45603 release v6.91.0: the Linux binary boots into the browser when no desktop webview backend or display exists
Instead of dying with WebViewException on every GTK/QT-less Linux box — or
crashing at the first window on a box WITH gi/GTK bindings but WITHOUT a
display (ssh session, headless server carrying the system gi) — the launcher
now probes both facts. The session environment (DISPLAY/WAYLAND_DISPLAY) is
checked BEFORE pywebview's guilib.initialize(), because even selecting a Qt
backend constructs a QGuiApplication that can abort a display-less process;
after initialize(), a GTK backend (recognized by the returned module's
identity, not the version-drifting renderer string) is refined through its
own Gdk.Display.get_default(), which answers None rather than raising on a
dead display. A Qt backend is judged on the environment alone — probing Qt
would cause the very crash the probe exists to detect (disclosed residual,
pinned by its own test and stated in the README row). macOS/Windows never
run any of this.

In browser mode the launcher installs the SIGINT/SIGTERM shutdown handlers
BEFORE the lifecycle thread spawns server.py (through the new
platform_layer.install_shutdown_signal_handlers), prints the URL, opens the
default browser without blocking, and keeps the process alive while the
server lifecycle runs. First-run onboarding is served by the existing
/api/onboarding web overlay. A shutdown signal during the startup window
aborts the readiness wait into the same clean teardown, and once shutdown
has been requested the launcher no longer announces the URL or launches the
owner's browser mid-teardown. Every headless teardown sweeps orphans against
the AUTHORITATIVE bound port (the server may rebind on conflict), including
the previously sweep-less startup-failure branch. The sys.exit teardown
paths rely solely on the atexit pid-lock release; the explicit release
remains only on the os._exit paths where atexit never runs. The opened
browser is the owner's own application, deliberately outside process custody
and launcher teardown. Headless boxes get a clear message instead of a
crash — now including boxes where the GUI libraries are present but no
display is.

README now leads its integrations story with subscription-powered delegation
through the bundled Claudexor engine (github.com/razzant/claudexor).
ARCHITECTURE documents the Linux browser fallback across Startup Flow,
First-run Wizard, Two-process Model, and Shutdown, including the
display-aware probe rationale, the Qt residual, and the disclosed
pre-existing spawn-admission residual tracked as an issue.

Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-08 17:43:11 +03:00
Ouroboros
2d61108bf0 synthesis step 6: transplant p7b-packaging functional range ca76d76..5f2efa3
Packaging + lifecycle: the finalization-grace EPISODE mechanics (E1) move into
task_reaper with a typed control msg_id and HOST_NARRATION-declared supervisor
toasts; salvage preserves the FULL output on the canonical drive before the child
drive dies (B5); OUROBOROS_SERVER_HOST stops being stamped from settings over the
environment (config: key not exported to env — the H5-adjacent authority fix; H5's
env.setdefault in launcher.start_agent auto-merged and holds). p7b's
test_packaged_runtime_and_lifecycle superset adopted; the one p34-only latch test
pins the pre-episode semantics p7b replaced and is registered as superseded.
H2 files stay on the full inverted stack (p7b carried only 8dd7065 + the
versioned-basename fix the family classifier subsumes). Guard PASS; focused
suites green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 16:33:46 +03:00
Ouroboros
d54e93ce35 synthesis step 1: transplant p34-converged functional range 7caf7c1..5cde01f
Range transplant via merge-tree with merge-base=7caf7c1 (contaminated-history
branch contributes its post-terminal delta only; D27). 65 files. All 8 conflict
blocks were version carriers, resolved to the base side (6.87.6) per the
single-final-bump policy (C7); the api_types.js conflict additionally dropped
the terminal typedef block the incoming side inherited from 7caf7c1, and the
README conflict dropped intermediate 6.88.x changelog rows carrying private
SHAs. PTY scan of the result: clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 15:34:37 +03:00
Ouroboros
09488e8b49 release v6.82.0: truthful working cards, mobile gestures, and cancel run
Ship honest sticky activity/cost projections, collapsed provider setup, updated model defaults, fresh-desktop safety authorship, the 500-subagent ceiling, exactly two mobile gestures, and synchronous subtree cancellation with first-class Cancelled rendering.
2026-07-30 01:09:27 +03:00
Anton Razzhigaev
b676f5c505 feat(v6.70.0): owner-facing honesty — full reviewer rationale, self-locating tool errors, and a decision-turn outcome contract
Review projections (task_results + Chat/Logs panels) publish the reviewer's
COMPLETE redacted rationale instead of a 500/800-char cut, plus a forensic
response_ref with flat content-hash anchors (never host paths). The shared
truncation primitive refuses cuts cheaper than their own omission marker;
reflection/task_contract markers unify on the canonical OMISSION NOTE
(tiny <100-char identifier fields keep a hard slice by design); per-arg
trace caps rise to 200 chars. Task-acceptance actors use their documented
second physical send as an extraction/format repair with forensic fallbacks
(rail-blocked, transport-failed, or empty resend keeps the malformed first
answer; attempt 1 is persisted as its own call record). The DEGRADED owner
line names per-slot causes through the shared primitive. Honest UI: the
Skills submit button creates a REAL managed task via /api/tasks; repair
buttons say 'will decide' instead of claiming a queued task; ephemeral
decision turns carry an explicit outcome contract. Tool errors self-locate
(resolved path + profile-visible roots; affordance maps name invisible
roots). Read-only review scouts gain read/list/search on skill payloads
(policy + discoverable schemas). Root loggers mask secret-shaped values via
the observability SSOT filter on server and launcher (fixed telegram
/bot<id>:<secret>/ pattern, mirrored in the utils scrubber), httpx quieted.
A report-only stray-server invariant scans this user's processes at startup
and live behind a 15-min TTL cache (case-insensitive, packaged installs
included). A bound task's Main-chat summary names its project thread.

Gate: triad+scope external review PASSED 3x (runs at $25.85/$13.63/$10.18 —
reviewer-prompt caching from v6.69.0 visibly compounding), final codex review
applied. Full suite green (non-serial + serial).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 10:18:10 +00:00
ndrew1337
e134328394
feat(chat): outbound file delivery + WKWebView-safe open/download + rotation-safe history (v6.62.0) (#67)
Ports the downstream chat file-delivery line (v6.57.0-v6.58.7, 12 commits) onto the
current upstream tip (v6.61.4) and re-versions it as 6.62.0 (a new capability, MINOR
bump). None of these symbols existed upstream -- additive, not a re-implementation.

What it adds:
- send_file(file_path, caption?) core tool (50 MB cap, MIME-detected): delivers an
  arbitrary finished file (report, .md/.csv/.html, PDF, archive, code) to the owner's
  chat, not just images/videos. Queues a send_document event; LocalChatBridge.send_document
  broadcasts a frozen `document` WS frame (DocumentOutbound contract) + publishes the
  chat.document event-bus topic so reviewed transport skills (e.g. telegram-bridge) can
  mirror it. supervisor _handle_send_document handler.
- WKWebView-safe open/download: clicking a delivered file bubble opens it in the OS
  default app via a pywebview bridge (per-open private mkdtemp, 0700), with a separate
  download button; degrades to the long-shipped download_file_to_downloads bridge on a
  stale packaged launcher; only falls back to window.open on true web (no in-app WKWebView
  navigation -- fixes a fullscreen lockup).
- Rotation-safe history: /api/chat/history backfills from rotated archive/chat_<ts>.jsonl
  segments (newest-first, bounded, thread-aware quota) so older messages and delivered-file
  bubbles no longer vanish when chat.jsonl crosses the ~800 KB rotation threshold --
  rotation changes granularity, not coverage.

Merge notes:
- Feature files (gateway/history.py, gateway/files.py, event_bus.py, message_bus.py,
  tool_capabilities.py, safety.py, launcher.py, ui_helpers.js) are new to upstream.
- Seam files (contracts.py, tools/core.py, events.py, chat.js, style.css, api_types.js,
  review.py, ARCHITECTURE.md, README.md, test_contracts.py) merged against upstream's
  current additions: DocumentOutbound sits beside upstream's contract additions; the
  history-replay document branch is spliced ABOVE the taskId/finishLiveCard block inside
  upstream's reworked Pass-2 render loop; the ARCHITECTURE envelope row keeps BOTH
  upstream's safety_mode/answer_protocol and our DocumentOutbound.
- The rotation-aware archive backfill is extracted to a module-level
  _read_chat_history_entries helper so api_chat_history/make_chat_history_endpoint stay
  under the 300-line review cap (matching upstream's lean-function convention).
- Version carriers set to 6.62.0 (VERSION, pyproject, package.json, api_types
  GATEWAY_CONTRACT_VERSION, README badge, ARCHITECTURE header). README changelog: one
  6.62.0 row added, oldest minor (6.57.0) rolled off to respect the P9 cap.
  review.py MAX_TOTAL_FUNCTIONS stays 3775 (measured merged count 3770).

Co-authored-by: Andrew <andgri200@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 21:49:34 +03:00
Ouroboros
806a15817a feat(core): v6.36.0 — boundary resilience, unified terminalization, reviewer-slot SSOT, acceptance feedback, macOS signing
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>
2026-06-17 11:14:06 +03:00
Ouroboros
fa424eb46f release: Ouroboros v6.33.0 — Capability-Evidence context modes, multi-project + LLM-first named projects, WS11 UI/UX
Context window is no longer a static per-model table: every window claim is sourced,
route-fingerprinted Capability Evidence (provider /models metadata, local n_ctx, or an
owner acknowledgement) with a status (confirmed/asserted/unprobeable/failed), persisted
atomically. Max context mode is fail-closed — it requires >=1M confirmed/asserted evidence
for the active route. Changing the model while Max is on stays friction-free: the change
succeeds and context auto-downgrades to Low with a plain notice when the new route can't be
confirmed >=1M, but a genuine no-connection during the probe is an error (the model is not
saved), and a transient provider outage never erases a prior confirmed record.

Multi-project: the agent can now CREATE a NAMED project from chat in one LLM-first call
(promote_chat_to_task project_name/title; non-ASCII names get a deterministic hash id while
the display name is preserved). A main-chat task converts to a project in one click,
auto-named from its title/objective (no prompt, no extra LLM call); project-chat follow-up
tasks bind to their project so the main chat shows no stray "turn into project" button and
instead a calm pointer that opens the project panel; a converted card becomes a calm indigo
project identity (no red "error" look); per-project unread dots sort active projects to the
top (server-stored last-viewed); the project status/sleep-wake lifecycle was removed.

UI: oval (pill) composer with centered controls; per-thread chat scroll restored on tab/
panel switch instead of jumping to the top.

Also: real deadline_at finalization + advisory pacing, polyglot tree-sitter code intelligence
for non-Python symbols (query_code op=digest; Python stays on stdlib ast), reflection
faculty-atrophy doctrine, BIBLE P1 (Capability Evidence) + P8 (faculty atrophy) clauses, and
assorted WS9 tool fixes.

New surface: POST /api/owner/capability-ack, ouroboros/capability_evidence.py,
data/state/capability_evidence.json.

Reviewed by triad (gpt-5.5/gemini-3.5-flash/opus-4.8) + scope (gpt-5.5) + claudexor (gpt-5.5)
+ an independent adversarial multi-agent audit, against the original plans and the owner's raw
message transcript; all confirmed defects fixed, remaining findings evidence-rejected or tracked.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 09:21:57 +03:00
Ouroboros
f6fe031646 fix(headless-provider-capabilities): restore workspace review and provider invariants
Phase 1 of the v6.18.0 unified plan.

Restore workspace parent access to task_acceptance_review without exposing commit/runtime-control tools, strengthen plan_task prompt discipline, normalize system-message placement at the LLM boundary, harden OpenRouter reasoning-signature retry behavior, tighten VLM routing/timeouts/payload caps, and move Claude Code governance prompts through private SDK prompt-file handoff.

Also integrate the useful OpenAI-compatible onboarding/model-loader slice from PR #36; the other PR #36 commits were stale-base changes already present in v6.17.0 and were not re-merged.

Review evidence: two adversarial review cycles completed; real triad+scope dry-run completed with scope_status=responded, scope_blocked=false, scope_review_skipped=false. Remaining triad version_bump finding is intentionally deferred per the accepted four-phase plan, which performs the unified 6.18.0 version/release sync in Phase 4.
2026-06-05 06:14:12 +03:00
Ouroboros
294a287713 fix(launcher): fix launcher-agent startup race condition
Synchronously executes stale process/port cleanup in preflight prior to launching the server and webview, preventing race conditions that load a dead/killed server port and yield a black screen.
2026-06-02 00:18:53 +03:00
Ouroboros
74015244d0 release: prepare v5.31.0-rc.1 2026-05-22 15:50:13 +03:00
Ouroboros
ecaa61969b release: v5.28.0-rc.1 stability and parity 2026-05-20 20:57:43 +03:00
Ouroboros
655f21515b v5.25.1-rc.1: compact non-test comments and docstrings 2026-05-17 23:57:26 +03:00
Ouroboros
1724dbaceb v5.19.0-rc.1: align skill review gates and collapse review messages 2026-05-12 23:46:21 +03:00
Ouroboros
dcd7a5ed9e v5.15.0-rc.8: quality dx closed-loop skills wave on top of rc.7
Layered on top of rc.5..rc.7 catch-up reduction line. Preserves the
rc.7 prompt-injection fix in renderSkillRepairPrompt (web/modules/utils.js)
and the rc.6 docs/accounting cleanup. Adds the Quality, DX & Closed-loop
Skills wave from the user-approved finish plan:

- runtime_mode=light reframed as a minimal compatibility/self-modification
  guard. Path-aware shell filter (_light_shell_repo_mutation): blocks
  simple writer commands (cp, mv, rm, sed, sort -o, uniq, ...) only when
  their target resolves inside the Ouroboros checkout, blocks shell-
  wrapped writes via 'sh -c' / 'bash -c', blocks mutative direct git
  through run_shell, and otherwise lets ordinary python/node/bash
  diagnostics run. Removed the heavy Python AST scanner + script-content
  scan that was over-blocking legitimate work.
- Chat scroll fixes: ResizeObserver re-attach, near-bottom threshold,
  Playwright smoke now asserts scrollTop ~ scrollHeight after send.
- Recent-chat dedup: read_jsonl_tail_after_offset honours
  dialogue_meta.last_consolidated_offset; provenance-aware via a chat
  log generation signature (first_line_sha256 + size) so log rotation
  cannot silently drop entries.
- Stable WORLD.md injected into context.build_memory_sections.
- plan_task and the commit triad accept duplicate model IDs as valid
  reviewer slots (single-provider stochastic sampling); _get_review_models
  no longer pads 2-slot configs to 3.
- Settings: OUROBOROS_AUTO_GRANT_REVIEWED_SKILLS owner-confirmed via the
  desktop launcher bridge (request_auto_grant_reviewed_skills_change),
  hot-read from settings.json so toggle changes take effect without
  restart, /api/settings POST drops the key. Consistent truthy parsing
  on JS + launcher sides.
- skill_review.py runs an optional fail-open Claude Code advisory over
  the skill payload only (include_repo_diff=False), and injects its
  output as inert evidence BEFORE the authoritative output contract.
- skill_exec emits skill_exec_finished / skill_exec_failed events;
  worker enqueues them on ctx.event_queue, supervisor.events dispatches
  them to logs/events.jsonl + the live log + the in-process event bus
  for skill.lifecycle subscriptions. host_service_api allows manifest-
  declared skill.lifecycle subscriptions without an extra grant.
- run_shell auto-rewrites grep "A\|B" argv-mode to grep -E "A|B" with
  SHELL_REGEX_AUTO_CORRECTED prefix; explicit -E/-G/-P/-F still pass
  through. SAFE_SHELL_COMMANDS no longer includes sort/uniq.
- Extension loader hardening: load_extension(drive_root=...) is
  mandatory (no silent ~/Ouroboros/data fallback), TestClient lifespan
  + settings hot-reload pin to app.state.drive_root, _sweep_stale_-
  extension_imports preserves the live import root via a keep-list,
  fixture cleanup uses unload_extension. Adds clean_extension_runtime_-
  state superset helper and tests for cleanup, drive_root requirement,
  and live-root preservation.
- Test pollution: scripts/cleanup_test_pollution.py (dry-run-first
  utility), tests/_shared._make_safe_mock_ctx for advisory-workflow
  ctxs, _make_safe_mock_ctx adoption in test_advisory_workflow*.
- PluginAPI v1.2: PLUGIN_API_VERSION bumped, skill_job_dir added to
  the frozen Protocol + the contract test.
- docs/ARCHITECTURE.md, docs/CHECKLISTS.md, docs/CREATING_SKILLS.md,
  prompts/SYSTEM.md updated for new behavior (light-mode wording,
  cleanup script, skill.lifecycle topic, advisory pre-review path,
  duplicate reviewer slots, auto-grant settings + permissions wording).

VERSION 5.15.0-rc.8 / pyproject.toml 5.15.0rc8 / README badge + Version
History row + ARCHITECTURE.md header all in sync.
2026-05-11 03:32:41 +03:00
Ouroboros
26a783ca62 Fix launcher host service port cleanup
Ensure launcher cleanup also clears the Host Service listener port so orphaned workers cannot block the next desktop startup.
2026-05-09 17:03:01 +03:00
Ouroboros
59fab07db0 v6.0.0: move A2A and Telegram into Hub skills 2026-05-08 23:57:04 +03:00
Ouroboros
da73d237a3 v5.6.1: Repair marketplace and widget flows 2026-05-02 00:09:25 +03:00
Ouroboros
39b732df78 v5.5.0: Add skills hub and lifecycle installer UX 2026-05-01 20:55:17 +03:00