Skip to content

v1.15.0

Choose a tag to compare

@marmutapp marmutapp released this 05 Jul 23:45

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 scrubbed HANDOFF-<id>.md the 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),
    MCP continue_session (tool count 19 → 20). Transcript readers:
    claude-code, codex, cursor, cline, cline-cli, hermes, opencode. Node-local
    handoffs table (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-logic internal/termsession (PTY session
    registry behind an injected spawner; process-group reaping on unix,
    concurrent cap + idle reaper) and the HandoffCapability.Launch registry
    field. Server-derived argv only; CSWSH-defended (256-bit crypto/rand
    handle minted only by the Origin-checked POST /api/session/<id>/launch,
    plus coder/websocket cross-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.md ledger.
  • Session Handoff — armed hook delivery (--deliver hook, claude-code).
    observer handoff <id> --to claude-code --deliver hook arms 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-disk HANDOFF-*.md. Doc content stays on disk; the
    handoffs row (migration 056: hook_expires_at / hook_delivered_at /
    project_root) records only the arming window and file path. The claim is
    a single guarded UPDATE … RETURNING (race-safe). Delivery dispatches on
    the target's integration.HandoffCapability inject set — only claude-code
    declares inject_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 (delivery inject_prompt) and seed the rendered
    handover as the tool's first user prompt before exec'ing it — no
    copy/paste. Mirrors observer handoff flags (--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|codex output now prints a
    --continue-from tip. Delivery still dispatches on the target's
    integration.HandoffCapability — a prompt handoff to a tool without the
    lane errors honestly.
  • Session Handoff — --continue-from extended to observer gemini and
    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-interactive flag ("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 declared promptInjection descriptor (leading
    positional / trailing positional / flag value) applied by a shared
    injectPrompt helper — no switch tool; claude and codex are refactored
    onto the same helper. hermes stays 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
    -p only), openclaw (proxy runtime-block) and cline-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 reading HANDOFF-<shortid>.md).
    observer handoff list now 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
    stamps handoffs.target_session_id on the first whose transcript carries
    the marker. The link is written once (guarded UPDATE); the list gains a
    TARGET column. Pure marker scan lives in internal/handoff
    (ScanMarkers / ContainsMarker); store seam adds LinkTargetSession,
    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_rehydration cache 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>.md read). It is now annotated as a new
    cause=handoff_rehydration (same reanchor kind, so kind-based
    denominators are unchanged) instead of a plain reanchor, so it no
    longer trips the advisor's session_balloon / cache_write_waste
    detectors or observer cache-health's cause-concentration WARN. Fired
    live in cachetrack when the superbased-handoff marker is present on the
    first observed turn (proxy parseRequest body 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 the superbased-handoff marker set,
    ruleImplicitHandoffRehydration fires cause=handoff_rehydration with the
    same implicit_write kind the plain reanchor uses, so every
    denominator/exclusion is unmoved (the kind routes to bucketSkipped +
    isRateSkipped, and the bootstrap turn is already excluded from
    ImplicitCacheConsistency) — only the cause differs. The marker flag,
    already scanned provider-agnostically by the proxy's parseRequest, is now
    threaded through the OpenAI branch of buildCacheObserveInput (it was
    previously dropped) and consumed by observeImplicit. 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 doctor probe (P4). The
    node-local handoffs table is now pruned by the shared retention runner
    (observer prune, and prune_on_startup on observer start / watch)
    via store.PruneHandoffRows, gated by the new [handoff] retention_days
    (default 180; 0 = keep forever). The prune summary line reports
    handoff_rows=<n>. observer doctor gains 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 — honest read 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, and observer obs … / observer eval CLIs are unchanged. See the new [docs/deployment-models.md].
  • New two-plane documentation. docs/deployment-models.md is 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 root README.md were 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 %XX sequences
    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, the observer import read-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.0

The 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.com

Supply 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