Skip to content

v1.34.0-rc.10

Pre-release
Pre-release

Choose a tag to compare

@marmutapp marmutapp released this 30 Sep 08:07
· 5 commits to main since this release

v1.34.0-rc.9 was tagged but never published: its release build failed (the web apps did not declare lucide-react, which the shared design kit imports) and its public snapshot did not compile (release.sh committed the unpatched no_obs stubs). rc.10 carries the same changes plus those two fixes.

Pre-release on the edge channel; everything since rc.8 (2026-09-21): Agent Access (off by default), the
post-Agent-Access backlog and its two live-verification rounds, the finish round (the shared design kit,
maker-over-reseller prices and Claude Sonnet 5.5, code-vs-comment lines, commit ownership, org session
gauges, the org daily spend summary), opt-in retroactive re-pricing, sandboxed-terminal containment, a
node dashboard performance pass and chart time granularity, with the review folds of each round.
Migrations: agent 127-147 (node-local or additive; they run on observer start), server 160-189 /
PostgreSQL 0026-0055. On the org server run observer-org upgrade preflight and then
observer-org migrate before starting the new image (PostgreSQL 0032 needs btree_gist; on Azure
Flexible Server see the btree_gist entry below). Node binaries need updating too. On a node that was
enrolled before this release, run observer org resync once (dry run by default; --confirm to queue)
so rows that changed or were corrected on the node before the re-send lane existed reach the org.

  • chore(config): the flat [org_client.share] obs_summary / obs_traces / obs_content / obs_eval_summary aliases are removed from the schema - the same leak as the code-graph blocks: the struct fields still existed, so every dashboard save / observer config set wrote them back and every observer process kept printing their deprecation lines. A config still carrying them keeps loading (the keys are ignored; [org_client.share.obs] is the only spelling read); observer start / observer config migrate rewrite them on disk (config-migrate step 5, config_version = 5): leftovers beside the nested keys are stripped with the nested values kept, a flat key with no nested counterpart is moved onto it, and a never-migrated file still has its values carried by step 2. What ships to an org is unchanged. A new invariant pins that no key the migrate registry retires can come back as a config field.

  • chore(config,codeintel): the legacy [compression.code_graph] / [intelligence.code_graph] config blocks are removed from the schema. They outlived their one-release deprecation window because the config structs still existed, so every dashboard save / observer config set wrote them back and the deprecation warnings never stopped. A config still carrying them keeps loading (the keys are ignored); observer start / observer config migrate now strip them (config-migrate step 4; a never-migrated file still has its values carried onto [codeintel] first). The dead Settings -> Intelligence "Code graph" toggle is gone - codeintel.enabled is the switch.

  • feat(agent-access): Agent Access - SuperBased-minted agent identity and a governed MCP gateway (optional, OFF by default: [agent_access].enabled on the org server, [mcp_relay].enabled on the node; both inert and byte-identical when off). A new companion binary observer-mcpgw (roles sts / pdp / xds / front / connect / egress) runs a Go MCP policy front in front of a stock, digest-pinned agentgateway v1.5.0 (ADR-0007, data plane A2). Every governed MCP call is authorised by one in-process policy decision point and recorded before it acts in a per-org hash-chained audit (async by default, fail-closed only when neither a leased sequence block nor the spool is writable). Tokens: RFC 8693 exchange for node relays, client_credentials (private_key_jwt incl. jwks_uri, mTLS, client secret, sbo_mcp_ API keys), an OAuth 2.1 authorization server with DCR and CIMD for direct MCP clients, and end-user OBO. Bearer by default, DPoP / mTLS opt-in per virtual server. See docs/agent-access.md.

  • feat(agent-access): MCP server registry, virtual servers, grants (incl. team and project subjects, fail-closed without trusted context), single-author policy publish with optional four-eyes, snapshot pinning with drift alerts, per-user OAuth connections (sealed per record; My Connections in the org dashboard; the connect callback lands on the dashboard origin), TOCTOU-safe parked approvals bound to the request digest and the live connection pin, MCP server / tool token budgets (budgets.scope gains mcp_server / mcp_tool), shadow-MCP discovery from node inventories, and an MCP-calls panel in the node session detail and the org session drawer. Org migrations 163-173 (PostgreSQL 0029-0039), node migrations 131-134.

  • feat(agent-access): observer-org agent-access - the full admin CLI (server, vserver, grant, policy, agent, credential, key, approval, connection, audit, reset-bootstrap, purge-subject <id>, reapply). Routed verbs run the dashboard's own handler in-process and write the same audit row as cli:<os-user>; purge-subject is the DSAR / deprovision cascade (credentials, API keys, OAuth AS grants, crypto-erased vault connections and IdP artifacts, task bindings, dashboard sessions, member generation; audit tables never touched).

  • feat(agent-access): observer-org agent-access reapply --since <T> --from <source> re-applies, forward only, the security actions a point-in-time restore silently undoes (purges, credential / API-key / OAuth-client revokes, connection and IdP-artifact erasures, agent / server retirements and quarantines, private-network locks, key rotations and retirements, the policy-generation floor, member session revokes) from the pre-restore database (read-only), the split data store, or a saved /api/org/audit page - never the MCP WORM export. Each step probes, applies only if missing and re-probes through the seam the original used; --dry-run writes nothing; a real run (--confirm) writes one agent_access.reapply audit row and then makes every restored refreshable connection due for refresh so reused tokens are re-detected. Run it before the restored server takes traffic.

  • feat(agent-access): node observer mcp {status|relay|wrap|unwrap|connect|doctor} (the older observer mcp-relay spelling stays); the node dashboard Security page gains an "MCP access" section and GET /api/mcp-access/status; the VS Code extension gains an "MCP access" status item.

  • feat(agent-access): observer-org doctor agent-access (probes AA1-AA10, each naming its failure mode), Agent Access rows in observer-org upgrade preflight (schema range, normalized listener conflicts, key-ring health, the observer-mcpgw same-tag lockstep and agentgateway pin), an agent-access.json support-bundle section, and an Agent Access alert rule set (pdp_down, pdp_degraded, audit_degraded, xds_nack, sts_down, replay_store_down, control_store_down, stale_replica, jwks_rotation_stall, mcp_budget_breach, vault_refresh_failures; mailed under [dashboard].obs_alert_email). [agent_access].companion_health_urls lists several companions for split and multi-replica deployments: pdp_down then pages only when every companion is down and pdp_degraded warns per down companion.

  • feat(agent-access): backpressure on the MCP front: PDP decision deadline pdp_decision_timeout (default 1 s; ~250 ms stays the latency target), per-call upstream deadline hop_call_timeout (120 s; first byte for SSE), a per-upstream circuit breaker (hop_breaker_failures 5, hop_breaker_cooldown 10 s) and an overload shed (front_max_in_flight 1024). All answer a retryable 503 + Retry-After; nothing retries a call.

  • feat(agent-access): Azure Key Vault signing keys rotate through the product: observer-org agent-access key rotate adds (or, with --akv-key-version, adopts) a Key Vault key version to the ring through the same ACK-gated activation, --emergency included; an identity that cannot create versions gets a 409 that prints the exact az keyvault key create + key rotate --akv-key-version step. The front's own key cache is bounded by min(invalidation_max_staleness, jwks_cache_seconds), so key retire takes effect at every running front without a restart (a key-set outage answers 503 + Retry-After, never 401).

  • feat(deploy,charts,release,supply-chain): Agent Access in every deployment shape, off by default everywhere, with one topology: observer-mcpgw and the agentgateway sidecar share the org's network namespace and sit behind the existing TLS terminator on ONE origin (the STS paths to :8850, /mcp/* and its protected-resource metadata to :8851, everything else to :8443; no new DNS name, certificate or public port). Org compose (production + dev) gains a docker-compose.agent-access.yaml override, an inert [agent_access] block, a Caddyfile with the path routes, keygen.sh agent-access-env and preflight checks (OBSERVER_AGENT_ACCESS_COMPANION=external keeps the separate-host companion supported); Helm chart 0.3.0 gains agentAccess.* (companion in the worker pod by default); observer-org deploy plan --set agent_access=on renders the whole switch (config, .env, the override, tfvars, RUNBOOK checklist and route table); every Azure and AWS OpenTofu root gains agent_access (session key minted in Key Vault / Secrets Manager, Caddy / HAProxy / Application Gateway / ALB path routes, first-boot cosign verification, and refusal of a bundle that disagrees). At zero virtual servers the companion writes an idle hop config, so the sidecar stays up and the companion reports ready.

  • feat(supply-chain): doc3 §18 gate 7 as code - .github/workflows/agent-access-images.yml (runs on every v* tag, separately from the npm / PyPI / Marketplace release) builds observer-mcpgw from an archive of the tag, emits SPDX + CycloneDX SBOMs, gates on a grype CVE scan against the ruled patch SLA, pushes by digest, cosign-signs keylessly with SBOM attestations and SLSA provenance, and mirrors the agentgateway image only after verifying upstream's signature and provenance, then counter-signs it. scripts/agent-access-supply-chain-check.sh is the one policy owner (pins / identity / upstream / verify / gate); dated, ledgered exceptions live in deploy/observer-mcpgw/cve-exceptions.json; roll-a2.sh verifies before every pull. The air-gap kit carries both images once that run has published them. Publishing needs registry credentials; without them the jobs build, scan and skip publish.

  • feat(org-assistant): the admin assistant reaches every admin route: its closed tool table grows 58 -> 212 rows (every admin route is mirrored by a row or carries a reasoned exclusion, pinned by TestEveryAdminRouteIsReachableOrExcluded), then 212 -> 247 with the Agent Access admin routes (4 read views, 31 route rows - 30 writes plus a simulate read - under the domains agent_access and mcp; minted secrets go once to the approver, never into the transcript; the approve / reject decision routes stay human-only). admin:agent_principals, admin:agent_keys, write:mcp_registry and write:mcp_policy become privileged keys: granting or widening them (dashboard or assistant) needs the super admin.

  • fix(agent-access): the PDP no longer serves its last-known-good policy forever (invalidation_max_staleness is enforced at decision time; /healthz goes not-ready past it); an agentgateway dying mid-response is answered with a retryable error and audited hop_unavailable instead of ok; the front's hop client pools connections; the front refetches the key ring within 1 s of an unknown kid (was 30 s: a 401 storm after every rotation); a node relay no longer reports a refused policy version as running.

  • fix(agent-access): honest readiness and retryable outages: a NEW policy publication that fails to compile is refused and the replica keeps last-known-good (then fails closed at invalidation_max_staleness); the rendered hop.yaml is checked with the pinned agentgateway's --validate-only before it replaces the live file; /healthz gains audit_store_error and dpop_replay, audit_degraded pages on a data-store outage and now clears on recovery (it was sticky until restart), and a new control_store_down alert rule; an ineffective node relay point reports accepted_inert, never effective; the relay keeps a still-valid cached token while the STS is down and fails closed only within 5 s of expiry; transient store outages at the token endpoint answer 503 temporarily_unavailable + Retry-After: 2; a refresh_token rotation is undone when the mint fails, so a retry is no longer mistaken for reuse.

  • fix(agent-access): security fixes from the session-3 adversarial reviews (ledger docs/security.md AA-13..AA-23, AA-GEN-1): an ambient HTTP proxy no longer bypasses the egress SSRF guard (explicit [agent_access].egress_proxy_url instead); approval redemption is fenced on the live connection; duplicate JSON members are refused before any decoding; approval previews require read:content; SCIM and team-admin roster changes commit atomically with the member-generation fence; every revocation strictly advances the member floor; a zero-estimate MCP call's quota reservation persists the unit it was checked against; discovery retention prunes the control store on split deployments.

  • fix(agent-access): deploy/observer-mcpgw/docker-compose.a2.yaml sets stop_grace_period: 45s (Docker's 10 s default cut the companion's drain short); the istio.io/istio dependency moves past GO-2026-5363 / GO-2026-5289 (govulncheck: 0 reachable in all three binaries).

  • fix(deploy,observer-org): PostgreSQL migration 0032 creates btree_gist, which Azure Database for PostgreSQL Flexible Server refuses unless it is in azure.extensions: the Azure OpenTofu module now allow-lists BTREE_GIST (a drift test fails when the lineage creates an extension the module does not allow), and observer-org upgrade preflight gains a <plane> extensions row per PostgreSQL store that refuses before migrate when a pending migration needs an extension the server will not allow, printing the exact fix. A server not managed by the module (for example an existing demo estate) needs the printed az postgres flexible-server parameter set step before the roll that carries 0032.

  • fix(support-bundle): doctor.txt ran with the support-bundle command's own arguments (cobra reads os.Args when args are nil) and never held the doctor's output; config.redacted.toml no longer carries URL userinfo (a proxy password in [agent_access].egress_proxy_url / serving_replicas).

  • feat(sessions): Tok/s has one owner. The Messages table's throughput used to divide output tokens by the gap to the next row (idle time read as generation time); it now divides by a measured per-call duration - the proxy's request time, the tool's own recorded per-call time (devin, hermes, poolside, muse, legacy copilot, cowork) or spans reconstructed from the Claude Code / Codex transcript - and shows "not measured" otherwise; the gap is shown only as "Elapsed". The node Messages tab, the cockpit and the org session drawer render the same value (token_usage.gen_ms / gen_basis ship on the org wire as metadata). Agent migration 136, server 174 / pg 0040. See docs/message-throughput.md.

  • feat(pricing): frontier model price refresh (2026-09-23: Anthropic, OpenAI, xAI, Cognition) folded onto the seed with presence semantics (a dimension the snapshot omits keeps the seed value; a stated one wins, a quoted zero included); a feed replay / downgrade floor; cache reads a vendor does not price surface as unpriced instead of $0. org_model_prices.long_context_threshold becomes nullable (server 175 / pg 0041): NULL keeps the node's seed long-context tier, a quoted 0 means negotiated flat; orgcontract.PricingPolicyRow.LongContextThreshold is *int64 on the signed rail (compatible both ways).

  • feat(model-pricing): tokcron, an approval-gated refresh job for the Tokenomics data behind the public pricing feed: it re-fetches vendor endpoints, gates hand-captured prices against vendor pages it fetched itself, rehearses on a local database and writes a proposal only when the feed would change; only the operator's interactive approve step (re-proved on a throwaway clone of production) reaches production. See model-pricing/deploy/tokcron/README.md.

  • feat(org): bulk developer import - POST /api/org/members/import (dry run, up to 200 rows, preflighted refusals before any mint, itemized per-row status and honest delivery notifier_invoked / no_notifier_configured, audited) and an Import developers dialog on the Provisioning page (paste or CSV).

  • feat(guard): control coverage per tool - one row per tool joining the tool-call enforcement channel, the prompt-submit posture, budget admission and route proof, on observer adapters, observer doctor <tool>, GET /api/org/guard/coverage and the org Security page.

  • fix(org): every session-scoped org read and every org correlation that joined on a bare session id is now bound to the session's owner (sessions are keyed by id AND user; a same-id session pushed by another developer can no longer be read through, merged into, or counted against a colleague's), including Live, the monthly report, LOC aggregates, the route matrix and coding-job evidence (an ambiguous owner is refused rather than guessed); task prose, the raw action target and the raw project_root are served only to callers holding read:content (ledger ORG-SCOPE-1 / ORG-CONTENT-1 / ORG-SCOPE-3).

  • fix(org): project display names never show a hash-seeded placeholder when a repository name is known (one resolver for the Projects list, project detail, sessions, budgets and team views); the org Tools page gains a per-tool version histogram (GET /api/org/tools/versions).

  • fix(alignment): the Projects-page local LLM judge (tier J) refuses to send org-owned or unknown-authority evidence to a non-loopback endpoint unless it is org-pinned; loopback detection is an exact host match (ledger JUDGE-1).

  • fix(cursor): Cursor IDE sessions no longer lose their token rows - the hook writes tokens first under their own deadline, Cursor's own hooks log is replayed as a backstop (deduplicated against the live hook), root-less events resolve to the session's real project root, and stale hook entries left by a lost build are healed on registration (observer doctor check cursor.hooks; observer backfill --cursor-hook-usage recovers history).

  • fix(deploy): the Azure env-sync re-applies a secret rotated in Key Vault to an already-rendered .env value and tracks what it applied per key (pending / committed / operator_override), so a crash on either side of the write is recoverable and an operator's own value is never overwritten (D-DEMO-16).

  • fix(configschema): the committed [mcp_relay] annotation rows that the embedded config schema was generated from (make verify-config-schema is green again).

  • docs(agent-access): operator reference docs/agent-access.md (incl. a per-profile enable checklist); runbooks for key rotation, restart while routed, audit degraded, vault refresh and CVE patching; docs/agent-access-production-gates.md (doc3 §18: gates 1-3 and 5 pass locally; the gate-4 reapply tool is built but the drill has not run; gate 7 is built as code with enablement pending registry credentials; live client interop not run); the vendor pen-test scope docs/agent-access-pentest-scope.md. Not yet done: push and deploy, the estate soak, the external penetration test, the six-agent security sweep, the live Azure Key Vault and client-interop checks.

  • feat(projects): a new Skills tab on the node Projects detail panel (and observer project <id|root> --skills) shows every skill a project can load (.claude/skills/<name>/SKILL.md and ~/.claude/skills), how each changed across the project's commits (versions identified by git blob id; added/modified/deleted, reintroduced, exact-content moves), and per session three separate facts: the version the Claude Code hook OBSERVED on disk at session start (SessionStart incl. resume/compact), the version committed at the commit the git REFLOG says HEAD was on, and the version each Skill-tool invocation used (PostToolUse, joined by tool_use_id). Sessions before capture read "not captured", never a guessed version; "uncommitted"/"untracked"/"ignored" come only from the status porcelain. Capture: hook snapshots (fail-open, 250 ms budget) + a read-only git step riding the commit scanner tick (reflog, ls-tree, status) through the one gitview envelope, with GIT_NO_LAZY_FETCH=1 added for this step only (a partial clone never fetches). Reflog entries sharing one second are ordered by the reflog itself, and a session whose chosen second holds several commits reads "HEAD moved several times in one second" rather than a guess; same-second commits are ordered by ancestry. Agent migration 135 adds seven NODE-LOCAL tables (privacy sentinel + seeded test); [projects].skill_history (default on) and skill_history_skew_seconds (default 120). Existing endpoints are byte-identical. See docs/projects-page.md "Skills: versions across commits and sessions".

  • fix(teams): the org session drawer's message rows are derived by the SAME pure code as the node's Messages tab (new internal/sessionmsg): orphaned actions, proxy/JSONL twins, codex multi-call turns (new wire column token_usage.turn_id, server migration 160 / pg 0026), user-prompt keying and Copilot shadow rows now fold identically on both sides; web2 labels a body that exists but joins no row "captured, not aligned" instead of "not shared" and joins tool bodies by id.

  • perf(projects): one union activity query, one windowed LOC loader and agent migration 130's three covering indexes replace four correlated EXISTS probes and a whole-ledger LOC scan per Projects read; every project window is half-open [since, until).

  • fix(projects): the Projects page's spend figures (detail panel, the /projects list, and every usd ROI proxy) now go through the process cost engine's own per-turn dedup+pricing pipeline instead of a second, drifted implementation - closes several undercounting bugs (session-cumulative adapters like droid/goose/crush double-counted against their own proxy rows; a proxy turn's project was silently dropped whenever api_turns.project_id was NULL, which is every grounded install; a codex-shaped turn's reasoning-token split could double-bill). The commit count shown on the detail panel, the /projects list and the ROI proxies is now the same reachable-only predicate everywhere.

  • fix: the Projects-page Commits/Prompts/Spend tabs now surface a "row caps hit" notice (matching the existing Overview banner) whenever a request-time linkage cap actually truncated their data, and flag a prompt's committed/uncommitted status as uncertain when it was computed over a capped input; the underlying prompt-linkage query and the task-report rollup are both faster (a new covering index and batched, no-longer-N+1 task queries).

  • fix(predict): codex rate-limit snapshots were silently dropped when a client reported plan_type: null with a populated window; codex's 5h/weekly window label is now derived from the window's own duration instead of its primary/secondary position (a single-window plan was rendering its weekly cap under the "5-hour" label). The next-message predictor's limit gauge gained an honest "not visible" state (CLI, dashboard, /api/session/<id>/predict) for tools where no local usage-limit signal can exist (cursor, grokbot), replacing the misleading "route through the proxy" hint. Run observer backfill --codex-rescan if your codex rate-limit history has a gap.

  • fix(tools): the Connected Tools page now flags compiled-in default adapters that are missing from a hand-written enabled_adapters list (a warn banner + a "not enabled (new default)" pill, one owner: the adopt-defaults diff), and observer config adopt-defaults --write states honestly that the daemon must be restarted before the new adapters capture anything.

  • Node dashboard: a new Projects page detail panel (web/src/components/ProjectDetailPanel.tsx,
    web/src/components/projectdetail/) with six tabs — Overview, Spend, Commits, Prompts, Tasks,
    Guidance — answering "is the money I put into API tokens turning into shipped work?" per project.
    The list view (web/src/pages/Projects.tsx) grows additive spend/AI-lines/commit/capture columns;
    an empty corpus keeps a byte-identical legacy /api/projects payload. See docs/projects-page.md.

  • Commit capture: a new read-only, HEAD-only git log scanner (internal/commitscan, internal/commitlog,
    daemon-lifetime, never a git hook install, [projects].commit_scan default on, 120s ticker) populates
    three new node-local tables (project_commits, project_commit_files, project_commit_scan, migration
    127) with reachability revalidation every tick so a rebased/reset commit is flagged, never deleted.
    observer backfill --commits runs a full-history pass; observer doctor gains a commit-capture line.

  • Prompt-to-commit attribution + ROI: a pure internal/projectroi package links each AI edit to its
    owning prompt, applies a per-file supersede rule, then matches against commits within a configurable
    link window ([projects].commit_link_window_days, default 14 days) to produce a committed /
    partial / uncommitted / superseded / no_edits status per prompt. Eight ROI proxies (spend per
    AI line reached, AI-files-reached share, spend with no linked commit, spend per commit/per completed
    task, prompts/turns per commit, cache-read share) each ship their formula and an honesty caveat;
    nothing is called "dead" or "line survival" — file-level reach is stated as exactly that.

  • Projects page spend is priced at READ time through the process cost engine (recorded cost wins when

    0; otherwise the turn's full token bundle is priced at its own timestamp), de-duplicated per turn
    across the proxy and transcript captures with the cost engine's own identity rule, and reports
    spend.unpriced_turns (turns with no recorded cost and no pricing entry) on the API, the Overview
    tile, the /projects list (spend_unpriced_turns_30d) and the CLI - a corpus that stores $0 in its
    cost columns no longer renders $0.00 (found on this repo's own corpus during the 2026-09-22 review).

  • observer project <id|root> [--days N] [--json] prints the same per-project summary the dashboard's
    detail panel shows, through the one shared composition (dashboard.ComposeProjectDetail).

  • Commit capture reports a fourth state, error (the last scan failed and none has succeeded since),
    instead of hiding a failing scanner behind ok; full-history scans are paged (500 commits per
    bounded git call, 60 s each) so observer backfill --commits completes on a large repository; a
    project rooted in a subdirectory of a repository is scanned with its subtree as the pathspec (file
    paths re-based onto the project root) instead of being credited with the whole repository's history.

  • Alignment grading (delivered vs. missed): a three-tier design — always-on local heuristics (tier L),
    an opt-in local/configured LLM judge (tier J), and Cloud Intelligence grading under the existing
    extended_evidence_deep_review purpose (tier C, observer cloud grade-commit). Tier C ships its node
    contract and request path in this release; the hosted executor is honestly not_available: hosted kind not deployed until it exists, never a fabricated grade.

  • Guard, proxy lane: goose's built-in developer__shell tool is now in the response-side tool
    table (responseToolShape), so a shell command goose intends to run is evaluated and flagged
    like Bash/run_command; before, goose shell calls were invisible to the proxy's response scan.
    Grounded on the demo estate 2026-09-21 (session 7). Response-side scanning stays flag-only.

  • Org dashboard, Guard tab: the bundle editor's rows are called RULES ("+ Add rule", "Rules (n)",
    "Remove rule"); before, "+ Add override" shared a card with "Developer may override" (the
    developer exception), one word with two meanings, which made a multi-rule bundle read as a
    one-rule form. The [[override]] TOML key is unchanged.

  • Org fleet findings: the evaluator's GRANTED set now includes the authority of the fleet grant-replacement
    generation a member acked under the enterprise posture (through the posture-owned
    AckedAuthorityByMember seam), not only the member's enrolment token. Before, every node that accepted
    the org's own fleet document was raised as authority_divergence ("accepted authority that was never
    granted") the moment it reported - D-DEMO-14, found on the demo estate on the first policy-acks after
    rc.8. A member that accepted tokens beyond its acked document is still flagged; an orphaned ack row
    never resurrects a deprovisioned member; on a split control store without the posture tables the fold
    is empty by construction and every other error is surfaced.

  • Org CLI: observer-org policy publish --team <id> (repeatable) publishes a TEAM-scoped guard bundle
    through the same path the dashboard's Guard tab uses (composed strictest-wins on the org-wide floor
    for members of those teams); without --team the command is unchanged (org-wide). The wave contract
    named the CLI and only the API/dashboard had it.

  • Node, org governance: the effective-policy-state reporter is now constructed on every org-client node
    and stays dormant until its channel is enabled, so an org raise of the policy_state share (enterprise
    default body, extract.policy_state authority) reaches a managed node whose local
    [org_client.share].policy_state was left off. Before, that raise had no reporter to act on: the node
    never posted a policy-ack and the org's fleet findings read every governed developer as
    governance_lapsed ("never reported a governance state") - D-DEMO-13, found on the demo estate the
    moment the rc.8 sweeper started. Individual nodes are unchanged (the org cannot raise the share there).

  • feat(ui): dashboards UI pass 1 (web, web2, cloud portal): one shared CSS motion layer (route enter, stagger, count-up, reduced-motion safe, transform / opacity only, no animation library); one query cache per app (concurrent requests deduplicated, stale-while-revalidate across mounts, visible staleness instead of old data shown as current); terminals follow the app theme by default and can be pinned light or dark in the terminal header; the shared Tailwind preset's opacity fix revives ~880 classes that rendered nothing, and fg-3 text meets WCAG AA; web2 and the portal are route-split (first-paint JS: web -18%, web2 -79%, portal -55%); quiet sessions poll every 60 s instead of 8 s. Report docs/audits/dashboards-ui-review-2026-09-27.md.

  • feat(ui): UI pass 2: the Cost chart overlays its series; the "Actions over time" legend no longer overlaps the top y-axis label; a query-key bug that requested /null is fixed; one shared slide-over with a focus trap; the open drawer and its tab live in the URL; filters are route-aware; the cloud portal's buttons, cards and switches come from the shared primitives.

  • feat(ui): the shared design kit across all three apps (plan docs/plans/dashboard-visual-upgrade-tracker-2026-09-28.md, WS1-WS10): real vendor logos for every tool key with capture-surface pips and a monogram for an unknown tool (attributions in shared/lib/THIRD_PARTY_ICONS.md); model-family, host and IdP marks and one shared model-id renderer; an SVG brand mark, branded loader and boot screens; one icon system; one tone vocabulary so the same status reads the same colour and pill everywhere; illustrated empty states, loading and error states, and a permission-denied state (a 403 is a denial, not an error); live signals (live dot, meters, progress rings) and number tweens; one Modal / Toggle / ConfirmButton / CopyOnClick / Tooltip; table hover and zebra rows; chart legends; branded sign-in shells for the org dashboard and the portal; radial gauges in the session detail.

  • feat(ui): finish-round UI pass 3: a density toggle (comfortable / compact) in all three apps; the node's hand-rolled tables move onto one DataTable (sorting, numeric alignment, a loading state), now a single shared component with web2's row expansion; filters in the URL (node: window, range, tool, project, search; org: ?days= on every route); sidebar collapse on the node and org dashboards; the web2 Spend figure counts up; the Security pages and org Settings fit a 390 px screen; a 403 on any chart or panel renders the shared permission-denied state. Behaviour changes: a cache row flagged by the engine is amber (warn) everywhere; destructive deletes need a two-step confirm (org: team, budget, dated rate, alert rule, project-identity rule, deployment connector, intelligence provider, virtual-key revoke, announcement retract, dataset item; node: Remote "Revoke all", arena candidate discard, "Run retention now", the terminal's "Stop & close"). Source maps are built hidden and never shipped in the embedded bundles.

  • feat(ui): the custom time range is a picker, not typed datetime fields (node and org): one-click presets (Today, Yesterday, This week, Last week, This month, Last month), a Monday-first month calendar (start day, then end day; future days disabled) and hour / minute selects; the end defaults to Now. The org dashboard's rollups are trailing windows, so its picker chooses a start and runs to now.

  • feat(dashboards): charts bucket by the window - 5 min / hour / day / week in the viewer's time zone, zero-filled, with a per-chart Auto / 5 min / Hour / Day / Week control (only the buckets the window allows, at most 2,000 points; an over-cap request is a 400 granularity, never a silently coarser chart; the choice travels in the URL as gran=). Auto picks 5 min up to 3 hours, hour up to 7 days, day up to 180 days, else week. Node: every time-series endpoint now honours the selected window (analysis trend, cache-savings trend, cost-by-hour, cost-by-day-of-week-hour and cache timeseries used to serve 30 days on 1h / 12h / custom), and the Analysis headline, movers, top sessions and routing suggestions and the Cache overview and events follow it too; the raw proxy-only hour query (which dropped transcript rows) is gone. Org: the window ladder gains 1h / 12h / custom (additive hours / since / until / gran / tz params; a days-only request keeps the daily response); sub-day spend is read from raw rows within the cap and Auto picks Day above 2 days; charts fed by daily pushed summaries offer Day / Week with a "daily data only" note. Cloud portal: day labels and a daily-data note. Review fold: the zone database is compiled in, so a Windows node buckets in the viewer's zone instead of silently in UTC (a fallback says "UTC buckets (zone unavailable)"); every series on a page agrees across DST changes; malformed timestamps no longer 500 on PostgreSQL; zero-filled org series show their empty state again; window-scoped analytics answers of a day or less are at most 30 s fresh. Plan docs/plans/chart-time-granularity-plan-2026-09-29.md.

  • perf(dashboard): node dashboard performance audit on a real 27 GB database, and fixes (docs/audits/node-dashboard-performance-audit-2026-09-29.md): a stale-while-revalidate response cache for 30 heavy GET endpoints (inside every guard, invalidated by dashboard writes); polls re-arm only after the previous one settles; the Sessions list polls every 30 s and pauses while the drawer is open; memoized table rows and charts, lazy tooltips, cached date formatters, finite illustration animations; the session Messages tab loads only the returned page; agent migration 147 adds covering indexes (sessions activity, excerpt lookup, latest limit snapshot, repeated-command discovery); the process-to-action correlator searches a sorted time window instead of every action. Measured on a copy of that database: drawer tabs 38-240 s -> 1.2-10 s to data-complete, Overview 157 s -> 54 s cold / 17 s warm, Analysis 111 s -> 33 s / 0.6 s, Discovery 60 s -> 12 s / 0.5 s, Cost 76 s -> 16 s / 6 s, Report 22 s -> 0.5 s; blocking time on drawer tabs 2-23 s -> 0.1-0.7 s; the correlator 6.2 s -> 71 ms on 20k x 15k. The org dashboard and the portal inherit the shared client fixes. On the live daemon (cold, first visits after a restart): Overview >240 s -> 93 s, Analysis 116 s -> 61 s, Discovery >240 s -> 27 s, Report 58 s -> 0.4 s, session Messages tab 207 s -> 5.4 s; idle main-thread use 5-35 % -> 1-2 % on every page.

  • perf(dashboard): the Sessions list uses its index again - the default sort repeated started_at, which kept SQLite off idx_sessions_started and scanned every session before the page limit (/api/sessions first call 4.2 s -> 0.14 s, byte-identical responses, plan pinned by a test); the Overview stale-reads tile asks /api/discover?sections=stale instead of computing the whole discovery report (5.7 s -> 0.23 s warm; it was the last panel on a cold Overview); chart first mounts take turns instead of mounting about ten charts in one task (Analysis blocking time roughly halved); bar charts with more than 400 bars (a 7-day hourly trend is about 1,200) draw without the entry animation.

  • perf: optimization review (docs/audits/optimization-review-2026-09-27.md): node Overview 40-47 s -> 11-21 s, Analysis 14-16 s -> 9-12 s, Cost 7-8 s -> 4.5-5.5 s, Sessions 8.5-9 s -> 6.8-7.4 s on a real 21.5 GB database copy (agent migration 138 covering index, a dashboard-only raw-row cache in the cost engine, serve-stale-then-refresh for /api/status and watcher health); org session drawer spend queries ~716 ms -> ~10 ms on a 900k-row PostgreSQL store (server 176 / pg 0042, indexes only); the org rollup cache shares concurrent cold loads and an invalidation beats an in-flight load.

  • perf(org): a daily deduplicated spend summary (spend_daily, server 184 / pg 0050) written at ingest by one writer from the same per-row projection and duplicate-count verdicts as the live spend query; every ingest path, re-send, moved row, tombstone, scrub, purge, eviction and prune refreshes the affected units in the same transaction. Overview, Projects, People, Teams, Tools, Models, Movers, reports and budget totals read it (a window is split into live head, summary middle and live tail; until the boot rebuild has stamped the summary every reader stays on the live tables). Measured on a 462k-token-row fixture: Overview 15.9 s -> 1.2 s (PostgreSQL), Projects 10.2 s -> 0.45 s, budget total 834 ms -> 60 ms. The session drawer, Live, workspaces and the People model ladder stay on the live tables.

  • feat(pricing): prices come from the Tokenomics database with their history: the public feed carries a per-row history of dated periods, the org importer keeps every period, and the cost engine prices each turn at the period in force at its timestamp (a period the source does not state is an honest miss, never a guess); the compiled seed snapshot is generated from the signed feed and the hand-maintained dated timelines are retired. New or corrected rows include claude-opus-5-5-fast (was billed at half its fast price), mimo-v2.6-flash / -pro, Moonshot's dotted kimi-k2.6 / k2.7-code ids, gemini-3.5-flash-lite (was billed as 3.5 Flash), gemini-3.1-flash-lite (was billed as 3.1 Pro) and the composer-2.5-fast cache read; Copilot CLI Auto sessions record the model Auto chose instead of auto.

  • fix(pricing): the model maker's price wins over a reseller's. The feed export ranked offerings without preferring the maker, so reseller cards (Venice, Azure AI Foundry, Novita, OpenModel.ai) won for 16 models on the public feed from 2026-09-16 (for example Claude Opus 4.5-4.8 at $6/$30 instead of $5/$25 per million, gpt-5.4 input at $5 instead of $2.50); feed version 5 pins each maker's page, and the export's maker preference plus a guard listing reseller-won ids whose maker publishes a card follow in the next Tokenomics publish (open-weight ids such as gpt-oss-120b stay reseller-priced on purpose). Costs already stored at the reseller rates are not changed automatically: use the new re-price (below). On an org server, feed-owned price rows now mirror the latest applied feed (a first poll that answers 304 still catches up), so a stale imported reseller row can no longer stay in force in the org's price book, the gateway rate card or the enrolled nodes' signed pricing documents.

  • feat(models): Claude Sonnet 5.5 (claude-sonnet-5-5): a 512-token minimum cacheable prompt in cache tracking and a 1M-token routing context window; the price ($2 in / $10 out / $0.20 cache read / $2.50 5m and $4 1h cache writes per million, no long-context tier) arrives through the pricing feed, not from a hand row in the binary.

  • feat(pricing): opt-in retroactive re-pricing of stored costs, node and org (closes PRICE-REPRICE-1). Capture still stamps the cost; a re-price is an explicit act at the price in force at each row's own timestamp, never today's. Node: observer reprice is a dry run unless --apply (--revert <run>, --list, --since / --until / --model, --json), plus a Settings -> Pricing card; it re-prices api_turns and summary_calls costs Observer computed itself, never a vendor- or tool-reported cost (integration.TokenTier.ReportsCost, 13 tools), never writes $0 for an unpriced row, keeps the captured figure and a per-run change log (agent migration 145), and re-priced rows reach the org through the re-send queue. Org: /api/org/pricing/reprice* (write:pricing, history read:budgets, audited before any row changes, fail-closed) and a panel on the Pricing page re-price org-held rows from the org's own dated price book (server 187 / pg 0053) and refresh the spend summary. Review fold: a single dated org row prices only from its date; reverts run newest first (an out-of-order revert is refused and names the later run) and one run holds the claim at a time on the node and the org; the CLI honours an org pricing pin like the dashboard. Nothing re-prices automatically after a new price version, and a re-price never re-runs budget alerts or rewrites gateway reservations. See docs/pricing.md "Re-pricing stored costs".

  • feat(org,pricing): context windows reach enrolled nodes (an unsigned sibling of the signed pricing policy, context_windows, covered by the ETag and outside the signed bytes so older verifiers still accept the document), so a node and its org show the same context-gauge ratio. A re-parse can now correct a token row's reliability: a Crush session that grows past one step corrects itself without --crush-rescan.

  • fix(org): one duplicate-count rule on every spend surface, node and org. The org drawer header, model split and cost series derive from the same sessionmsg.Derive pass as the node (it had counted every proxied OpenCode turn twice); duplicate verdicts are stored at ingest and applied by every org list, page and drawer (server 179 / pg 0045; org Overview 30 d on PostgreSQL 71.7 s -> 3.5 s), and on the node by the cost engine, Analysis, reports, budget, live, statusline, predictor, guard token and priced-spend checks, cloud evidence and the task and sub-agent drill-downs (stored node verdicts, agent migration 143; server 182 / pg 0048). OpenCode twins whose output was clamped to 0 because reasoning exceeded the completion now fold (a session had shown 49,554 tokens for ~24.8K on node and org). The org names its push boundary ("as of "); a claude -p session reads sdk · cli on the org instead of other. Remaining: legacy session-less proxy rows always count.

  • feat(org): rows a node changes after pushing them reach the org (agent migration 140, server 178 / pg 0044): triggers queue a changed row only when enrolled and a shipped column changed, every row carries a node revision, and the org applies a re-sent row only when its revision is newer (a moved turn is relocated, never doubled). Corrections a node makes by deleting rows (dedup sweeps, merges, identity changes) ship an identity-only tombstone (agent migration 141); ageing deletes (retention) never propagate. Migration 142 fixes the queue triggers, which failed a whole ingest batch on enrolled nodes when a row was already queued. observer org resync (dry run by default, --confirm, --deletions default on) heals divergence from before the upgrade and backfills session end times. A share-posture change between two sends no longer lands a second org row (server 180 / pg 0046), and observer-org scrub-content / the enterprise purge collapse such twins instead of failing on the primary key.

  • feat(sessions): sessions get an end time: sessions.ended_at was never written by any path (NULL for every session of every tool); a table-driven rule (a session end closes, a later prompt or session start reopens) now sets it inside ingest, so the dashboards stop showing finished sessions as "in progress". Historical sessions pick it up on their next lifecycle event or via observer org resync.

  • feat(scoring): the session quality score is computed: only the manual observer score CLI ever called the scorer, so almost no session was scored. A daemon auto-scorer ([intelligence.scoring], default on, capped passes, a session counts as ended after 30 min idle) stores all four components (agent migration 137) and a Session quality card shows the breakdown and a stale-score note on the node session detail and the org drawer (server 177 / pg 0043; the org's newer-action count is derived like the node's). The scorer is about 80x faster on the largest session.

  • feat(org): context-window and rate-limit gauges on the org session drawer from one shared derivation (context used = newest non-zero cache read over the session's reported prompt budget or the model's context window; over-window and unknown stay unknown, never 100% or 0%). Rate-limit windows reach the org as a new metadata-only wire family session_limit_snapshots (5 h / 7 d utilization and resets; no headers or counters), gated by [org_client.share].limit_gauge or full-content sharing (server 183 / pg 0049); agent migration 146 starts an already-enrolled node's cursor at head so its older limit history is not shipped. The node session detail gains the same context gauge.

  • fix(codex,cowork): Codex (and Cowork) sessions no longer show a "Rate limit" row between every message. A rate-limit reading is recorded only when the limit really changes (status, plan, window, used percent by half a point or more, or a reset moved by more than 10 minutes), plus a 15-minute heartbeat that keeps the usage gauge fresh - on the author's own history that is about 9,100 readings instead of 53,500. In the session Messages tab, readings fold into the message they follow and a small badge (for example "7d 74%") marks only the turns where usage changed; node and org drawer derive this from the same shared code. Already-captured readings fold at display time; nothing is deleted.

  • feat(org): the Claude Code request class (x-claude-code-request-class: main, subagent, workflow, compaction, auxiliary; anything else stays empty, never guessed) is recorded per proxied turn (agent migration 144), ships to the org as a content-free enum (server 188 / pg 0054); both session-detail APIs return the per-class split and the org drawer shows it.

  • feat(org): sessions.parent_thread_id ships as metadata (server 162 / pg 0028) so the org drawer resolves a Cursor sub-agent session's tool account through its parent, as the node does; the per-session AI tool version reaches the org (server 161 / pg 0027).

  • feat(loc,projects): AI code vs comment lines on every lines-of-code surface, node and org, from one derivation (code = added + modified code lines, comments = added comment lines, a share only when either is non-zero): session card, Sessions list, the Cost lines-per-dollar tile (code lines only), Projects list, overview, commits, spend and prompts, observer loc show, observer project, and the org People, person / project LOC cards, "Code lines over time", developer footprint and session drawer (server 185 / pg 0051; an older agent's rows show no split rather than 0%). Honesty fixes: Projects "AI code lines", by-session and commit lines, the reached-line proxy and prompt edit counts no longer include docs and config files.

  • feat(projects): the session that owns each git commit, node and org. A table-driven rule: merge, unreachable, foreign-author (a teammate's commit you pulled) and no-AI-edit commits have no owner, never a guess; otherwise most AI code lines, then most files, then earliest prompt, then session id (comment lines do not count; sub-agent edits fold into the parent). Node: an Owner column on the Projects Commits tab, a Commits card on the session detail, GET /api/session/{id}/commits. Org: an additive commit-ownership wire family (no author identity, no paths; commit_sha_hash always, the raw SHA and subject only under full-content sharing; server 186 + 189 / pg 0052 + 0055), audited org session and project commit views, subject and raw SHA only with read:content. The local git author is stored as a hash only (agent migration 146). See docs/projects-page.md "Commit ownership" and ledger COMMIT-3.

  • fix(claude-code): tokens-per-second sanity: a response-side attachment introduced in Claude Code builds from 2026-09-26 sat in the timing start slot and collapsed generation spans (rates up to 127,667 tok/s). A table of response-side attachment types plus a strict-before rule fix the span (live 7-day max 229, no row at or above 500). Rows stored with the old rule are corrected when their transcript is re-parsed.

  • feat(proxy): the Claude Code prompt id (x-claude-code-prompt-id) is recorded per proxied turn (agent migration 139, node-local) and the next-message predictor groups by it; observer claude enables Claude Code's gateway hint headers only when routed to Observer's proxy and never over your own value. Codex: a Responses websocket upgrade is answered 426 so Codex falls back to captured HTTP; /v1/realtime routes to OpenAI instead of Anthropic; observer doctor codex gains codex.proxy_route and reports a managed requirements.toml provider. The org AI gateway forwards anthropic-* headers.

  • fix(cursor): an unfinished Cursor turn (quit mid-answer, or every retry failed) records evidence and a precise reason on the node page, the org drawer and observer doctor cursor (cursor.usage) instead of a number: no local artefact holds its billed usage. Auto-mode turns record the model Auto routed to per request; placeholder models (default, auto) never overwrite a concrete session model; hook input nets both cache buckets (cache writes were billed twice). cursor-agent 2026.09 also runs Claude Code's user hooks with Cursor payloads; the Claude Code receiver now ignores those (no duplicate prompt guard, no rows mis-tagged as claude-code).

  • fix(adapters): Hermes schema 30 auxiliary-call spend is captured on both the hook and database paths. Crush's token counters are the last step's context size, so only one-step sessions keep token counts; every other Crush session keeps a token row with its model and Crush's own cost at 0/0 tokens (reliability unknown), and observer backfill --crush-rescan corrects rows stored before. New tool-name mappings seen live or in vendor source (for example OpenCode question -> ask_user, Cline list_code_definition_names, Zed grep / fetch / spawn_agent, Kimi plan mode and task tools).

  • feat(mcp): MCP calls made through the node relay are tied to their session for every client, not only Claude Code: a third, unanchored correlation tier (always labelled inferred, read-side only, retroactive, ambiguity shown rather than guessed). Protocol traffic (tools/list, notifications) never claims a tool action and attaches at session level; the method reaches the org so the drawer shows the same fields as the node (server 181 / pg 0047).

  • feat(ide): observer ide <id> [project-dir] launches an IDE or desktop app through the same path as the dashboard's GUI launch and prints an honest per-agent routing outcome (vendor-hosted inference such as Cursor's own models, Antigravity, Kiro, Qoder, Devin / Windsurf or Grok Bot cannot be routed and is reported so). Live traffic proof is still owed for VS Code, JetBrains, OpenCode Desktop and Goose Desktop (steps in docs/proxy-wrappers.md).

  • feat(shell-wrap): command wrapping, default off: observer shell-wrap status|preview|enable|disable and a Settings -> Terminal "Command wrapping" card put PATH shims first so typing claude runs observer claude (per-tool opt-in; all means installed CLI tools only). One marked block in bash / zsh rc files, a fish conf.d drop-in or the PowerShell profile (never auto-created), an exact preview, byte-for-byte undo, recursion guards so no launcher resolves a shim. On observer start a shim whose observer binary was moved or deleted is re-pointed at the running binary (a still-runnable different binary is kept); the PowerShell profile resolves the real Documents folder. Ledger SHELLWRAP-1.

  • fix: small live-verification defects: the org session quality card's newer-action count is derived like the node's (it was always 0); the goose watcher no longer logs "caught up dropped writes" every 2 s for a database scanned by row watermark; observer doctor <tool> defers the whole-database quick_check (--integrity forces it); the Cursor "no finish hook" note no longer tells you to run observer init when the hooks are already registered.

  • chore(build): web/dist and web2/dist are no longer tracked (the three go:embed bundles stay committed, so go install and the Docker builds are unchanged), every dist tree is marked -diff, and source maps stay out of the embeds; a rebuild no longer produces a multi-megabyte diff that agents such as OpenCode copy into their session stores. Stored raw_tool_output is capped at 1 MiB at every writer.

  • fix(security): a review of what earlier reviews had not covered (docs/audits/security-review-2026-09-27.md; 3 High + 9 Medium found, all High and 7 Medium fixed with regression tests): the proxy refuses browser-shaped requests (a web page can no longer drive it cross-origin; CLI, SDK and editor clients are unaffected); the guard evaluates Monitor, PowerShell and Grep tool calls; a truncated PreToolUse payload asks instead of allowing in enforce mode; key_pool rotates only credentials in the pool; Gemini API keys are redacted; the org gRPC receiver authenticates before decoding; tree-sitter parsing runs under deadlines; a repository symlink into your home directory no longer leaks the target through get_project_guidance; node database files are restricted to 0600 when opened. The rest is ledgered as SR27-*.

  • feat(sandbox): sandboxed terminals are contained (SR27-SBX-1): each sandboxed launch gets its own network namespace with the tier from [terminal.sandbox].egress (internet default, proxy_only, none, or host which restores the old shared namespace). A host helper serves the observer proxy and an egress gateway over sockets bound into the sandbox, so launcher URLs are unchanged and the dashboard on :8081 is unreachable from inside; the gateway refuses loopback, link-local (incl. 169.254.169.254), multicast, the host's own addresses and private ranges (RFC 1918, CGNAT, IPv6 ULA and site-local) unless listed in [terminal.sandbox].egress_allow_cidrs. Every tier runs in a private PID namespace; host sockets under /run, WSL interop and agent environment variables are masked; Observer's secrets and the attach socket are hidden; daemon config, guard policies, shims, each tool's hook and MCP config and the workspace .git/config and hooks are read-only (a missing protected path gets a read-only placeholder) unless allow_tool_config_writes = true. A host that cannot create a network namespace refuses the launch (netns_denied), never a silent fallback. Linux and WSL2 only, opt-in as before; residual risk in ledger SR27-SBX-2, see docs/sandboxed-terminals.md.

  • fix(harness-gateway): the codex adapter runs codex with its built-in tools disabled (exec, shell, view_image and apply_patch calls return unsupported, web search off, the default-off features explicitly disabled), an allow-listed environment and a per-session private home; @openai/codex-sdk and @openai/codex are pinned to exactly 0.147.0 (the disabled list is re-grounded on every bump), and turns are serialized per session with the codex home disposed only after a running turn ends (SR27-C2).

  • fix(dashboard): the node dashboard's Origin check compares scheme, TLS, host and port with the request's own Host (loopback aliases equal) instead of the host alone (DASH-ORIGIN-1).

  • ci: third-party GitHub Actions in secret-holding jobs are pinned to commit SHAs (tag kept as a comment; Dependabot keeps them current) (SR27-SC1).

  • Price snapshot: 2026-09-17 (aws us-east-1, azure eastus2, gcp us-central1) — the dated
    three-cloud price snapshot every observer-org deploy plan estimate in this release is
    computed from (plan v2.1 6.9; scripts/verify-price-snapshot.sh --line prints this line and
    scripts/release.sh requires it in a final tag's section).


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.34.0-rc.10-linux-x64.tar.gz
Linux arm64 observer-v1.34.0-rc.10-linux-arm64.tar.gz
macOS x86_64 (Intel) observer-v1.34.0-rc.10-darwin-x64.tar.gz
macOS arm64 (Apple Silicon) observer-v1.34.0-rc.10-darwin-arm64.tar.gz
Windows x86_64 observer-v1.34.0-rc.10-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.34.0-rc.10

Org server (Teams)

The self-hosted org server is an enterprise-licensed product distributed from SuperBased's private container registry with a per-customer pull token issued with your enterprise licence; its release assets are not attached here. Contact sales for a pull token. The pull-and-verify recipe for your exact release is the README.md of the deployment bundle (observer-org deploy export).

Enterprise updates

This release publishes on the edge channel.

Each agent archive carries a detached vendor signature (<archive>.sig, raw Ed25519 over the archive bytes) and the release ships a signed update-manifest-edge.json. Self-hosted org servers consume them with:

observer-org update sync --version v1.34.0-rc.10
observer-org update publish --channel edge --version v1.34.0-rc.10

For a disconnected server, download observer-v1.34.0-rc.10-airgap-bundle.tar (archives + signatures + SHA256SUMS + the signed manifest + provenance), carry it across the gap, and run observer-org update import --version v1.34.0-rc.10 --bundle <dir>.

Supply chain

A CycloneDX SBOM for the agent is attached: observer.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