v1.15.0
Added
- Session Handoff (continue-anywhere) —
observer handoff <session-id> [--to <tool>]distills any captured session from the source tool's OWN
transcript files into a scrubbedHANDOFF-<id>.mdthe target tool reads in
the project root, priced per carry mode (metadata / distilled /
distilled_tail / full) at the target model. Fork from any stable point of
the message history (snap table refuses cuts inside unresolved tool chains).
NOT cache migration — provider caches are server-side and prefix-exact; the
estimate's stay option (next-message predict band + live cache
value-at-risk) is the honest surface of that fact. Surfaces: CLI
(observer handoff,handoff list), dashboard session-detail
"Continue in…" modal with fork picker
(GET /api/session/<id>/handoff/estimate+POST /api/session/<id>/handoff),
MCPcontinue_session(tool count 19 → 20). Transcript readers:
claude-code, codex, cursor, cline, cline-cli, hermes, opencode. Node-local
handoffstable (migration 055) stores counts/enums/hashes only — never
the doc. Docs:docs/session-handoff.md. - Session Handoff — dashboard "Launch
<tool>here" (embedded web
terminal). The Continue-in… modal can now START the target tool in the
browser instead of only writing a handover file: for a launchable target
(claude-code / codex / gemini-cli / pi) the daemon spawns
observer <tool> --continue-from <id>in a PTY inside its own OS and
streams the TUI into an xterm.js panel over a/ws/launch/<handle>
websocket — working uniformly local, remote, or WSL-daemon/Windows-browser
(no cross-OS shell). New pure-logicinternal/termsession(PTY session
registry behind an injected spawner; process-group reaping on unix,
concurrent cap + idle reaper) and theHandoffCapability.Launchregistry
field. Server-derived argv only; CSWSH-defended (256-bitcrypto/rand
handle minted only by the Origin-checkedPOST /api/session/<id>/launch,
pluscoder/websocketcross-origin rejection). On by default, kill-switch
[handoff].allow_dashboard_launch.GET /api/launch/sessions+
DELETE /api/launch/<handle>for the live-session list. Unix-only PTY
backend (native-Windows daemon reports unsupported → run under WSL). Docs:
docs/session-handoff.md(Launch here),docs/security.mdledger. - Session Handoff — armed hook delivery (
--deliver hook, claude-code).
observer handoff <id> --to claude-code --deliver hookarms the handover
for the NEXT claude-code session in the project: it injects as SessionStart
additionalContext(same seam as the advisor digest), one-shot, expiring
after[handoff] hook_ttl_minutes(default 240). The payload is hard-
budgeted to[handoff] hook_max_bytes(default 8192; Phase 0 D-P0.2's 8KB
intact cap) — the compact doc when it fits, else the document head plus a
pointer to read the on-diskHANDOFF-*.md. Doc content stays on disk; the
handoffsrow (migration 056:hook_expires_at/hook_delivered_at/
project_root) records only the arming window and file path. The claim is
a single guardedUPDATE … RETURNING(race-safe). Delivery dispatches on
the target'sintegration.HandoffCapabilityinject set — only claude-code
declaresinject_hook; other tools error honestly. - Session Handoff — launcher
--continue-from(prompt delivery).
observer claude --continue-from <session-id>and
observer codex --continue-from <session-id>run the handoff for the
launcher's OWN tool (deliveryinject_prompt) and seed the rendered
handover as the tool's first user prompt before exec'ing it — no
copy/paste. Mirrorsobserver handoffflags (--carry,--from-message,
--from-time; default fork = last message). claude gets the doc prepended
as its leading positional prompt, codex appended as the trailing positional
(TUI +exec); forwarding your own positional prompt errors honestly (two
prompts — forward value-flags as--flag=value). Handovers over 100KB
degrade to a marker-carrying pointer prompt (the full doc is on disk). The
observer handoff … --to claude-code|codexoutput now prints a
--continue-fromtip. Delivery still dispatches on the target's
integration.HandoffCapability— a prompt handoff to a tool without the
lane errors honestly. - Session Handoff —
--continue-fromextended toobserver geminiand
observer pi. Both now accept--continue-from(plus--carry,
--from-message,--from-time), seeding the handover as the tool's first
prompt: gemini via its-i/--prompt-interactiveflag ("Execute the
provided prompt and continue in interactive mode"), pi as a trailing
positional message (pi[messages...]start an interactive session). The
injection strategy is now a declaredpromptInjectiondescriptor (leading
positional / trailing positional / flag value) applied by a shared
injectPrompthelper — noswitch tool; claude and codex are refactored
onto the same helper.hermesstays deferred: its only prompt flag
(-z/--oneshot,chat -q) is headless one-shot (answer once and exit),
not an interactive seed, so wiring it would change the run mode.
opencode(TUI positional is a project path),copilot-cli(headless
-ponly),openclaw(proxy runtime-block) andcline-cli(not
verifiable on the grounding node) also remain deferred. - Session Handoff — best-effort target-session linker. Every rendered
handover carries a<!-- superbased-handoff <shortid> -->marker that
rides into the target session on every delivery lane (injected prompt,
SessionStart context, or the model readingHANDOFF-<shortid>.md).
observer handoff listnow runs a time-boxed best-effort sweep first:
for each delivered handoff of the last 7 days still missing a target,
it re-reads candidate sessions of the target tool in the same project
(started after the handoff) via the shared transcript-reader dispatch and
stampshandoffs.target_session_idon the first whose transcript carries
the marker. The link is written once (guarded UPDATE); the list gains a
TARGETcolumn. Pure marker scan lives ininternal/handoff
(ScanMarkers/ContainsMarker); store seam addsLinkTargetSession,
ListUnlinkedHandoffs,CandidateTargetSessions. Short-id is recovered
from the delivered doc's file name (delivery_ref). Everything is
best-effort — an unreadable candidate is skipped and one handoff's failure
never aborts the sweep. - Session Handoff —
handoff_rehydrationcache accounting. A handoff
target's first turn is a large cold cache write BY DESIGN (the handover
doc arrives as the first prompt / SessionStart context / an early
HANDOFF-<id>.mdread). It is now annotated as a new
cause=handoff_rehydration(samereanchorkind, so kind-based
denominators are unchanged) instead of a plainreanchor, so it no
longer trips the advisor'ssession_balloon/cache_write_waste
detectors orobserver cache-health's cause-concentration WARN. Fired
live in cachetrack when thesuperbased-handoffmarker is present on the
first observed turn (proxyparseRequestbody scan + Tier-2 store
block-body scan), and applied retroactively by the advisor via
handoffs.target_session_id(the belt for non-proxied targets). Docs:
docs/cache-tracking.md→ "Session-handoff accounting". - Session Handoff — implicit-cache lane consults the handoff marker. The
§15.3 implicit / OpenAI-Codex attribution path now mirrors the Anthropic
lane: on the bootstrap turn with thesuperbased-handoffmarker set,
ruleImplicitHandoffRehydrationfirescause=handoff_rehydrationwith the
sameimplicit_writekind the plain reanchor uses, so every
denominator/exclusion is unmoved (the kind routes tobucketSkipped+
isRateSkipped, and the bootstrap turn is already excluded from
ImplicitCacheConsistency) — only the cause differs. The marker flag,
already scanned provider-agnostically by the proxy'sparseRequest, is now
threaded through the OpenAI branch ofbuildCacheObserveInput(it was
previously dropped) and consumed byobserveImplicit. Live coverage is
proxy-only; a non-proxied codex Tier-2 target carries no reconstructed
block bodies to scan, so that lane stays covered by the advisor's
retroactive handoff-target belt. - Session Handoff — retention sweep +
observer doctorprobe (P4). The
node-localhandoffstable is now pruned by the shared retention runner
(observer prune, andprune_on_startuponobserver start/watch)
viastore.PruneHandoffRows, gated by the new[handoff] retention_days
(default 180;0= keep forever). Theprunesummary line reports
handoff_rows=<n>.observer doctorgains a handoff readers check:
per adapter it reports the declared transcript tier + delivery lanes and,
where a session exists from the last 30 days and the adapter implements
the reader, runs a read-only, time-boxed (2s) readability probe against
the latest session — honestread OK/metadata handover only/
reader-declared-but-unreadable WARN, dispatched on capability shape (no
tool-name branching).
Changed
- The node/developer dashboard is now purely coding-agent (Plane B). The
general-observability surfaces — Trajectories, Evals, and the
Admission policy editor / per-end-user budgets — were removed from the
local dashboard nav. These observe an LLM application you host at the
admin level (end-user traces, evals, and input guardrails), not your own
coding assistant, so their home is the admin dashboard (web2, the
Trajectories nav group). A node still captures and pushes obs data when
[observability]is enabled; it just no longer renders the obs UI locally.
The obs backend,/api/obs/*endpoints, andobserver obs …/observer evalCLIs are unchanged. See the new [docs/deployment-models.md]. - New two-plane documentation.
docs/deployment-models.mdis the
canonical explainer of the two deployment models — Plane A (general
observability of a hosted LLM app) vs Plane B (coding-agent org/teams) — and
is now Start-here #1.CLAUDE.md,docs/README.md,docs/observability.md,
and the rootREADME.mdwere updated to keep the two planes legible, backed
by a full plane-separation audit
(docs/audits/plane-separation-audit-2026-07-06.md) whose verdict is that
every enforced code boundary between the planes holds. - Community & support card added to the node dashboard Overview (star the
repo, report a problem, refer/share, send feedback).
Security
- SQLite DSN path escaping (low; closes ledger item L8). Every SQLite
file:DSN now routes its filesystem path through the new one-owner helper
internal/platform/sqlitedsn.Escape, which percent-encodes the characters
the SQLite URI parser treats specially (%,?,#). Previously a database
path containing?was truncated into the query string (and%XXsequences
were mis-decoded), which could drop the read-only pragmas on adapter reads.
Applied to all 13 DSN sites: the 8 external-database adapter readers
(kilocode, opencode, openclaw, cline-cli, cursor, hermes, antigravity ×2),
both backfill readers, theobserver importread-only ATTACH, and both
first-party database opens. Ordinary paths produce byte-identical DSNs.
Downloads
Pre-built binaries for each supported platform are attached below. Linux variants bundle antigravity-bridge.exe next to the observer binary for WSL2 users of the Antigravity adapter.
| Platform | Asset |
|---|---|
| Linux x86_64 | observer-v1.15.0-linux-x64.tar.gz |
| Linux arm64 | observer-v1.15.0-linux-arm64.tar.gz |
| macOS x86_64 (Intel) | observer-v1.15.0-darwin-x64.tar.gz |
| macOS arm64 (Apple Silicon) | observer-v1.15.0-darwin-arm64.tar.gz |
| Windows x86_64 | observer-v1.15.0-win32-x64.zip |
Verify with sha256sum -c SHA256SUMS (or shasum -a 256 -c SHA256SUMS on macOS) from the directory containing the downloads.
Also available via npm: npm install -g @superbased/observer@1.15.0
Org server (Docker)
The self-hosted org server ships as a Docker image and as per-platform observer-org-v1.15.0-* archives (attached below).
docker pull ghcr.io/marmutapp/observer-org:v1.15.0The image is keyless-signed with cosign. Verify it:
cosign verify ghcr.io/marmutapp/observer-org:v1.15.0 \
--certificate-identity-regexp 'https://github.com/marmutapp/superbased-observer-private/.*' \
--certificate-oidc-issuer https://token.actions.githubusercontent.comSupply chain
CycloneDX SBOMs are attached: observer.cdx.json and observer-org.cdx.json.
SLSA Level 3 build provenance for the binaries is attached below as a *.intoto.jsonl attestation. The build runs on the private origin repo, so pass that as the source when verifying an extracted binary with slsa-verifier v2.7.0 or newer (older versions fail with unexpected tlog entry type: expected intoto:0.0.2, got dsse:0.0.1):
slsa-verifier verify-artifact ./observer \
--provenance-path *.intoto.jsonl \
--source-uri github.com/marmutapp/superbased-observer-private