
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>SuperBased changelog</title>
  <subtitle>Release notes for SuperBased, the local-first cost-and-control layer for AI coding agents.</subtitle>
  <link href="https://superbased.app/feed.xml" rel="self" type="application/atom+xml"/>
  <link href="https://superbased.app/docs/changelog" rel="alternate" type="text/html"/>
  <id>https://superbased.app/docs/changelog</id>
  <updated>2026-08-26T00:00:00Z</updated>
  <author><name>Gaja AI Private Limited</name></author>
  <entry>
    <title>v1.32.0 - 2026-08-26</title>
    <link href="https://superbased.app/docs/changelog#v1-32-0" rel="alternate"/>
    <id>https://superbased.app/docs/changelog#v1-32-0</id>
    <updated>2026-08-26T00:00:00Z</updated>
    <published>2026-08-26T00:00:00Z</published>
    <content type="html">&lt;h3&gt;Fixed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;fix(retention): the daemon no longer runs unbounded full-database
&lt;code&gt;VACUUM&lt;/code&gt;s&lt;/strong&gt; - the retention size-cap's automatic, looping bare &lt;code&gt;VACUUM&lt;/code&gt;
(which could write tens of GiB of SQLite temp files on large databases and
fill the host disk) is removed from every automatic path. Size-cap
reclamation is now a single bounded pass (aged-actions shed + WAL
checkpoint + incremental vacuum where enabled); full compaction is
operator-triggered via &lt;code&gt;observer prune --vacuum&lt;/code&gt;, which now also requires
the daemon to be down and ~2× free disk headroom.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(db): connection-scoped pragmas apply to every pooled connection&lt;/strong&gt; -
&lt;code&gt;synchronous&lt;/code&gt;, &lt;code&gt;temp_store&lt;/code&gt;, and a new &lt;code&gt;hard_heap_limit&lt;/code&gt; memory backstop
moved into the SQLite DSN (previously they were applied post-open to one
arbitrary pooled connection, letting other connections spill temp files to
disk with default settings). The pool is now bounded
(&lt;code&gt;SetMaxOpenConns&lt;/code&gt;/&lt;code&gt;SetConnMaxIdleTime&lt;/code&gt;), and a regression test pins the
pragma set on N concurrent connections. Applied to the node DB, the org
server DB, and the edge WAL store.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(db): startup integrity check is size-gated&lt;/strong&gt; - &lt;code&gt;PRAGMA quick_check&lt;/code&gt;
(which reads every page and could run for over an hour on multi-GiB
databases) is skipped above a configurable size threshold
(&lt;code&gt;integrity_check_max_gb&lt;/code&gt;, default 8) with a 10-minute deadline;
&lt;code&gt;observer doctor db&lt;/code&gt; remains the explicit, authoritative integrity path.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(observer): cross-process maintenance lease&lt;/strong&gt; - retention,
maintenance, and codeintel-on-start acquire a flock-based lease so
concurrent observer processes cannot duplicate expensive maintenance work;
codeintel index-on-start gained an aggregate deadline.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;perf(store): org-push snapshot queries no longer sort or scan far more
than they ship&lt;/strong&gt; - three per-tick reads fixed, each verified with
&lt;code&gt;EXPLAIN QUERY PLAN&lt;/code&gt; and selection-equivalence tests: session network
events (per-session cap pushed into SQL via &lt;code&gt;ROW_NUMBER()&lt;/code&gt; so the body
join fires only on surviving rows, migration 089), session process rows
(same cap pushdown, plus the per-run event count now seeks a new
&lt;code&gt;process_run_id&lt;/code&gt; index instead of aggregating the whole &lt;code&gt;process_events&lt;/code&gt;
table per tick, migration 090), and the codeintel dev + teams-tier
aggregates (Cartesian-product joins rewritten to pre-aggregate per
file). On the profiled node these were ~55% of steady-state daemon CPU.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(arena): Windows build&lt;/strong&gt; - unix-only process-group syscalls in
&lt;code&gt;internal/arena&lt;/code&gt; are build-tagged, restoring &lt;code&gt;GOOS=windows&lt;/code&gt; builds (and
the win32 npm/VSIX artifacts).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Added&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;feat(observer): env-gated pprof endpoint&lt;/strong&gt; - &lt;code&gt;OBSERVER_PPROF_ADDR&lt;/code&gt;
(loopback-only, default off, fail-soft) serves &lt;code&gt;net/http/pprof&lt;/code&gt; for the
daemon's lifetime, so steady-state CPU consumers can be named empirically.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(observer): temp-file watchdog + startup guidance&lt;/strong&gt; - a background
check WARNs when deleted-but-open SQLite temp files exceed a threshold
(the failure mode that silently consumed ~80 GiB inside WSL), a
stale-binary check WARNs when the running executable no longer matches
the on-disk build, and daemon startup states that full integrity checks
and compaction are operator-triggered.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Docs&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Root-cause audit + remediation plan for the disk/compute exhaustion
incident, and a steady-state CPU audit (pprof-named findings, a full
background-loop cadence inventory, and prevention guidance) with its
remediation plan - see &lt;code&gt;docs/audits/&lt;/code&gt; and &lt;code&gt;docs/plans/&lt;/code&gt;
(&lt;code&gt;*2026-08-26*&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v1.31.0 - 2026-08-17</title>
    <link href="https://superbased.app/docs/changelog#v1-31-0" rel="alternate"/>
    <id>https://superbased.app/docs/changelog#v1-31-0</id>
    <updated>2026-08-17T00:00:00Z</updated>
    <published>2026-08-17T00:00:00Z</published>
    <content type="html">&lt;h3&gt;Added&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(adapter): JetBrains Junie adapter&lt;/strong&gt; - event-sourced &lt;code&gt;events.jsonl&lt;/code&gt;
capture for JetBrains' Junie coding agent, bringing the supported-tool
count to 33.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(judge): opt-in Baseten judge provider&lt;/strong&gt; - a Qwen 2.5 3B Instruct
judge behind a budget on/off switch, for admission and eval scoring.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;docs: adapter count reconciled to 33&lt;/strong&gt; - READMEs, package manifests, and
in-product copy aligned to the 33 tools folded from the integration
registry.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(plane-a): P1-4 remote-config and cert rotation v1&lt;/strong&gt; - server migration
040 &lt;code&gt;org_fleet_remote_config&lt;/code&gt; / &lt;code&gt;org_fleet_cert_events&lt;/code&gt;; GET/PUT
&lt;code&gt;/api/org/fleet/collectors/{id}/config&lt;/code&gt;; POST
&lt;code&gt;/api/org/fleet/collectors/{id}/certs/rotate&lt;/code&gt; (placeholder not_before/
not_after); fleet board gains &lt;code&gt;remote_config_present&lt;/code&gt; / &lt;code&gt;last_cert_event&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;refactor(plane-a): telemetry bundle helper for deployment paths&lt;/strong&gt; -
&lt;code&gt;telemetry.AssembleBundle&lt;/code&gt; is the single seam for capabilities/Doctor/
connector Test connection; handlers no longer construct CH/Parquet/SQLite
adapters inline. Full Control Store rewrite (Postgres dialect across
orgserver handlers) remains residual (tracker P1-7).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(plane-a): P1-1 FTS filter on ClickHouse query store&lt;/strong&gt; - additive
&lt;code&gt;model.QueryRequest.TextQuery&lt;/code&gt;; ClickHouse &lt;code&gt;fts_text&lt;/code&gt; column (DedupKey+
ServiceName) + &lt;code&gt;positionCaseInsensitive&lt;/code&gt; filter. Trajectory
(&lt;code&gt;obs_traces&lt;/code&gt;) explorer remains without FTS - TelemetryQueryStore only.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(plane-a): P1-9 Doctor + demo IaC emit&lt;/strong&gt; - &lt;code&gt;POST /api/org/deployment/doctor&lt;/code&gt;
returns &lt;code&gt;{ok, probes, ingest_ok, query_matched, detail}&lt;/code&gt; (hot/ingest/query/
durable Probe + synthetic &lt;code&gt;doctor-&amp;lt;uuid&amp;gt;&lt;/code&gt; batch when hot configured);
&lt;code&gt;GET /api/org/deployment/iac&lt;/code&gt; emits static Terraform/Bicep demo templates
(CH URL / Blob / ACI open-webui vars, no secrets); &lt;code&gt;/deployment&lt;/code&gt; Doctor +
IaC card.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(plane-a): P1-7 ClickHouse HTTP adapter + JSONL durable SoR&lt;/strong&gt; -
&lt;code&gt;clickhouse.Store&lt;/code&gt; (EnsureSchema / IngestBatch / Query / Probe via HTTP
JSONEachRow; &lt;code&gt;OBSERVER_CLICKHOUSE_URL&lt;/code&gt; or &lt;code&gt;CLICKHOUSE_URL&lt;/code&gt;); &lt;code&gt;parquet.Store&lt;/code&gt;
filesystem JSONL under &lt;code&gt;OBSERVER_PARQUET_ROOT&lt;/code&gt; (engine &lt;code&gt;parquet_object&lt;/code&gt;,
interim until Arrow); stubs when unset; &lt;code&gt;assembleTelemetryBundle&lt;/code&gt; prefers
env stores; &lt;code&gt;POST /api/org/deployment/doctor&lt;/code&gt; synthetic ingest+query.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(plane-a): P1-4 fleet inventory + health board v1&lt;/strong&gt; - org-scoped
collector board (&lt;code&gt;fleetinventory&lt;/code&gt;) with healthy/stale/never_seen;
&lt;code&gt;GET /api/org/fleet/collectors&lt;/code&gt;; hosted on &lt;code&gt;/deployment&lt;/code&gt;. Residual:
remote config / cert rotation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(plane-a): P1-2 entity correlation graph v1&lt;/strong&gt; - server migration
039 &lt;code&gt;org_entities&lt;/code&gt;/&lt;code&gt;org_entity_edges&lt;/code&gt;; Upsert/List/Link/Neighbors; admin
APIs + &lt;code&gt;/deployment&lt;/code&gt; entity card. Provenance taxonomy unchanged.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(plane-a): P1-9 Phase 2 - connector catalog + capability probes&lt;/strong&gt; -
server migration 038 &lt;code&gt;org_deployment_connectors&lt;/code&gt;; catalog CRUD + Test
connection via P1-7 capability Probe; &lt;code&gt;/deployment&lt;/code&gt; shows resolved
capabilities + connectors.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(plane-a): P0-10 Phase B - targeting, simulate, rollout UX&lt;/strong&gt; -
workspace/environment/service selectors on policy-resource publish
(signing-bound); agent GET query attrs; &lt;code&gt;POST …/simulate&lt;/code&gt; fleet
preview; &lt;code&gt;/policy&lt;/code&gt; rollout panel wired to P1-3 APIs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(plane-a): P1-7 Phase A - engine ratification + capability seams&lt;/strong&gt; -
designate ClickHouse T1 / Postgres control / SQLite starter / Parquet SoR
(harness = validation). Pure &lt;code&gt;telemetry/model&lt;/code&gt; + five capability contracts +
topology resolver; SQLite adapter; ClickHouse/Parquet NotConfigured stubs;
&lt;code&gt;GET /api/org/deployment/capabilities&lt;/code&gt;. Plan:
&lt;code&gt;docs/plans/plane-a-storage-ha-plan.md&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(plane-a): P1-9 Deployment Control Center Phase 1&lt;/strong&gt; - server
migration 037 &lt;code&gt;org_deployment_wizard&lt;/code&gt;; &lt;code&gt;GET/PUT&lt;/code&gt; topology APIs; web2
&lt;code&gt;/deployment&lt;/code&gt; wizard (SQLite / ClickHouse-recommended / existing /
custom). Connectors, Doctor, IaC residual (P1-7 blocked). Plan:
&lt;code&gt;docs/plans/plane-a-deployment-control-center-plan.md&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(plane-a): P0-10 Organization Control Center Phase A&lt;/strong&gt; - admin
HTTP list/show/lint for &lt;code&gt;admission.input&lt;/code&gt; + &lt;code&gt;egress.routing_guardrail&lt;/code&gt;;
web2 &lt;code&gt;/policy&lt;/code&gt; gains family tabs (Guard TOML + Plane-A JSON
lint→publish) with links to &lt;code&gt;/fleet-state&lt;/code&gt;. Targeting/simulate/rollout
UX residual. Plan: &lt;code&gt;docs/plans/plane-a-p0-10-org-control-center-v1-plan.md&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(plane-a): P1-3 policy rollout + exceptions v1 (API+CLI)&lt;/strong&gt; -
server migration 036 (&lt;code&gt;org_policy_rollouts&lt;/code&gt; / &lt;code&gt;org_policy_exceptions&lt;/code&gt;);
canary delivery via &lt;code&gt;policyrollout.ResolveDelivered&lt;/code&gt; on
&lt;code&gt;GET /api/agent/policy/{family}&lt;/code&gt; (named + hash% cohort; waivers force
baseline); admin stage/approve/promote/halt/rollback + exception
routes; auto-halt from &lt;code&gt;policy_state&lt;/code&gt; cohort rates; rollback republishes
baseline as MAX+1; CLI &lt;code&gt;observer-org policy-rollout&lt;/code&gt;. UI deferred to
P0-10. Plan: &lt;code&gt;docs/plans/plane-a-p1-3-policy-rollout-exceptions-plan.md&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(plane-a): P1-1 trajectory explorer v1 (pagination + filters)&lt;/strong&gt; -
&lt;code&gt;GET /api/org/obs/trajectories&lt;/code&gt; gains Sessions-style &lt;code&gt;limit&lt;/code&gt;/&lt;code&gt;offset&lt;/code&gt;/
&lt;code&gt;total&lt;/code&gt; plus status/source/session_id/model/provider filters over the
pushed &lt;code&gt;obs_traces&lt;/code&gt; substrate. Web2 &lt;code&gt;/trajectories&lt;/code&gt; gains a filter row&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pager. FTS / saved views / live-tail / gateway browse / million-trace
remain deferred (P1-7). Plan:
&lt;code&gt;docs/plans/plane-a-p1-1-searchable-trajectory-explorer-plan.md&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(plane-a): P1-10 production self-obs retrofit (Phases A-D)&lt;/strong&gt; -
opt-in &lt;code&gt;[selfobs]&lt;/code&gt; (default OFF) builds a credentialed OTLP emit sink
in &lt;code&gt;buildProxy&lt;/code&gt; (Shutdown on cleanup). Routing Decide emits sampled
DecisionRuns (&lt;code&gt;routing_sample_n&lt;/code&gt;, default 32). Admission Admit, online
eval (&lt;code&gt;OnlineSampler.OnScored&lt;/code&gt;) + CLI &lt;code&gt;obsEvalRun&lt;/code&gt;, and &lt;code&gt;observer advise&lt;/code&gt; emit under &lt;code&gt;system_agent&lt;/code&gt;. Conformance registry Wired:true for
routing/advisor/admission/eval (insight-agent remains P2-7). Plan:
&lt;code&gt;docs/plans/plane-a-p1-10-production-retrofit-plan.md&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(plane-a): P0-5 unified policy resource v1&lt;/strong&gt; - org distribution for
&lt;code&gt;admission.input&lt;/code&gt; + &lt;code&gt;egress.routing_guardrail&lt;/code&gt; (agent mig 081 / server mig
035). Signed fetch + CAS-fenced accept, enrolment-generation fence,
LKG-before-listener (incl. standalone &lt;code&gt;observer proxy start&lt;/code&gt;), steady-state
poller, layered Org ownership on the shared AdmissionService, and P0-6
reporter widening (&lt;code&gt;accepted_inert&lt;/code&gt; / &lt;code&gt;delivered_unaccepted&lt;/code&gt;). Pure
compilers live in &lt;code&gt;internal/policyfam/{admission,egress}&lt;/code&gt;; wire in
&lt;code&gt;internal/orgclient&lt;/code&gt; + &lt;code&gt;cmd/observer/policyresource_wire.go&lt;/code&gt; +
&lt;code&gt;internal/orgserver/policyresource&lt;/code&gt;. Codex BLOCK B1-B11 + SHOULD-FIX
SF1-SF8 folded (304 revalidate, LKG pin-required, cache-tree clear on
identity change, Cleared outcome slots, accepted_inert↔observe,
publish BEGIN IMMEDIATE + in-txn audit, 4KiB description cap).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(dashboard): New Terminal dialog gains a model picker.&lt;/strong&gt; Per-tool,
capability-gated: a grounded &lt;code&gt;Model ModelSpec&lt;/code&gt; row on the adapter's
&lt;code&gt;internal/integration&lt;/code&gt; capability declares HOW a tool takes a model
(top-level flag, subcommand-scoped flag, or env var) so no consumer
branches on tool name. The picker is seeded from the tool's own local
session history (180-day window, recency-ordered) plus the row's
grounded known models; an invalid or unsupported value is silently
dropped so the tool's own default applies. goose is delivered via
&lt;code&gt;GOOSE_MODEL&lt;/code&gt; (env-only, no flag exists); kiro-cli's &lt;code&gt;--model&lt;/code&gt; lives
under its &lt;code&gt;chat&lt;/code&gt; subcommand. openclaw and droid get no picker at all -
neither has a grounded seed-time model mechanism (droid's &lt;code&gt;--model&lt;/code&gt;
exists only on its headless &lt;code&gt;droid exec&lt;/code&gt;, not the interactive launch).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(terminal): New Terminal launches can run inside a bubblewrap
filesystem sandbox (Linux + WSL2, opt-in, default off).&lt;/strong&gt; New
&lt;code&gt;internal/sandbox&lt;/code&gt; (bwrap argv composition + a readiness probe) and
&lt;code&gt;internal/workspace&lt;/code&gt; (three host-side workspace sources) packages,
both pure per CLAUDE.md #1 - no SQL/HTTP/os-exec, the actual &lt;code&gt;bwrap&lt;/code&gt;
and &lt;code&gt;git&lt;/code&gt; exec calls live in the one seam,
&lt;code&gt;cmd/observer/terminal_sandbox.go&lt;/code&gt;. The private root is bwrap-only in
v1 (no Docker backend); it shares the host's network namespace, so
&lt;strong&gt;this does not block or monitor egress&lt;/strong&gt; - a sandboxed agent can
still reach the network exactly like an unsandboxed one, same
provider creds and all. &lt;code&gt;~/.observer&lt;/code&gt; is bound read-write inside the
sandbox on purpose, so the proxy route, hooks, and token capture are
unaffected. Workspaces come from one of three host-side git
operations before the sandbox starts - &lt;code&gt;live&lt;/code&gt; (bind the real project
dir), &lt;code&gt;clone-local&lt;/code&gt; (&lt;code&gt;git clone --no-hardlinks&lt;/code&gt;, so the clone can
never hardlink objects back into the real repo), or &lt;code&gt;clone-remote&lt;/code&gt;
(host-side &lt;code&gt;git clone &amp;lt;url&amp;gt;&lt;/code&gt; using your ambient auth, gated by
&lt;code&gt;allow_remote_clone&lt;/code&gt;, off by default) - plus a fourth, &lt;code&gt;worktree&lt;/code&gt;,
that ships &lt;strong&gt;off by default&lt;/strong&gt; because it needs the main repo's &lt;code&gt;.git&lt;/code&gt;
bound read-write and a known pre-existing worktree-attribution bug
(&lt;code&gt;findGitRoot&lt;/code&gt;) has to be fixed first. Only &lt;code&gt;claude-code&lt;/code&gt; has a
grounded per-tool &lt;code&gt;SandboxSpec&lt;/code&gt; (its real state directories) in v1;
every other adapter is honestly reported as not sandbox-launchable
rather than guessed at. A sandboxed launch request that can't
actually be satisfied (disabled, backend missing/too old, userns
denied, tool unmapped, workspace prep failed) &lt;strong&gt;fails the launch
outright&lt;/strong&gt; - there is no silent unsandboxed fallback. New
&lt;code&gt;observer workspaces ls|rm &amp;lt;id&amp;gt;&lt;/code&gt; CLI to inspect/clean up the managed
workspace tree (no automatic retention sweep yet in v1). See
&lt;code&gt;docs/sandboxed-terminals.md&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Fixed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;fix(watcher): New Terminal install→launch capture for Muse/Prime (and peers).&lt;/strong&gt;
The watcher used to freeze its fsnotify root set at daemon start via
one-shot &lt;code&gt;Detected()&lt;/code&gt;, and entered permanent idle mode when no session
directories existed yet. Installing Muse/Prime (or any transcript-only
adapter) from the New Terminal dialog and launching immediately left
that session invisible until a daemon restart. &lt;code&gt;Watcher.RefreshRoots&lt;/code&gt;
now hot-adds newly-existing roots into the live watch set and Scans;
the dashboard kicks it (with a short retry schedule) after guided
install and after a successful launch; the poller's full-scan pass
also re-applies roots so CLI installs recover without a dashboard
kick. Empty &lt;code&gt;enabled_adapters = []&lt;/code&gt; still detects nothing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;fix(launchers): every &lt;code&gt;observer &amp;lt;tool&amp;gt;&lt;/code&gt; launcher now faithfully
passes arbitrary flags through to the wrapped CLI.&lt;/strong&gt; &lt;code&gt;observer claude --model sonnet&lt;/code&gt; previously died on a silently-swallowed
unknown-flag rejection (exit 1, no output); passthrough only worked
when a positional preceded the flag or after &lt;code&gt;--&lt;/code&gt;. All 24 launcher
verbs now parse their own wrapper-reserved flags manually
(&lt;code&gt;DisableFlagParsing&lt;/code&gt; + a shared parser) and forward every other
token verbatim, in order. Wrapper-owned flags (&lt;code&gt;--resume&lt;/code&gt;,
&lt;code&gt;--continue-from&lt;/code&gt;/&lt;code&gt;--carry&lt;/code&gt; and the handoff family,
&lt;code&gt;--attach&lt;/code&gt;/&lt;code&gt;--no-attach&lt;/code&gt;/&lt;code&gt;--no-proxy&lt;/code&gt;, &lt;code&gt;--verify&lt;/code&gt;, &lt;code&gt;--config&lt;/code&gt;,
&lt;code&gt;--proxy&lt;/code&gt;, &lt;code&gt;--&amp;lt;tool&amp;gt;-path&lt;/code&gt;, codex's process-control flags,
copilot-cli's &lt;code&gt;--model&lt;/code&gt;) keep their existing meaning and are never
forwarded; malformed wrapper-flag usage now errors loudly instead
of silently. Positional-first and &lt;code&gt;--&lt;/code&gt; invocations behave
byte-identically to before. Known trade-off: shell completion no
longer suggests wrapper flag names on these subcommands (a cobra
&lt;code&gt;DisableFlagParsing&lt;/code&gt; limitation).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v1.30.0 - 2026-08-08</title>
    <link href="https://superbased.app/docs/changelog#v1-30-0" rel="alternate"/>
    <id>https://superbased.app/docs/changelog#v1-30-0</id>
    <updated>2026-08-08T00:00:00Z</updated>
    <published>2026-08-08T00:00:00Z</published>
    <content type="html">&lt;h3&gt;Fixed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;fix(cursor): Cursor-on-Windows capture restored end to end.&lt;/strong&gt; The
hook bridge had been dead since 2026-07-05 behind stale tee-shim
entries; auto-register now self-heals that file shape (loud WARN +
remediation on failure, &lt;code&gt;last_result&lt;/code&gt;/&lt;code&gt;last_error&lt;/code&gt; persisted to
&lt;code&gt;hook_checksums.json&lt;/code&gt;), the watcher resolves project roots from
&lt;code&gt;.workspace-trusted&lt;/code&gt; with stat-gated candidate expansion, and hook
payloads carrying the IDE's &lt;code&gt;Uri.fsPath&lt;/code&gt; spelling (&lt;code&gt;/c:/…&lt;/code&gt;) now
land on the same canonical &lt;code&gt;/mnt/c/…&lt;/code&gt; root as the watcher's rows -
one project identity instead of up to six spellings of one
directory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(pathnorm): the &lt;code&gt;/c:/&lt;/code&gt; URI-fsPath drive spelling folds into the
Windows-drive layer.&lt;/strong&gt; Anchored lexical detection (never
&lt;code&gt;filepath.IsAbs&lt;/code&gt;, which is host-dependent); non-drive lookalikes
(&lt;code&gt;/cache/…&lt;/code&gt;, &lt;code&gt;/cc:/…&lt;/code&gt;, bare &lt;code&gt;/c:&lt;/code&gt;) are pinned untouched. Hook ==
watcher convergence is enforced by test.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Changed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tool count synced to 31 everywhere, from one generated manifest.&lt;/strong&gt;
&lt;code&gt;tools/toolcountgen&lt;/code&gt; derives the editorial adapter count from the
integration registry (fold rules explicit and tested); the website
hero badge, docs, READMEs, npm and VS Code Marketplace descriptions,
and the extension walkthrough all read 31 now, and the accuracy
checker fails on bare &amp;quot;N tools&amp;quot;/&amp;quot;N integrations&amp;quot; drift, on
registry↔prose disagreement, and on the distribution surfaces that
previously sat outside its scan root.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Version-scoped the stale &amp;quot;Cursor 3.4+ stopped writing transcripts&amp;quot;
claims.&lt;/strong&gt; True on 3.4.20-3.9.16 where it was measured; on 3.14.27
the transcript walker is live again and currently the sole
Windows-IDE capture path.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v1.29.0 - 2026-08-07</title>
    <link href="https://superbased.app/docs/changelog#v1-29-0" rel="alternate"/>
    <id>https://superbased.app/docs/changelog#v1-29-0</id>
    <updated>2026-08-07T00:00:00Z</updated>
    <published>2026-08-07T00:00:00Z</published>
    <content type="html">&lt;h3&gt;Added&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;feat(adapter): Meta Muse Code CLI - the 30th adapter.&lt;/strong&gt; Event-sourced
&lt;code&gt;session.jsonl&lt;/code&gt; parsing (envelope → payload_type → event.kind) with
microsecond &lt;code&gt;recorded_at&lt;/code&gt; timestamps. &lt;code&gt;model_completed.usage&lt;/code&gt; needs
DUAL netting - input including &lt;code&gt;cache_read&lt;/code&gt;, output including
reasoning - the OpenAI-Responses convention rather than Anthropic's;
a subagent run under &lt;code&gt;subagent/&amp;lt;child-uuid&amp;gt;/&lt;/code&gt; rolls up into its
parent session. &lt;code&gt;auth.json&lt;/code&gt;, &lt;code&gt;trust.json&lt;/code&gt;, and &lt;code&gt;tui-history.jsonl&lt;/code&gt;
are never read.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(adapter): Prime Agent - the 31st adapter.&lt;/strong&gt; Prime Intellect's
Prime Agent CLI is a hard fork of pi-mono with its own parser, not a
retag of the existing &lt;code&gt;pi&lt;/code&gt; adapter. Flat JSONL sessions under
&lt;code&gt;~/.prime/agent/sessions/&amp;lt;uuid&amp;gt;.jsonl&lt;/code&gt; form a tree via &lt;code&gt;parentId&lt;/code&gt;
(8-hex ids); the envelope timestamp is ISO-8601 while the inner
message timestamp is Unix milliseconds. Usage input arrives already
NET (&lt;code&gt;totalTokens == input+output+cacheRead+cacheWrite&lt;/code&gt; exactly) -
the opposite of most adapters' gross-then-netted convention, so this
one is a genuine exception, not a bug. &lt;code&gt;ipython&lt;/code&gt; is the sole
built-in tool: reads, edits, and shell commands all run through one
persistent Python kernel. A child agent run's usage folds into the
parent's token row via the same source-event id (ON CONFLICT
MAX-upgrade, never double-counted). &lt;code&gt;auth.json&lt;/code&gt;,
&lt;code&gt;daemon-workers/*.json&lt;/code&gt;, and the pickled &lt;code&gt;kernel-state.dill&lt;/code&gt; sidecar
are never read.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(cli): &lt;code&gt;observer muse&lt;/code&gt; and &lt;code&gt;observer prime-agent&lt;/code&gt; - launcher
verbs 22 → 24.&lt;/strong&gt; Muse launches non-proxied for now; an open
&lt;code&gt;--base-url&lt;/code&gt; question blocks proxy routing until it's answered.
Prime Agent launches proxied, through its own
&lt;code&gt;~/.prime/agent/models.json&lt;/code&gt; provider entry. Both ship with the same
grammar/resume-row/provider-merge conformance tests every other
launcher verb carries.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(dashboard): plain-shell &amp;quot;New terminal&amp;quot; launch, opt-in.&lt;/strong&gt; The
New Terminal dialog can now spawn a bare shell - the child's own
&lt;code&gt;$SHELL&lt;/code&gt;, or &lt;code&gt;/bin/bash&lt;/code&gt;/&lt;code&gt;/bin/sh&lt;/code&gt; as a fallback - instead of only a
known AI-tool launcher. Off by default and deliberately independent
of the existing fresh-agent toggle: &lt;code&gt;[terminal.launch].allow_shell&lt;/code&gt;
is its own opt-in, because a plain shell can run any command, a
strictly larger authority grant than a capability-registry-bounded
AI-tool launch. The dialog only offers the option when the daemon
reports it enabled, rather than showing it and failing at launch
time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(dashboard,obs): Policies module - admission and egress policy
authoring on the node dashboard.&lt;/strong&gt; What used to be config-file-only
setup is now a guided editor at &lt;code&gt;/policies&lt;/code&gt;: six tabs (Overview,
Templates, Guardrails, Routing, Test, Activity) covering an
11-entry template catalog across five groups (Scope, Safety, Cost,
Data locality, Bundles) for one-click guardrail criteria and egress
rules, plus live validate-and-apply and an activity feed. The UI
states its own honesty limit rather than hiding it: the dashboard
and the proxy each hold a SEPARATE &lt;code&gt;AdmissionService&lt;/code&gt; instance, so
&amp;quot;Apply live&amp;quot; only takes effect on the dashboard's own SDK front door
immediately - egress edits and proxy-side enforcement need Save plus
a daemon restart. Paired with a new &lt;code&gt;examples/copilot-harness&lt;/code&gt; demo
walking the whole Plane-A governance loop (admit → proxy → optional
OTLP trace) end to end.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(store,dashboard,cli): overall session rating (1-10).&lt;/strong&gt; A
fourth session-classification primitive alongside tags, favorite,
and note (migration 080): one reviewer score per session, landing
as a column on the existing &lt;code&gt;session_annotations&lt;/code&gt; row rather than a
new table. 0 is the &amp;quot;unrated&amp;quot; zero value everywhere, and an
annotation row is garbage-collected once favorite, note, and rating
are all back to their zero states - &amp;quot;no row&amp;quot; and &amp;quot;reviewed and
found unremarkable&amp;quot; stay indistinguishable, as intended. Node-local
like the rest of session classification: no wire surface, no
org-push column.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(cost,dashboard): dated pricing - recorded → dated → undated.&lt;/strong&gt;
A new per-model rate timeline lets a price change take effect
without silently repricing history: usage before a cut keeps the
old rate, usage after keeps the new one. First landed against a
real change - the OpenAI GPT-5.6 Terra/Luna price cut effective
2026-07-30 - then rolled out across the dashboard surfaces that had
been pricing every row at today's flat rate regardless of when it
ran: report, budget, statusline, live, and experiments, plus two
more found beyond the originally named list. Each now prefers a
turn's own recorded &lt;code&gt;cost_usd&lt;/code&gt; first, falls back to the rate that
was actually in force on that turn's own timestamp, and only falls
back further to the current flat rate when neither exists.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(website): &lt;code&gt;/pricing&lt;/code&gt;.&lt;/strong&gt; The site had no pricing link anywhere,
and a missing price label reads as a hidden price rather than a free
product. The page states what is true: the node &lt;strong&gt;and&lt;/strong&gt; the
self-hosted org server are both Apache-2.0 with no licence gate, so
Teams can be self-hosted free today; commercial support and a managed
option are in design and do not exist yet. No figures, because none
are shipped. Pricing takes the Arcade slot in the primary nav; Arcade
stays reachable from both footers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(website): homepage rebuilt around the install command.&lt;/strong&gt; Four
competing hero subheadlines collapse to one, and
&lt;code&gt;npx @superbased/observer&lt;/code&gt; becomes the primary copyable call to action
&lt;ul&gt;
&lt;li&gt;the site's own analytics already counted installing as the
conversion while the gold button pointed at the docs. &amp;quot;No account · No
signup · No telemetry&amp;quot; is promoted out of fine print. A new
measurement-honesty section surfaces the public retraction, which had
no link from any marketing page, alongside two entry points to the
eight comparison pages, previously unreachable from the marketing
site.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(website): FAQPage schema on the comparison pages.&lt;/strong&gt; The docs
renderer was already generic; emission was gated behind an allow-list
containing only the track section. Auditing Compare and flipping one
map entry adds 31 questions across 9 pages, taking site coverage from
30 pages / 151 questions to 39 / 182, with honesty parity holding by
construction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(website): RFC 9116 &lt;code&gt;security.txt&lt;/code&gt;.&lt;/strong&gt; The disclosure route
existed only as prose; researchers and enterprise scanners look for
&lt;code&gt;/.well-known/security.txt&lt;/code&gt; first, and its absence reads as no
process.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;test(website): licensing and release-date tripwires&lt;/strong&gt; in the
accuracy gate (9 → 11 check groups). The licensing check binds to
structural column identity - locate the header column named
SuperBased, inspect only its cells - rather than proximity to the
word, because comparison prose routinely names SuperBased and a
competitor in one sentence.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Fixed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;fix(integration,adapters): adapter-count surfaces move together,
30 → 31.&lt;/strong&gt; Landing Prime Agent meant every pinned adapter-count
surface had to move in the same pass - &lt;code&gt;observer adapters&lt;/code&gt;, doc
counts, and the generated website pages that state &amp;quot;N coding tools&amp;quot;
&lt;ul&gt;
&lt;li&gt;six drift gates re-verified in sync so the number can't drift out
from under the roster the way a stale &amp;quot;26 coding tools&amp;quot; once did
(see v1.28.0's tool-count drift fix).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(vscode): &lt;code&gt;observer.daemon.mode&lt;/code&gt; now defaults to &lt;code&gt;auto&lt;/code&gt;.&lt;/strong&gt; It
shipped as &lt;code&gt;detect&lt;/code&gt;, which never spawns the daemon, so a fresh install
showed an empty sidebar and a warning status bar until the user found
and changed a setting the README itself called &amp;quot;recommended for most
users&amp;quot; - the documentation and the default disagreed, and the default
won. &lt;code&gt;auto&lt;/code&gt; attaches to a daemon you already started and only spawns
when none is running, and only ever stops a daemon it spawned itself.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(website): three shipped claims that contradicted the site's own
honesty standard.&lt;/strong&gt; Literal &lt;code&gt;[REDACTED]&lt;/code&gt; placeholders in the live
&lt;code&gt;/enterprise&lt;/code&gt; SSO and enrolment copy; SuperBased's own Apache-2.0
licence described as &amp;quot;Source-available&amp;quot; across nine comparison pages,
next to competitors correctly labelled MIT; and npm/PyPI &lt;strong&gt;downloads&lt;/strong&gt;
presented as &amp;quot;total installs&amp;quot; beside a 35-star repo.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(website): the nav &amp;quot;Install free&amp;quot; button was unreadable.&lt;/strong&gt; It
rendered &lt;code&gt;--ink-dim&lt;/code&gt; cream on gold at 1.52:1, in both rest and hover,
on every home-layout page: the CTA sits inside &lt;code&gt;.nav__links&lt;/code&gt;, so that
rule's higher specificity beat &lt;code&gt;.nav__cta&lt;/code&gt; and the intended dark text
never applied. Now 9.14:1.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(website): WCAG AA contrast across both themes.&lt;/strong&gt; Eight measured
failures, worst 2.70:1, corrected by lightness and alpha only so hue
and brand identity are unchanged; verified live at 77 elements per
theme with zero failures.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(website): meta descriptions across 61 docs pages.&lt;/strong&gt; All were
past the point where search results truncate, and 16 generated ones
carried a literal ellipsis mid-sentence. Composition is now
budget-aware, spending what is left after the per-tool lead on the
longest call-to-action rung that fits, so the marketing tail degrades
and the differentiating fact survives. Median length 209 → 154, zero
ellipses, all unique.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(website): exactly one &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; per docs page.&lt;/strong&gt; 62 of 95 emitted
two - one from the front-matter title, one from the markdown body.
Fixed in the renderer rather than the sources, because the changelog
page is itself generated and would have been overwritten.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(website): sitemap freshness.&lt;/strong&gt; &lt;code&gt;lastmod&lt;/code&gt; was a hardcoded
constant reused for every URL and never updated, leaving &lt;code&gt;/docs&lt;/code&gt; a
month stale; it now derives per file from git history. &lt;code&gt;changefreq&lt;/code&gt;
was &amp;quot;weekly&amp;quot; on 94 of 104 URLs, contradicting its own stale
timestamps.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(website): missing &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt; landmark and focus ring&lt;/strong&gt; on the
home-layout pages, which had neither while every support page had
both.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v1.28.0 - 2026-08-01</title>
    <link href="https://superbased.app/docs/changelog#v1-28-0" rel="alternate"/>
    <id>https://superbased.app/docs/changelog#v1-28-0</id>
    <updated>2026-08-01T00:00:00Z</updated>
    <published>2026-08-01T00:00:00Z</published>
    <content type="html">&lt;h3&gt;Added&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(cli): &lt;code&gt;observer statusline&lt;/code&gt; - one-line, fail-open, wordmarked
cost status.&lt;/strong&gt; Prints a single line - the &lt;code&gt;▞ superbased&lt;/code&gt; wordmark plus
(when available) the current session's cost, today's total observed
spend, and the active model name - for Claude Code's &lt;code&gt;statusLine&lt;/code&gt;
contract or any host tool that execs a command and reads stdout.
Input precedence is piped stdin JSON, then &lt;code&gt;--session-cost&lt;/code&gt;/&lt;code&gt;--model&lt;/code&gt;/
&lt;code&gt;--cwd&lt;/code&gt; flags, then &lt;code&gt;OBSERVER_STATUSLINE_SESSION_COST&lt;/code&gt;/
&lt;code&gt;OBSERVER_STATUSLINE_MODEL&lt;/code&gt; env vars, then nothing - segments are
omitted, never rendered as a fabricated &lt;code&gt;$0.00&lt;/code&gt;. The &amp;quot;today&amp;quot; segment
comes from a new, lean &lt;code&gt;GET /api/statusline&lt;/code&gt; daemon endpoint over a
bounded, loopback-only HTTP call (&lt;code&gt;--timeout&lt;/code&gt;, default &lt;code&gt;80ms&lt;/code&gt;); when
no daemon is running, or it doesn't answer in time, that segment (and
only that segment) is silently omitted and the command still exits 0.
&lt;code&gt;--no-daemon&lt;/code&gt; skips the daemon attempt entirely; &lt;code&gt;--explain&lt;/code&gt; reports
which data path was used to stderr; &lt;code&gt;--json&lt;/code&gt; emits a machine-readable
line. All dollar figures are
estimated list-price totals, not invoiced amounts, stated once at
&lt;code&gt;--help&lt;/code&gt; and at registration time, never per-render. Registration is
opt-in via &lt;code&gt;observer init --statusline&lt;/code&gt; (writes Claude Code
&lt;code&gt;settings.json&lt;/code&gt;'s top-level &lt;code&gt;&amp;quot;statusLine&amp;quot;&lt;/code&gt; key) - never implied by
&lt;code&gt;--all&lt;/code&gt;, never auto-registered by &lt;code&gt;observer start&lt;/code&gt;; &lt;code&gt;--uninstall&lt;/code&gt;
removes the key entirely. A Claude Code install detected only on the
Windows side of a cross-OS WSL setup gets an honest WARN, not a
cross-OS bridge. The VS Code status bar's live-state text also picks
up the same &lt;code&gt;▞ superbased&lt;/code&gt; wordmark prefix
(&lt;code&gt;observer.statusBar.wordmark&lt;/code&gt;, default &lt;code&gt;true&lt;/code&gt;, to turn it off). The
daemon side adds migration 074 (&lt;code&gt;idx_token_usage_timestamp&lt;/code&gt;) so the
endpoint's &amp;quot;today&amp;quot; aggregate is an index scan, not a table scan. See
&lt;a href="docs/observer-statusline.md"&gt;&lt;code&gt;docs/observer-statusline.md&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(cli): &lt;code&gt;observer usage&lt;/code&gt; - zero-install one-shot cost report (the
&lt;code&gt;npx @superbased/observer&lt;/code&gt; activation path).&lt;/strong&gt; Scans every detected AI
coding tool's own local session files into a throwaway temp database,
prints one tool × model cost table, and deletes the database again.
Zero configuration, zero network calls: pricing is embedded in the
binary and the default path never reads &lt;code&gt;~/.observer/config.toml&lt;/code&gt; or
any &lt;code&gt;OBSERVER_*&lt;/code&gt; environment variable, never writes any AI tool's
config, and never binds a port. Flags: &lt;code&gt;--since&lt;/code&gt; (default &lt;code&gt;30d&lt;/code&gt;,
accepts &lt;code&gt;7d|30d|90d|all|RFC3339&lt;/code&gt;), &lt;code&gt;--days&lt;/code&gt;, &lt;code&gt;--group-by&lt;/code&gt;
(&lt;code&gt;tool-model|tool|model|day&lt;/code&gt;), &lt;code&gt;--tool&lt;/code&gt;, &lt;code&gt;--budget&lt;/code&gt; (default &lt;code&gt;30s&lt;/code&gt;,
&lt;code&gt;0&lt;/code&gt; = unlimited, prints an honest &lt;code&gt;partial:&lt;/code&gt; footer on expiry),
&lt;code&gt;--json&lt;/code&gt;, &lt;code&gt;--keep-db&lt;/code&gt;, &lt;code&gt;--config&lt;/code&gt; (opt back into a real config and its
pricing overrides), &lt;code&gt;--no-progress&lt;/code&gt;. Bare &lt;code&gt;observer&lt;/code&gt; now runs this same
report on a machine with no local SuperBased state at all (no
&lt;code&gt;~/.observer/observer.db&lt;/code&gt;, no &lt;code&gt;config.toml&lt;/code&gt;, no daemon listening) - a
state branch, never an invocation-channel branch - and prints the
usual welcome screen otherwise; &lt;code&gt;OBSERVER_ONESHOT=off&lt;/code&gt; always forces
the welcome screen. New pure package &lt;code&gt;internal/oneshot&lt;/code&gt;. See
&lt;a href="docs/one-shot-usage-report.md"&gt;&lt;code&gt;docs/one-shot-usage-report.md&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;docs: repo-landing hygiene fixes.&lt;/strong&gt; README gets a &amp;quot;Try it in one
command&amp;quot; block (the &lt;code&gt;npx&lt;/code&gt;/&lt;code&gt;observer usage&lt;/code&gt; activation path, immediately
above Install) and a plain, no-count &amp;quot;⭐ Star this repo&amp;quot; badge + CTA
line near the top. &lt;code&gt;scripts/release.sh&lt;/code&gt;'s public-mirror re-staging now
also carves out &lt;code&gt;docs/deployment-models.md&lt;/code&gt;, &lt;code&gt;docs/remote-access.md&lt;/code&gt;,
&lt;code&gt;docs/session-handoff.md&lt;/code&gt;, &lt;code&gt;docs/cache-tracking.md&lt;/code&gt;, and the
&lt;code&gt;docs/guard-{rules,policy-authoring,compliance}.md&lt;/code&gt; trio, fixing four
confirmed-live 404s on the public repo's README links (all three
re-staging sites - the force-add list, the &lt;code&gt;.gitignore&lt;/code&gt; negation
block, and the &lt;code&gt;docs_leaks&lt;/code&gt; sanity-check regex - kept in sync). Both
README hero infographics regenerated from new &lt;strong&gt;versioned HTML
sources&lt;/strong&gt; (&lt;code&gt;docs/assets/infographics/gen/&lt;/code&gt; + &lt;code&gt;render.mjs&lt;/code&gt; - the old
images were one-offs with no source in the repo): current single-word
lockup, correct counts (29 adapters / 25 MCP tools), and the
proxy-accuracy / cache-attribution / routing differentiators now in
the pixels. The stale &lt;code&gt;13-trajectories.png&lt;/code&gt; screenshot recaptured from
the web2 admin dashboard's Trajectory Explorer (the node dashboard no
longer hosts that page).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(mcp): droid + Command Code MCP registration.&lt;/strong&gt; &lt;code&gt;observer init&lt;/code&gt;
can now register the SuperBased MCP server into Factory Droid and
Command Code - one locate row + Installed probe + registry &lt;code&gt;MCPTarget&lt;/code&gt;
each, following the grounded droid pattern. Registry rows only; no
new switches (integration-registry discipline).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(store,dashboard,web,cli): session tags/favorites/notes.&lt;/strong&gt; New
migration 075 backs a &lt;code&gt;sessiontags&lt;/code&gt; store seam behind Execute-class
routes (mutations gated the same way as every other write path), plus
an &lt;code&gt;observer tag&lt;/code&gt;/&lt;code&gt;observer tags&lt;/code&gt; CLI with exact-first-then-index-range
prefix resolution. The dashboard gains &lt;code&gt;TagPill&lt;/code&gt;/&lt;code&gt;TagEditor&lt;/code&gt;,
star-favorite toggles, a note field, server-side tag+favorite filters,
and a tags rollup panel; the rollup query is chunked past SQLite's
32766 bind-variable ceiling (&lt;code&gt;cost.SessionRowsByID&lt;/code&gt;, capped at 900
session IDs per scope - the pre-fix symptom was cost columns silently
zeroing out, not an error). Remote devices are honestly read-only for
tag mutation: the only &lt;code&gt;Execute&lt;/code&gt;-class mint is terminal-scoped and
loopback, so a phone or tablet viewing the dashboard sees the
classification controls disabled with a stated reason rather than a
control that quietly fails. Mutations are validate-before-write atomic
and single-flight; a conflicting note edit surfaces a hint instead of
silently overwriting. Privacy pins cover the new columns end to end
(a canary tag proven never pushed under &lt;code&gt;admin_managed&lt;/code&gt;). See
&lt;a href="docs/dashboard-walkthrough.md"&gt;&lt;code&gt;docs/dashboard-walkthrough.md&lt;/code&gt;&lt;/a&gt;
(&amp;quot;Classifying sessions: tags, favorites, notes&amp;quot;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(announce,web,orgserver,orgclient,web2): dashboard
announcements, three rails.&lt;/strong&gt; New pure package &lt;code&gt;internal/announce&lt;/code&gt;
backs &lt;strong&gt;R1&lt;/strong&gt;, a &lt;code&gt;GET /api/announcements&lt;/code&gt; embedded rail with a
dismissible &lt;code&gt;AnnouncementBanner&lt;/code&gt; (ack tracked in &lt;code&gt;sb_announce_ack&lt;/code&gt;,
never re-shown once dismissed). &lt;strong&gt;R2&lt;/strong&gt; is a click-only npm-metadata
piggyback - the &lt;code&gt;superbased.announcement&lt;/code&gt; field an operator authors
into &lt;code&gt;npm/observer/package.json&lt;/code&gt; at publish time and the dashboard
reads passively; an always-on background poll was considered and
rejected for the zero-network posture &lt;code&gt;observer privacy&lt;/code&gt; states, and
the choice is written down on the measurement-honesty page. &lt;strong&gt;R3&lt;/strong&gt; is
a signed org-distribution rail on the routing-policy pattern: agent
migration 076 (a node-side cache) + server migration 022, a
&lt;code&gt;[dashboard].org_announcements&lt;/code&gt; gate (partial-merge default tested),
and a web2 composer as the first UI consumer of the sign-and-distribute
mechanism. See Fixed below for the security round that hardened R3
before it shipped, and
&lt;a href="docs/teams-operations.md"&gt;&lt;code&gt;docs/teams-operations.md&lt;/code&gt;&lt;/a&gt; §7 for the
publish/retract/trust-model/opt-out operator reference.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(tooltax,web): canonical cross-adapter tool taxonomy.&lt;/strong&gt; New pure
package &lt;code&gt;internal/tooltax&lt;/code&gt; (WP-T1) is a 1,074-row table across all 30
tool identities, with &lt;code&gt;MCPIdentity&lt;/code&gt; as the one owner of MCP-tool
naming - a corpus-measured slash-form convention was dropped on
zero corpus evidence rather than guessed at, closing a taint
false-positive class; &lt;code&gt;models.IsMCPToolName&lt;/code&gt; now delegates to it, and
the routing package's independent zero-imports pin correctly refuses
the same delegation, with equivalence proven from the tooltax side
instead. WP-T2 generates a TypeScript mirror (&lt;code&gt;actiontax.gen.json&lt;/code&gt; →
&lt;code&gt;actions.ts&lt;/code&gt; as a reader) so the dashboard's category/colour data
can't drift from the Go table, aligns the MCP-parser divergence to Go,
and adds a &lt;code&gt;taxonomy-build-drift&lt;/code&gt; CI job. A codex gate round then
closed the real hole the first pass left open: the Go-side test suite
stayed green while a hand-written TS reader could still silently
diverge, so the fix is a REAL-TS parity gate that esbuild-compiles the
actual &lt;code&gt;actions.ts&lt;/code&gt; against 28 Go-oracle vectors, a generated literal
category union that makes a missing &lt;code&gt;CATEGORY_COLOR&lt;/code&gt; a compile error
instead of a silent runtime fallback, and &lt;code&gt;C:/&lt;/code&gt;-drive plus
POSIX-colon path guards.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(mcp,cli,docs): published stable MCP local contract.&lt;/strong&gt;
&lt;a href="docs/mcp-contract.md"&gt;&lt;code&gt;docs/mcp-contract.md&lt;/code&gt;&lt;/a&gt; documents the full
25-tool tier table (18 stable, 4 conditional, 3 experimental) and
&lt;code&gt;observer contract --json&lt;/code&gt; emits it as machine-readable data, backed
by conformance tests that pin it against the real server; the README
gains an Integrations section pointing at it. A codex round then made
the published invariants actually true: a &lt;code&gt;days&lt;/code&gt;-parameter clamp
closes a gap between the documented and enforced range, every one of
the 25 tools' required parameters and all 18 stable tools' result keys
are wire-checked, and the markdown drift-gate test now parses BOTH the
doc and the generated mirror instead of one - the prior version could
pass while blind to a real divergence between them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(plugins): adapter distribution as installable plugins, Phase 1
in-repo - not yet published.&lt;/strong&gt; &lt;code&gt;plugins/plugingen&lt;/code&gt; satisfies the
one-owner registration rule by execution rather than duplication: it
runs the real &lt;code&gt;observer init&lt;/code&gt; registrars (&lt;code&gt;mcp.Registrar&lt;/code&gt;,
&lt;code&gt;hook.Registry&lt;/code&gt;) against a sandbox &lt;code&gt;$HOME&lt;/code&gt; and transposes their exact
output into &lt;code&gt;plugins/claude-code/&lt;/code&gt; (a marketplace root plus a plugin
directory - &lt;code&gt;plugin.json&lt;/code&gt;, &lt;code&gt;.mcp.json&lt;/code&gt;, &lt;code&gt;hooks.json&lt;/code&gt; with all 22
events) and &lt;code&gt;plugins/cursor/deeplink.txt&lt;/code&gt; (a static, exact-config
base64 deeplink, with its inherent one-click-install caveat stated
rather than hidden). A byte-for-byte &lt;code&gt;verify-plugins-build&lt;/code&gt; plus a
&lt;code&gt;plugins-build-drift&lt;/code&gt; CI job keep the generated trees honest, and
&lt;code&gt;sync-npm-version.sh&lt;/code&gt; now stamps both plugin manifests with the full
semver (an opaque version pin, not MV3's numeric-core trap). Nothing
is published: the &lt;code&gt;superbasedapp/observer-plugins&lt;/code&gt; repo, the Claude
Code marketplace listing, and the Cursor deeplink distribution all
stay operator-gated pending a decision on a known caveat - installing
the plugin alongside &lt;code&gt;observer init --claude-code&lt;/code&gt; double-registers
hooks, so both would fire on every event until that's deduped.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(orgserver,orgclient,web2): Teams member-invite loop,
default-off.&lt;/strong&gt; &lt;code&gt;[server].member_invites&lt;/code&gt; (default &lt;code&gt;false&lt;/code&gt;) lets an
active admin mint a capped, audited, time-boxed invite link - server
migration 023 backs the monthly cap and the &lt;code&gt;invite_minted&lt;/code&gt; audit
trail - with a web2 invite composer page and a node-dashboard nudge on
the &lt;code&gt;Execute&lt;/code&gt;-class surface. Conversion is reconstructed by joining
&lt;code&gt;minted_by&lt;/code&gt; against &lt;code&gt;used_at&lt;/code&gt;; nothing new goes on the agent wire. See
Fixed below for the security round that closed eight findings (seven
fixed, one documented) before this shipped.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(plugins): one-command install for 20 AI coding tools, published
as the public &lt;code&gt;superbasedapp/plugins&lt;/code&gt; repo.&lt;/strong&gt; Each supported tool can
now wire SuperBased up through its own native plugin or extension
mechanism instead of a hand-edited config file. The repo is &lt;em&gt;assembled&lt;/em&gt;
from this one, never hand-maintained: &lt;code&gt;scripts/assemble-plugins-repo.sh&lt;/code&gt;
runs the REAL &lt;code&gt;observer init&lt;/code&gt; registrars (&lt;code&gt;mcp.Registrar&lt;/code&gt; +
&lt;code&gt;hook.Registry&lt;/code&gt;) against a sandbox &lt;code&gt;HOME&lt;/code&gt; and transposes their exact
output, so a plugin manifest can never drift from what &lt;code&gt;init&lt;/code&gt; actually
writes. Coverage grew across three waves to a &lt;strong&gt;52-file&lt;/strong&gt; assembled
tree: six native manifests (kimi-code, qoder, devin, droid, openclaw,
antigravity - validated with each vendor's own validator where one
exists), six generated config listings (crush, kiro-cli, copilot-cli,
kilo-code, roo-code, open-interpreter), a Gemini CLI extension, a Goose
listing, a Codex plugin + marketplace, and a Copilot
&lt;code&gt;vscode:mcp/install&lt;/code&gt; deep link. &lt;code&gt;@superbased/opencode-plugin&lt;/code&gt; is
published to npm. Cowork's &lt;code&gt;.mcpb&lt;/code&gt; bundle is built but deliberately
&lt;strong&gt;not&lt;/strong&gt; claimed as supported until a live install verifies it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(tooltax): a canonical tool-name taxonomy shared by every
adapter.&lt;/strong&gt; A single 1,074-row table (30 tools) is now the one owner of
what each tool call &lt;em&gt;is&lt;/em&gt; - its canonical name, category, and surface -
replacing per-adapter string matching. Adapters read &lt;code&gt;tooltax.For&lt;/code&gt;;
migration 077 backfills historical rows whose &lt;code&gt;action_type&lt;/code&gt; was
&lt;code&gt;unknown&lt;/code&gt;; the dashboard gains a &lt;code&gt;/api/tools/breakdown&lt;/code&gt; endpoint with
real category and surface dimensions; and &lt;code&gt;observer adapters&lt;/code&gt; gains a
&lt;code&gt;VOCAB&lt;/code&gt; column reporting, per adapter, whether its vocabulary is
grounded or honestly unknown.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(db): test runs can no longer touch your real database.&lt;/strong&gt; &lt;code&gt;db.Open&lt;/code&gt;
now refuses any path inside the operator's actual &lt;code&gt;~/.observer&lt;/code&gt; when
running under &lt;code&gt;go test&lt;/code&gt;, returning &lt;code&gt;ErrRealDBInTest&lt;/code&gt; before &lt;code&gt;sql.Open&lt;/code&gt;.
This closes a real incident in which a working-tree test resolved
&lt;code&gt;config.Default()&lt;/code&gt;'s live path and ran a migration against the 16 GB
production store. The gate resolves symlinks across the full path and
checks hard links via &lt;code&gt;os.SameFile&lt;/code&gt;, guards both migration entry points
(including &lt;code&gt;internal/orgserver/db&lt;/code&gt;), and fails loudly rather than
skipping when the home directory can't be resolved.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(orgserver,web2): GitHub Copilot seat subscriptions are finally
priced.&lt;/strong&gt; The seats API returns COUNTS ONLY, so &lt;code&gt;/api/org/telemetry&lt;/code&gt;
reported &amp;quot;50 seats&amp;quot; and the metered overage while the subscription
those seats cost - normally the larger of Copilot's two cost feeds -
appeared nowhere. &lt;code&gt;[copilot_analytics].per_seat_price_usd&lt;/code&gt; existed and
defaulted to $19, but &lt;strong&gt;nothing read it&lt;/strong&gt;: an admin could set it and
change nothing. &lt;code&gt;SeatStats&lt;/code&gt; now carries &lt;code&gt;per_seat_price_usd&lt;/code&gt; and
&lt;code&gt;monthly_usd&lt;/code&gt; (&lt;code&gt;total × price&lt;/code&gt;), threaded from config through the
dashboard options, and the org dashboard renders a &amp;quot;Seat subscription&amp;quot;
tile plus a summary stat. Both are omitted entirely when the price is
unconfigured - absent means &amp;quot;price not supplied&amp;quot;, never &amp;quot;seats are
free&amp;quot;. &lt;strong&gt;The unit trap is preserved at every level:&lt;/strong&gt; &lt;code&gt;monthly_usd&lt;/code&gt; is
a point-in-time monthly fee and is never summed into &lt;code&gt;cost_usd&lt;/code&gt;
(additive per-day metered spend) - asserted in Go, on the wire, and in
every UI aggregate. A non-finite or negative price is now refused at
config validation: TOML accepts the literals &lt;code&gt;nan&lt;/code&gt; and &lt;code&gt;inf&lt;/code&gt; without
error, and &lt;code&gt;inf&lt;/code&gt; would otherwise reach &lt;code&gt;encoding/json&lt;/code&gt;, which refuses
it &lt;em&gt;after&lt;/em&gt; the 200 status is already sent.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(cockpit): burn rate on the session cost strip.&lt;/strong&gt; A running
total never answers &amp;quot;should I stop this?&amp;quot; - a rate does. The terminal
cockpit's cost strip gains $/h plus a +1h projection. The rate is
measured over the turns the cockpit already polls so it reflects
current spend rather than being diluted by earlier idle time; the
oldest fetched turn is the window boundary, so it sets the denominator
but is excluded from the numerator. Falls back to the session average
over the same elapsed the header shows, and returns nothing - never a
confident $0.00/h - when neither basis exists.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Fixed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;fix(codex): patch rows no longer land with an empty input.&lt;/strong&gt; Modern
Codex invokes &lt;code&gt;apply_patch&lt;/code&gt; from inside an &lt;code&gt;exec&lt;/code&gt; custom_tool_call and
the executor stamps &lt;code&gt;patch_apply_end&lt;/code&gt; with its own &lt;code&gt;exec-&amp;lt;uuid&amp;gt;&lt;/code&gt; id,
while the response_item carries &lt;code&gt;call_&amp;lt;hash&amp;gt;&lt;/code&gt;. Different namespaces, so
the join could never match on current builds and every patch row took
the standalone path with no &lt;code&gt;raw_tool_input&lt;/code&gt;. Measured over a
393-rollout corpus: 2,059 exec-uuid vs 416 call_hash. There is no join
to repair, so the standalone path now reconstructs the input from the
producer's own &lt;code&gt;changes&lt;/code&gt; object, with the rendering owned in one place
so a live-captured row and a &lt;code&gt;backfill --codex-tool-input&lt;/code&gt; recovery are
byte-identical. On one live update-heavy session this took empty inputs
from 95 to 0.&lt;/p&gt;
&lt;p&gt;Authored-byte accounting was deliberately left alone after measurement
proved the obvious &amp;quot;fix&amp;quot; wrong: an &lt;code&gt;update&lt;/code&gt; change carries only
&lt;code&gt;unified_diff&lt;/code&gt; and scores zero here, which &lt;em&gt;looks&lt;/em&gt; like a bug, but every
patch also emits an invocation row that already counts the same bytes
from its own patch text (107 invocation rows / 142,823 B alongside 95
executor rows). Counting the diff as well double-counts every update.
The reasoning is now written into the code so the zero is not &amp;quot;fixed&amp;quot;
again.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;fix(dashboard): Compression tiles show an em dash, not a confident
zero.&lt;/strong&gt; &lt;code&gt;deriveTotals()&lt;/code&gt; returned an all-zero object whenever the
timeseries query had no data, so five tiles rendered &amp;quot;$0.00 saved
across 0 compression events&amp;quot; from the moment the page mounted - and
because the loading flag also clears on error, a failed query settled
that zero in as a confident, wrong answer. The no-data branch now
yields undefined, which the existing null-safe formatters render as an
em dash: loading keeps the pulse, an error settles to a static dash.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;test(terminal): one flaked assertion can no longer kill an entire
package.&lt;/strong&gt; A cache-cleared &lt;code&gt;-race&lt;/code&gt; sweep reported &lt;code&gt;FAIL cmd/observer 2400s&lt;/code&gt; - the full 40-minute timeout. The cause was not slowness:
&lt;code&gt;TestTerminalPidSeederEndToEnd&lt;/code&gt; failed an assertion and then deadlocked
in cleanup, because the PTY stub's &lt;code&gt;Kill&lt;/code&gt;/&lt;code&gt;Close&lt;/code&gt; were no-ops that never
unblocked the parked reader, so &lt;code&gt;Manager.Shutdown&lt;/code&gt;'s unbounded
&lt;code&gt;wg.Wait()&lt;/code&gt; never returned. Being a serial test, it left ~340 parallel
tests in the same package waiting and never run - the package reported
FAIL having executed almost none of itself. The prior &amp;quot;green&amp;quot; sweep
could not have caught this: &lt;code&gt;cmd/observer&lt;/code&gt; was one of the 193/195
cached packages. With the stub honouring &lt;code&gt;Close&lt;/code&gt;, the same failure now
takes 6.9s instead of 40 minutes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;fix(dashboard): cache-savings counterfactual no longer zeroed for
proxy-recorded turns.&lt;/strong&gt; Rows with a recorded cache read &amp;gt; 0
contributed $0 to the &amp;quot;saved by caching&amp;quot; counterfactual, understating
cache savings roughly 3× on real corpora. Found by the Show HN corpus
mining pass; the memo's savings claims are gated on this fix.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;fix(store): outcome-update seam hardened.&lt;/strong&gt; Cross-tick
&lt;code&gt;tool_results&lt;/code&gt; outcome flips now persist action outcomes through ONE
store-owned seam instead of per-adapter writes, closed across two
adversarial review rounds (evidence-gated 1→0 self-heal included).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;fix(hook,init): settings.json writer classes hardened (9 call
sites).&lt;/strong&gt; Two pre-existing defect classes shared by the hooks/cursor/
statusline registrars: the &lt;code&gt;any&lt;/code&gt;-decode re-indent path could mangle
big integers (float64), reformat numbers, HTML-escape strings, panic
on JSON null, and silently collapse duplicate keys - now re-indents
RAW bytes; and the read-modify-write used a fixed temp name with no
lock - now unique temps + a cross-process advisory lock +
re-read-after-lock. Plus: loose ownership matching tightened, symlink
clobbering refused, a 5 MiB size cap, PID-reuse liveness via
&lt;code&gt;/proc&lt;/code&gt; cmdline, and oversize-stdin handling on the statusline path.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;fix(hook): registrar write-path hardening, second pass.&lt;/strong&gt; The
deferred WP9 ledger: &lt;code&gt;hook_checksums.json&lt;/code&gt; writes now take the
cross-process advisory lock and rename a unique temp file (was an
unlocked plain write); the codex &lt;code&gt;hooks.json&lt;/code&gt;/&lt;code&gt;config.toml&lt;/code&gt; writers
drop their fixed &lt;code&gt;.tmp&lt;/code&gt; names for unique-temp atomic writes under
per-path locks with re-read-after-lock; and the unregister path
refuses to delete a symlinked config file instead of silently
unlinking the link while the target keeps stale hooks. Each pinned
by a concurrent-writer or symlink regression test.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;fix(adapter): foreign-mount SQLite mirror staging unified under
&lt;code&gt;internal/adapter/mirrorbase&lt;/code&gt;.&lt;/strong&gt; Seven adapters staged cross-mount DB
mirrors into persistent &lt;code&gt;~/.cache&lt;/code&gt; during parsing through copied
helper code; the new single-owner seam scopes them, and
&lt;code&gt;observer usage&lt;/code&gt; redirects mirrors into its throwaway scratch
directory (live-verified: a one-shot run adds zero cache entries).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;fix(integration): npm Binary-row honesty.&lt;/strong&gt; Dropped impossible
&lt;code&gt;.exe&lt;/code&gt; spellings from 10 npm-distributed CLI tools' Windows binary
rows - npm shims install &lt;code&gt;.cmd&lt;/code&gt;/&lt;code&gt;.ps1&lt;/code&gt; wrappers, never raw &lt;code&gt;.exe&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(web): share surfaces + camera-ready wordmark + once-only star
prompt.&lt;/strong&gt; CommunityCard can share a real personal stat the user opts
into (&amp;quot;$X tracked across N tools this month - superbased.app&amp;quot;), with
the exact text previewed before sharing and a static-link fallback
(never &amp;quot;$0.00 tracked&amp;quot;). MilestonesCard brag moments gain share/copy
actions. The four hero stat surfaces (Cost, Suggestions, Milestones,
Report) carry a muted in-frame &lt;code&gt;▞ superbased&lt;/code&gt; wordmark so a native
screenshot travels with attribution - no export pipeline. A
lazygit-pattern once-only GitHub star prompt appears after a week of
real usage (never in demo mode, never twice). A new open-ended
Feedback issue form joins the GitHub templates.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(cli): &lt;code&gt;observer privacy&lt;/code&gt; - verifiable zero-network posture.&lt;/strong&gt;
Prints an honest, config-derived egress report: every listening
socket (loopback-only except the opt-in tailnet remote-access
listener) and every outbound path the binary can take, each with its
gate and this config's actual on/off state; &lt;code&gt;--json&lt;/code&gt; for scripting.
Paired with two changes that make the claim exact: the dashboard's
npm-registry update check is now &lt;strong&gt;user-initiated only&lt;/strong&gt; (a &amp;quot;Check
for updates&amp;quot; card in Settings → Health; no fetch on tab load, no
background timer), and a new website page,
&lt;code&gt;/docs/reference/measurement-honesty&lt;/code&gt;, states the
compression-savings retraction plainly and documents the provable
accuracy claims that replace it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;feat(website): three new competitor comparison pages&lt;/strong&gt; (CodeBurn,
Claude Code Usage Monitor, TokenTracker), authored from a dated
2026-07-30 re-verification of every competitor claim, with steelman
sections and the competitors' newest features stated fairly. New
&lt;code&gt;make track-build&lt;/code&gt; / &lt;code&gt;verify-track-build&lt;/code&gt; + a CI drift gate; fixed a
track-gen idempotency bug (marker blocks re-appended at EOF instead
of spliced in place, which could permanently redden a byte-for-byte
drift gate).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;fix(website): tool-count drift sweep.&lt;/strong&gt; Live compare pages said &amp;quot;26
coding tools&amp;quot; against 29 shipped adapters; the four compare pages are
corrected and &lt;code&gt;track-gen&lt;/code&gt; now derives counts from &lt;code&gt;len(roster)&lt;/code&gt; so the
class can't recur (new accuracy-check Check B2 guards it).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;fix(orgserver,orgclient,store): org-announcements rail hardened
before release (adversarial review, six findings, all fixed).&lt;/strong&gt; The
rail was built by cloning the routing-policy distribution rail, and
cloning a mechanism cloned its weaknesses into a context that couldn't
tolerate them. Three HIGHs, all fixable because the rail was still
unreleased: the signature covered the body only - no version, no rail
identity - so a captured signed document replayed at a bumped version
froze a node's cache via its own monotonic short-circuit, an old
retraction replayed cleared every banner, and because the org server
has one shared signing identity, a genuinely-signed routing-policy
document verified as a valid announcement. Fixed with
&lt;code&gt;orgcontract.AnnouncementSigningMessage&lt;/code&gt; (a domain tag, the version,
and the body, hashed together) - the routing rail keeps its released
wire shape as-is, and the residual is now tracked as ledger row
&lt;strong&gt;ROUTING-SIG-1&lt;/strong&gt; (&lt;code&gt;docs/security.md&lt;/code&gt;) instead of silently inherited.
Announcement TOFU also consulted only its own rail's pin, so a node
enrolled for months would accept any key on its first announcement
fetch - closed in &lt;code&gt;internal/orgclient/orgpin.go&lt;/code&gt;, one org identity now
enforced across both rails. And unenrolment left a departed org's
cached banner (and its pinned key) live, risking poisoning
re-enrolment into a different org - &lt;code&gt;store.DeleteEnrolment&lt;/code&gt; now clears
both distribution caches. Three smaller fixes: the per-cycle poll is
now stated in &lt;code&gt;observer privacy&lt;/code&gt; instead of left implicit; both
endpoints' 1 MiB caps applied to the read only and ignored trailing
bytes, now &lt;code&gt;orgcontract.DecodeCapped&lt;/code&gt;; and &lt;code&gt;&amp;quot;[]&amp;quot;&lt;/code&gt;/&lt;code&gt;&amp;quot;null&amp;quot;&lt;/code&gt; were a third
and fourth silent spelling of a retraction, now one representation.
Every fix carries a regression test proven to fail pre-fix by inline
mutation against a document the org genuinely signed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;fix(orgserver): member-invite loop hardened before release
(adversarial review, eight findings, seven fixed, one documented).&lt;/strong&gt;
Two HIGHs: the monthly mint cap was read-then-insert across two
connections with tens of milliseconds of argon2id hashing between
them, so concurrent mints could all read the same pre-mint count and
all land past the cap - now one &lt;code&gt;BEGIN IMMEDIATE&lt;/code&gt; transaction,
mutation-proved by an 8-goroutine hammer test; and a SCIM-deactivated
admin with a still-live SAML cookie kept minting uncapped because the
admin branch returned before any liveness check - fixed both at the
invite gate and, more broadly, at &lt;code&gt;adminCheckerFor&lt;/code&gt; (&lt;code&gt;AND active = 1&lt;/code&gt;),
restoring deactivation as an authority revocation across every
&lt;code&gt;RequireAdminSAML&lt;/code&gt; route. Three MEDs: &lt;code&gt;ttl_days&lt;/code&gt; was unbounded (a
273-year token was mintable) and is now clamped 1-90 with explicit-zero
rejected rather than treated as &amp;quot;omitted&amp;quot;; the invite-lookup
404-vs-201 response was a membership oracle, now rate-limited to 20
failed lookups/hour per inviter (server migration 024, storing only
the inviter id and timestamp - never the probed address); and the
enrol link is now copy-only text rather than a clickable URL (the SPA
has no &lt;code&gt;/enrol/:token&lt;/code&gt; route, so navigability bought nothing and only
cost exposure to link-unfurlers and mail scanners). One MED + one LOW:
inviter attribution now survives SCIM deletion via a &lt;code&gt;minted_by&lt;/code&gt;
fallback, and the invite audit's &lt;code&gt;source_ip&lt;/code&gt; no longer trusts
&lt;code&gt;X-Forwarded-For&lt;/code&gt; (new ledger row &lt;strong&gt;XFF-1&lt;/strong&gt; for two pre-existing,
deliberately-deferred XFF-trusting audit sites elsewhere in the org
server). One LOW documented rather than fixed: target-deletion CASCADE
frees a cap slot early, recorded in &lt;code&gt;docs/teams-operations.md&lt;/code&gt; §8.2 as
needing member-lifecycle authority that already outranks the cap.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;fix(adapters): model reasoning no longer files itself as a completed
task.&lt;/strong&gt; Fifteen adapters minted a separate action row - typed
&lt;code&gt;task_complete&lt;/code&gt; - every time the model produced a reasoning block,
inventing 15,734 phantom &amp;quot;task completions&amp;quot; in a live corpus for work
the model never did. Reasoning is not an action; it is something the
model did on the way to one. Every adapter now carries it as
&lt;code&gt;preceding_reasoning&lt;/code&gt; on the &lt;em&gt;successor&lt;/em&gt; event and mints no row at all.
Threading is consumed-once, last-wins, discarded at a turn boundary,
and never crosses a session id. Opaque or encrypted reasoning
placeholders are never threaded anywhere. Affected: crush, hermes,
cline-cli, antigravity, cursor, opencode, kilo-code-cli, codex,
open-interpreter, openclaw, cline, cowork, pi, copilot, copilot-cli,
gemini.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;fix(dashboard): &lt;code&gt;/api/status&lt;/code&gt; no longer saturates the daemon.&lt;/strong&gt;
&lt;code&gt;diag.Snapshot&lt;/code&gt; costs several seconds of &lt;code&gt;COUNT(*)&lt;/code&gt;s on a large
database, and two always-mounted chrome components polled it every 5
seconds - so a scan was permanently in flight and starved every other
query (measured first-load latencies reached 36 s). The snapshot is now
computed behind a 15-second TTL + singleflight cache. Crucially the
scan runs &lt;strong&gt;detached&lt;/strong&gt; from the caller's request context: the previous
fix was incomplete because the client aborts its prior fetch each tick,
cancelling whichever poller held the gate and serialising the scans
anyway. Degraded snapshots now carry a &lt;code&gt;QueryErrors&lt;/code&gt; count and are
returned but never cached.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;fix(cursor): the reasoning stash is now safe across hook processes.&lt;/strong&gt;
Cursor is a hook adapter - one process per event - so its pending
reasoning needs an on-disk carrier. The first implementation raced:
under contention, 190 of 200 iterations double-threaded a thought and 8
of 200 reads saw a truncated file. It is now an atomic rename-claim
protocol - writes land at a unique temporary name and rename over the
target, and consumers claim by renaming the target to a nonce first, so
exactly one participant can win a name. Proven under &lt;code&gt;-race&lt;/code&gt; with
multiple concurrent participants.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;fix(gemini): a failed call no longer records itself as a success.&lt;/strong&gt; A
legacy-shaped failed call persisted &lt;code&gt;success=1&lt;/code&gt; forever. The verdict is
now taken from the response body - but only for &lt;em&gt;meaningful&lt;/em&gt; errors
(non-blank strings, non-empty objects or arrays). &lt;code&gt;{&amp;quot;error&amp;quot;: false}&lt;/code&gt;,
&lt;code&gt;0&lt;/code&gt;, &lt;code&gt;[]&lt;/code&gt;, &lt;code&gt;{}&lt;/code&gt;, and bare booleans or numbers never invent a failure.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;fix(plugins): two wrong-plugin-resolution hazards caught before
publication.&lt;/strong&gt; Both were reproduced live, not theorised. Factory's
&lt;code&gt;droid&lt;/code&gt; resolved &lt;code&gt;./superbased&lt;/code&gt; at the repo root to the &lt;em&gt;Claude Code&lt;/em&gt;
plugin directory - hooks and all - so the plugin was relocated to
&lt;code&gt;factory/superbased&lt;/code&gt;. &lt;code&gt;qodercli plugins marketplace add&lt;/code&gt; likewise
installed the Claude plugin via its binary's literal search order;
closed with a root &lt;code&gt;.qoder-plugin/marketplace.json&lt;/code&gt; whose schema was
extracted from the shipped binary, then verified end to end.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Changed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Migration 079 deletes ~15,050 content-free reasoning rows on first
run, and your action counts will drop.&lt;/strong&gt; This is the historical half of
the reasoning fix above: the &lt;code&gt;(reasoning)&lt;/code&gt; and &lt;code&gt;(encrypted reasoning, N bytes)&lt;/code&gt; placeholder rows written by the retired emit sites, plus their
FTS search excerpts, are removed, and 7 stale cursor rows are rewritten.
Those rows have no content, never had content, and were never threaded
anywhere - deleting them removes rows, not information. &lt;strong&gt;Aggregate
action counts on the dashboard will fall accordingly; this is the
intended correction, not data loss.&lt;/strong&gt; Everything content-bearing is
kept, including the 329 codex reasoning rows carrying real summary text
and all 15 gemini reasoning rows (deleting those was measured to be
lossy). An id high-water marker is recorded in &lt;code&gt;schema_meta&lt;/code&gt; before the
deletes so the result can be re-verified afterwards. Schema golden
moves 78 → 79.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scripts/sync-npm-version.sh&lt;/code&gt; now stamps &lt;strong&gt;11&lt;/strong&gt; plugin-side manifests
in addition to the npm and VS Code packages, with a set-equality test
in both directions so a new manifest cannot be silently missed.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v1.27.0 - 2026-07-29</title>
    <link href="https://superbased.app/docs/changelog#v1-27-0" rel="alternate"/>
    <id>https://superbased.app/docs/changelog#v1-27-0</id>
    <updated>2026-07-29T00:00:00Z</updated>
    <published>2026-07-29T00:00:00Z</published>
    <content type="html">&lt;h3&gt;Added&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;feat(adapter): three new adapters - Factory &lt;code&gt;droid&lt;/code&gt;, Open Interpreter
and Command Code (26 → 29).&lt;/strong&gt; All three were Phase-0 grounded against
live installs on WSL &lt;em&gt;and&lt;/em&gt; Windows before any parser was written, then
put through one adversarial review over the combined diff (four
confirmed findings, each fixed with a revert-proof regression test -
see Fixed below). All three are &lt;strong&gt;Tier-2 log capture&lt;/strong&gt;: none has a
verified proxy lane and none exposes a hook mechanism, so every token
figure they produce is the tool's own reported number read out of its
local transcript, never a proxy-exact one.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;droid&lt;/code&gt;&lt;/strong&gt; (&lt;code&gt;internal/adapter/droid/&lt;/code&gt;, &lt;code&gt;models.ToolDroid&lt;/code&gt;) is
Factory AI's terminal agent - the company is Factory AI, the product
is droid, and Observer names adapters after the product. Two flat
files per session and no SQLite anywhere: the JSONL transcript at
&lt;code&gt;~/.factory/sessions/&amp;lt;dashed-cwd&amp;gt;/&amp;lt;uuid&amp;gt;.jsonl&lt;/code&gt; plus a
&lt;code&gt;&amp;lt;uuid&amp;gt;.settings.json&lt;/code&gt; sidecar. There is &lt;strong&gt;no per-message usage
envelope anywhere in the corpus&lt;/strong&gt; (&lt;code&gt;&amp;quot;usage&amp;quot;&lt;/code&gt; occurs zero times across
the nine captured sessions), so tokens are SESSION-level cumulative
only - the goose precedent. Only the self-only &lt;code&gt;tokenUsage&lt;/code&gt; block is
emitted, under the stable id &lt;code&gt;tokens:&amp;lt;session-id&amp;gt;&lt;/code&gt;, so a later parse
of a grown sidecar rewrites the same &lt;code&gt;(source_file, source_event_id)&lt;/code&gt;
row and the store's &lt;code&gt;ON CONFLICT … MAX(…)&lt;/code&gt; upgrade keeps the counts
monotonically non-decreasing; &lt;code&gt;inclusiveTokenUsage&lt;/code&gt; and
&lt;code&gt;lastCallTokenUsage&lt;/code&gt; are deliberately NOT emitted (both would
double-count - mission child sessions get their own transcript and
sidecar), and &lt;code&gt;factoryCredits&lt;/code&gt; has no &lt;code&gt;TokenBundle&lt;/code&gt; counterpart at
all. Tier &lt;code&gt;source='jsonl'&lt;/code&gt;, &lt;code&gt;reliability='approximate'&lt;/code&gt;. Project root
comes from the inline &lt;code&gt;session_start.cwd&lt;/code&gt;; &lt;code&gt;compaction_state&lt;/code&gt; maps to
&lt;code&gt;ActionContextCompacted&lt;/code&gt; with its git-output snapshots dropped. The
adapter never reads the &lt;code&gt;~/.factory&lt;/code&gt; root - &lt;code&gt;auth.v2.*&lt;/code&gt; and the
top-level &lt;code&gt;settings.json&lt;/code&gt; carry plaintext BYOK keys - and sidecar
reads refuse symlinks (a new house idiom).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Open Interpreter&lt;/strong&gt; is deliberately &lt;strong&gt;not a new package.&lt;/strong&gt; The
&lt;code&gt;interpreter&lt;/code&gt; binary is the OpenAI Codex CLI Rust codebase recompiled
under another product name, and the evidence is not circumstantial:
every subcommand's &lt;code&gt;--help&lt;/code&gt; is titled &amp;quot;Codex&amp;quot;, the Rust module
namespace is &lt;code&gt;codex_*&lt;/code&gt;, the session file's &lt;code&gt;base_instructions&lt;/code&gt; say
&amp;quot;You are Codex&amp;quot;, &lt;code&gt;CODEX_HOME&lt;/code&gt; is renamed to &lt;code&gt;INTERPRETER_HOME&lt;/code&gt;, and
every &lt;code&gt;token_count&lt;/code&gt; event's &lt;code&gt;rate_limits.limit_id&lt;/code&gt; is still the
literal string &lt;code&gt;&amp;quot;codex&amp;quot;&lt;/code&gt;. So &lt;code&gt;codex.NewOpenInterpreter()&lt;/code&gt; retags the
existing codex parser at the §2.1 boundary seam (CLAUDE.md rule 3 -
branch on capability, not source identity) with watch root
&lt;code&gt;~/.openinterpreter/sessions&lt;/code&gt;; because the on-disk shape is
&lt;em&gt;identical&lt;/em&gt; to codex's, root-based watcher dispatch is the only thing
keeping the two apart. Tier 2 JSONL &lt;code&gt;token_count&lt;/code&gt;, with gross input
netted against &lt;code&gt;cached_input_tokens&lt;/code&gt; exactly as codex's own path does.
Its four SQLite stores are index/debug only and are not read.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Command Code&lt;/strong&gt; (&lt;code&gt;internal/adapter/commandcode/&lt;/code&gt;,
&lt;code&gt;models.ToolCommandCode&lt;/code&gt;) is the closed-source &lt;code&gt;command-code&lt;/code&gt; npm CLI
(v1.4.5 at capture) - one binary behind four bin aliases (&lt;code&gt;cmd&lt;/code&gt;,
&lt;code&gt;cmdc&lt;/code&gt;, &lt;code&gt;command-code&lt;/code&gt;, &lt;code&gt;commandcode&lt;/code&gt;), not a two-product split.
Claude-Code-shaped JSONL under &lt;code&gt;~/.commandcode/projects/&lt;/code&gt;, with
per-assistant-message usage inline. &lt;strong&gt;&lt;code&gt;inputTokens&lt;/code&gt; is GROSS&lt;/strong&gt; - it
includes &lt;code&gt;cacheReadTokens&lt;/code&gt; - so the adapter emits the netted figure,
clamped at zero (mutation-proved), and carries the cached count
separately. The provider's own &lt;code&gt;costUsd&lt;/code&gt; is carried through as an
estimated cost (the opencode / pi precedent) because Command Code
resells ~48 mostly open-weight models through its own gateway, for
which Observer has no pricing rows. &lt;code&gt;.checkpoints.jsonl&lt;/code&gt;, meta,
config and history files are excluded by &lt;code&gt;IsSessionFile&lt;/code&gt;, and
&lt;code&gt;auth.json&lt;/code&gt; is never read.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Registration.&lt;/strong&gt; &lt;code&gt;enabled_adapters&lt;/code&gt; goes 26 → 29, with one
&lt;code&gt;internal/integration&lt;/code&gt; capability row each (droid and open-interpreter
&lt;code&gt;probe_required&lt;/code&gt;; command-code &lt;code&gt;after_bridge&lt;/code&gt; - its API-URL knob
points at its own closed gateway, not an Anthropic/OpenAI-shaped
endpoint), guard conformance rows, cross-OS process-attribution
basenames (the &lt;code&gt;cmd&lt;/code&gt; / &lt;code&gt;cmdc&lt;/code&gt; aliases are deliberately excluded - they
collide with &lt;code&gt;cmd.exe&lt;/code&gt;), &lt;code&gt;defaults.Adapters()&lt;/code&gt;, and dashboard tool
label + colour rows (CIE76-checked). &lt;code&gt;RegistryVersion&lt;/code&gt; stays at 1 by
the browserchat precedent: a bump revokes aggregate consent receipts,
and adding tools is not a consent-shape change. As with every new
adapter, a daemon built before this release has no compiled-in support
&lt;ul&gt;
&lt;li&gt;rebuild and restart before expecting rows.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(launch): full terminal parity for the wave - 19 → 22 launchers.&lt;/strong&gt;
&lt;code&gt;observer droid&lt;/code&gt;, &lt;code&gt;observer open-interpreter&lt;/code&gt; (alias &lt;code&gt;interpreter&lt;/code&gt;) and
&lt;code&gt;observer command-code&lt;/code&gt; (alias &lt;code&gt;commandcode&lt;/code&gt;) each open a real PTY from
the dashboard or a shell. Every seed and resume contract was read out of
the tool's own &lt;code&gt;--help&lt;/code&gt; on 2026-07-29 rather than inferred: droid takes
the distilled handover as a &lt;strong&gt;trailing positional&lt;/strong&gt; and resumes with a
JOINED &lt;code&gt;--resume=&amp;lt;uuid&amp;gt;&lt;/code&gt; (its flag declares an optional value, so a
space-separated form would swallow the next argument); Open Interpreter
resumes through the &lt;code&gt;resume &amp;lt;uuid&amp;gt;&lt;/code&gt; &lt;strong&gt;subcommand&lt;/strong&gt;, codex's shape, which
landed as a new positional &lt;code&gt;resumeTranslation&lt;/code&gt; shape expressed as DATA
rather than a new code path; Command Code resumes with &lt;code&gt;--session &amp;lt;id&amp;gt;&lt;/code&gt;,
chosen over its optional-value, name-resolving &lt;code&gt;-r&lt;/code&gt;. All three launch
&lt;strong&gt;non-proxied&lt;/strong&gt; on purpose - no proxy lane has been probed for any of
them, and &lt;code&gt;observer open-interpreter&lt;/code&gt; deliberately does not copy
&lt;code&gt;observer codex&lt;/code&gt;'s &lt;code&gt;openai_base_url&lt;/code&gt; injection. Attach, attach-by-default,
Jump-in and the Session Cockpit come for free, because those dispatch on
the launcher capability rather than the tool name (new-adapter checklist
§3.6a). Totals after the pass, read out of the registry: &lt;strong&gt;22 launcher
verbs&lt;/strong&gt; (20 seeded + 2 doc-assisted), &lt;strong&gt;22 attachable&lt;/strong&gt;, &lt;strong&gt;21 of 22 with
native resume&lt;/strong&gt; - openclaw is the sole holdout, picker-only - &lt;strong&gt;22
&lt;code&gt;Binary&lt;/code&gt; rows&lt;/strong&gt;, and &lt;strong&gt;21 with at least one grounded install hint&lt;/strong&gt;
(&lt;code&gt;kimi-code&lt;/code&gt; is the sole gap, no official channel grounded). Factory's
Windows &lt;code&gt;irm&lt;/code&gt; one-liner is deliberately NOT offered as an install hint:
it is undocumented upstream.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;docs: the adapter-coverage parity matrix is re-derived from code.&lt;/strong&gt;
&lt;code&gt;docs/plans/adapter-coverage-parity-plan-2026-06-26.md&lt;/code&gt; §15 is now a
34-row matrix - every cell read out of the &lt;code&gt;internal/integration&lt;/code&gt;
registry and the launcher wiring on 2026-07-29 and cross-checked against
&lt;code&gt;observer adapters&lt;/code&gt;, with &lt;code&gt;-&lt;/code&gt; meaning the registry's honest zero (&amp;quot;no
grounded capability&amp;quot;), never &amp;quot;probably&amp;quot;. It also writes down the four
adapter numbers that are routinely confused and are not a discrepancy:
&lt;strong&gt;29&lt;/strong&gt; CLI/IDE/desktop adapters, &lt;strong&gt;34&lt;/strong&gt; registry rows (the 29 plus the
five browser-rail &lt;code&gt;*-web&lt;/code&gt; tool identities, which are one package),
&lt;strong&gt;35&lt;/strong&gt; &lt;code&gt;enabled_adapters&lt;/code&gt; entries (the 34 plus &lt;code&gt;roo-code&lt;/code&gt;, which has no
package and no row), and &lt;code&gt;integration.Tools()&lt;/code&gt; - not &lt;code&gt;EnabledAdapters&lt;/code&gt; -
as the canonical closed tool vocabulary. &lt;code&gt;docs/new-adapter-checklist.md&lt;/code&gt;
gains §3.6a, &amp;quot;what a new launcher gets for FREE&amp;quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Fixed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;fix(adapter): a tool result that lands in the NEXT parse tick is no
longer dropped.&lt;/strong&gt; Found by adversarial review over the wave's combined
diff, not by a test: when a poll ends between a &lt;code&gt;tool_use&lt;/code&gt; record and
its &lt;code&gt;tool_result&lt;/code&gt;, the outcome arrives in a later parse and the action
had already been written without it. Both new JSONL parsers now defer -
an unanswered trailing &lt;code&gt;tool_use&lt;/code&gt; rewinds &lt;code&gt;NewOffset&lt;/code&gt; back to that
record's start (never below &lt;code&gt;fromOffset&lt;/code&gt;), bounded by a 1 MiB tail and a
90-minute mtime grace so a genuinely abandoned session cannot pin the
cursor forever. &lt;strong&gt;Honest scope: this fixes the two new parsers only.&lt;/strong&gt;
claudecode, qwencode, qoder, kimicode and grok carry the same latent
defect, and the right fix there is one store seam (an &lt;code&gt;ON CONFLICT&lt;/code&gt;
outcome upgrade, or a &lt;code&gt;ParseResult&lt;/code&gt; outcome-update channel) rather than
five more copies of the deferral - that arc is deferred and recorded
rather than quietly bundled here.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(codex): duplicate token and system-prompt rows when identical
snapshots straddle a poll boundary.&lt;/strong&gt; Surfaced while reviewing the
Open Interpreter retag, but it is a &lt;strong&gt;codex bug and the fix benefits
codex itself&lt;/strong&gt;: &lt;code&gt;prefetchSessionContext&lt;/code&gt; did not seed its dedup state
from the already-parsed prefix, so a &lt;code&gt;token_count&lt;/code&gt; snapshot whose totals
were unchanged across a poll - and, separately, a re-seen system prompt
&lt;ul&gt;
&lt;li&gt;produced a second row. It now seeds both &lt;code&gt;seenModernTotal&lt;/code&gt; and
&lt;code&gt;seenSystemPrompts&lt;/code&gt; by a state-only prefix replay: rescan-idempotent,
with no change to the &lt;code&gt;SourceEventID&lt;/code&gt; scheme, and it closes a
pre-existing codex system-prompt duplicate class along the way.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(dashboard): the messages-table sort survives a reload and follows
you across sessions.&lt;/strong&gt; v1.26.0 made every header sortable but the choice
was per-mount state, so any reload or session switch silently reverted to
chronological. The selection now persists in &lt;code&gt;localStorage&lt;/code&gt;, is validated
on read (an unknown column or direction falls back to today's exact
chronological default rather than erroring), and is &lt;em&gt;removed&lt;/em&gt; rather than
written when the sort IS the default - so a stored value never
out-lives the preference that created it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(adapter): two smaller findings from the same review.&lt;/strong&gt; Command
Code's meta-model fallback was reachable only at offset 0, so a session
first parsed mid-file never recovered its model; it is now lazy and
fires at any offset. And a racy &lt;code&gt;WithName&lt;/code&gt; mutator was removed outright -
the adapter name is construction-only, so a setter that could run
concurrently with a parse had no reason to exist.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Changed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;test(terminal): the repaint-nudge geometry read is now pinned.&lt;/strong&gt;
v1.26.0's reconnect repaint nudge shipped with the gap written into its
own commit message: the geometry snapshot must be taken BEFORE the
forwarded resize (after it, the manager's snapshot has already converged
and every resize misreads as identical), but nothing pinned that order,
because the package's fake &lt;code&gt;Snapshot()&lt;/code&gt; never converged - so a refactor
moving the read below the resize would have passed the whole suite while
nudging on every resize. A converging fake closes it; mutation-proved.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v1.26.0 - 2026-07-28</title>
    <link href="https://superbased.app/docs/changelog#v1-26-0" rel="alternate"/>
    <id>https://superbased.app/docs/changelog#v1-26-0</id>
    <updated>2026-07-28T00:00:00Z</updated>
    <published>2026-07-28T00:00:00Z</published>
    <content type="html">&lt;h3&gt;Added&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;feat(processobs/etw): Windows per-process network accounting over ETW
(W1-W4).&lt;/strong&gt; Closes the cross-OS gap where only Linux (eBPF) could measure
per-process network bytes. W1 is a pure-Go, CGO-free, dependency-free
decode-only consumer of &lt;code&gt;Microsoft-Windows-Kernel-Network&lt;/code&gt; - the manifest
provider chosen over the legacy NT Kernel Logger for no singleton-session
contention, fixed-width payloads (&lt;code&gt;connid&lt;/code&gt; is &lt;code&gt;win:UInt32&lt;/code&gt;, where the
legacy MOF declares it Pointer-qualified so the width tracks pointer size)
and keyword filtering. Bytes are attributed to the PAYLOAD pid, never
&lt;code&gt;EVENT_HEADER.ProcessId&lt;/code&gt;, which for kernel network events is routinely 4
(System) or 0 (Idle) because completion runs in a DPC or worker thread.
TCP only, enforced structurally: TCP and UDP decode into unrelated types
with no shared parent, so a UDP count cannot reach a TCP total by
accident. The ABI is pinned by 26 two-sided compile-time assertions rather
than tests - CI has no Windows runner and &lt;code&gt;GOOS=windows go build&lt;/code&gt; does not
compile &lt;code&gt;_test.go&lt;/code&gt; files, so a size test would never execute anywhere.
W2 adds the per-pid cumulative accumulator that reconciles ETW's
PER-EVENT byte reports with the cumulative contract every consumer
differentiates (16384 live entries with LRU eviction, mirroring the Linux
&lt;code&gt;netMapMaxEntries&lt;/code&gt;, plus a 1024-entry retired cache so an exit event still
carries final totals), and settles the W1 open question: Linux's
&lt;code&gt;tcp_cleanup_rbuf(copied)&lt;/code&gt; maps to ETW event 11 alone, not 11+18 - summing
both would double-count already-pended data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(processobs,cmd,config): the elevated Windows capturer dials the
daemon (ETW W3/W4).&lt;/strong&gt; The transport direction from the 2026-06-17 spike
was inverted by measurement: on a NAT-mode host, WSL→Windows 127.0.0.1 is
REFUSED (it is WSL's own loopback) and WSL→gateway times out (Defender
drops inbound on the WSL vNIC), while Windows→WSL loopback works via
&lt;code&gt;localhostForwarding&lt;/code&gt;. So the capturer dials a loopback listener the WSL
daemon owns - no firewall rule, no host-IP discovery, no
NAT-vs-mirrored probe. Auth is mandatory with no bypass: 256 bits of
&lt;code&gt;crypto/rand&lt;/code&gt; persisted 0600 beside the DB, constant-time compared, never
logged, read from &lt;code&gt;--token-file&lt;/code&gt; or &lt;code&gt;OBSERVER_PROCESS_BRIDGE_TOKEN&lt;/code&gt; -
there is deliberately NO &lt;code&gt;--token&lt;/code&gt; flag, because argv is world-readable
and this tool captures argv. New &lt;code&gt;[observer.process.etw]&lt;/code&gt; config block.
Backend selection is additive: &lt;code&gt;etw&lt;/code&gt; selects the same baseline &lt;code&gt;auto&lt;/code&gt;
would and ADDS the listener, so an elevated feed that never arrives can
never trade away working zero-privilege capture. Two real bugs were found
building it - an infinite hot loop (a read error and &lt;code&gt;bufio.ErrTooLong&lt;/code&gt;
are permanent and &lt;code&gt;bufio.Scanner&lt;/code&gt; returns them forever, latent on a pipe
where EOF ends a stream, immediately fatal on a socket where a reset does)
and a 30s reconnect stall, now ~1s via a hangup watcher. W4 adds
capturer-link health (a &lt;code&gt;TransportStatsSource&lt;/code&gt; + &lt;code&gt;TransportUnavailableSource&lt;/code&gt;
capability PAIR resolved into &lt;code&gt;none&lt;/code&gt;/&lt;code&gt;unavailable&lt;/code&gt;/&lt;code&gt;configured&lt;/code&gt;, with the
&lt;code&gt;(TransportStats, bool)&lt;/code&gt; signature load-bearing so a Composite carrying no
transport child cannot be forced to claim &amp;quot;a transport exists, with zero
connections&amp;quot;), a detect-and-emit setup surface (&lt;code&gt;observer init&lt;/code&gt; DETECTS an
existing task via &lt;code&gt;/Query&lt;/code&gt;, which works unprivileged, and emits a
fully-resolved command for the operator's own elevated run - it never
prints &amp;quot;registered&amp;quot;, because from WSL's medium-integrity interop token
&lt;code&gt;/Create&lt;/code&gt; is refused for &lt;code&gt;/RL HIGHEST&lt;/code&gt; and for &lt;code&gt;/SC ONLOGON&lt;/code&gt; while a plain
&lt;code&gt;/SC ONCE&lt;/code&gt; succeeds, so it is elevation that is blocked, not task
creation), and &lt;code&gt;--token-file&lt;/code&gt; re-read per reconnect attempt so a
logon-triggered task firing before WSL is up no longer dies permanently.
&lt;code&gt;AuthFailures&lt;/code&gt; counts every handshake refusal and so can never name a
cause - proven live, a wire-version mismatch and port-scanner garbage both
rendered as &amp;quot;shared-token mismatch&amp;quot; - so the daemon's verbatim reason now
travels separately, clamped to 240 bytes, with the metric label carrying a
bounded CLASS rather than the remote string.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(processobs,dashboard): dashboard-driven ETW capturer setup (E1-E7).&lt;/strong&gt;
The W4 arc had concluded &lt;code&gt;observer init&lt;/code&gt; can only DETECT and emit a
command; the measurement behind that still stands (&lt;code&gt;schtasks /Create&lt;/code&gt; IS
Access-denied from WSL's medium-integrity token) but the inference -
&amp;quot;elevation cannot be self-granted&amp;quot; - was too strong. Elevation cannot be
taken silently; it can be brokered through UAC consent. Measured on this
host: &lt;code&gt;Start-Process -Verb RunAs&lt;/code&gt; from WSL reaches High Mandatory Level,
&lt;code&gt;/Create /SC ONLOGON /RL HIGHEST&lt;/code&gt; succeeds, and the single-quoted &lt;code&gt;/TR&lt;/code&gt;
form stores correctly - the first end-to-end confirmation of the quoting
rule W4 derived (the backslash-escaped form parses in cmd.exe but FAILS in
PowerShell; the unquoted form stores unquoted and would launch
&lt;code&gt;C:\Program&lt;/code&gt;). New &lt;code&gt;GET /api/process/etw/status&lt;/code&gt; (capability V, first-class
states rather than errors), &lt;code&gt;POST /api/process/etw/register&lt;/code&gt; (capability L
&lt;ul&gt;
&lt;li&gt;confirm token, with the argv built ENTIRELY server-side - there is no
request struct at all), and an ETW capturer card under Settings → Process
capture. Independent review of E1-E6 raised eight findings, each reproduced
with a failing test before any fix; two were real and sharp - an apostrophe
in a Windows path (&lt;code&gt;C:\Users\O'Brien\…&lt;/code&gt;) closed the &lt;code&gt;/TR&lt;/code&gt; quote early so
schtasks stored a program that was a PREFIX of the real path, and
&lt;code&gt;normalize()&lt;/code&gt; floored a negative counter to zero, turning &amp;quot;this report is
nonsense&amp;quot; into &amp;quot;the decoder ran and refused nothing&amp;quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(processobs,diag,metrics): decode-classification counters, so
&amp;quot;nothing captured&amp;quot; can no longer read as &amp;quot;healthy&amp;quot;.&lt;/strong&gt; &lt;code&gt;Classify()&lt;/code&gt; routes
every unknown event id to &lt;code&gt;ClassIgnored&lt;/code&gt;, so a renumbered provider would
report &lt;code&gt;dropped:0 / unsupported:0&lt;/code&gt; and zero bytes - passing validation
while measuring nothing. New &lt;code&gt;NetworkIgnored&lt;/code&gt; + &lt;code&gt;NetworkDecoded&lt;/code&gt; counters
and &lt;code&gt;NothingClassified()&lt;/code&gt;; &lt;code&gt;Ignored&lt;/code&gt; is deliberately NOT in &lt;code&gt;Any()&lt;/code&gt;,
because a healthy busy capture has a huge Ignored and folding it in would
fire a fault on every working host. Separately, &lt;code&gt;Health.NetworkAccountingMode&lt;/code&gt;
/ &lt;code&gt;Reason&lt;/code&gt; were computed and read by nothing, so an operator whose probes
failed to attach got silence and could not tell &amp;quot;measured, no traffic&amp;quot;
from &amp;quot;never measured&amp;quot;. The daemon now publishes a small node-local JSON
record beside the DB (per-PID + liveness-filtered, the pattern
&lt;code&gt;diag.LockInfo&lt;/code&gt; already uses; a record whose writer pid is gone is dropped
rather than called stale), refreshed every 30s because the backend only
decides the accounting outcome inside &lt;code&gt;Start&lt;/code&gt;. Both &lt;code&gt;observer doctor&lt;/code&gt; and
the &lt;code&gt;/metrics&lt;/code&gt; exporter read it and report it AS A REPORT (&amp;quot;pid N said X,
T ago&amp;quot;), never as live truth; with no daemon reporting, the
&lt;code&gt;observer_process_*&lt;/code&gt; families are ABSENT rather than zeroed, since a
fabricated &lt;code&gt;backend_up 0&lt;/code&gt; is indistinguishable from a genuinely down
backend, and the network mode is an enum series per mode so a mode flip
cannot leave a stale series at 1.
&lt;ul&gt;
&lt;li&gt;Honesty caveat, restated on every surface: nothing under
&lt;code&gt;internal/processobs/etw/&lt;/code&gt; has ever executed. There is no Windows CI
runner and WSL cannot elevate, so the Windows runtime path is compiled,
vetted and lint-clean under both GOOS - not run. The six-step elevated
validation is now enumerated (it had been cited in three documents and
written down in none) in &lt;code&gt;docs/process-observability.md&lt;/code&gt; §5.5 and is
still owed. An idle host also produces the same counter shape as a
renumbered provider; no threshold was invented in either direction, so
the signal is worded as a suspicion.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(processobs): eBPF per-process network bytes + a high-frequency
metric ring.&lt;/strong&gt; The Linux backend attached only
&lt;code&gt;sched_process_exec&lt;/code&gt;/&lt;code&gt;exit&lt;/code&gt; and hard-coded &lt;code&gt;NetworkBytesIn/Out&lt;/code&gt; to zero;
it now attaches &lt;code&gt;fexit/tcp_sendmsg&lt;/code&gt; (return value = bytes actually
queued, so partial sends are honest) and &lt;code&gt;fentry/tcp_cleanup_rbuf&lt;/code&gt;.
&lt;code&gt;tcp_recvmsg&lt;/code&gt; was rejected deliberately - its arity changed between 5.x
and 6.x and an fexit program must know the argument count to locate the
return slot. Same pure-Go &lt;code&gt;cilium/ebpf&lt;/code&gt; loader and hand-written asm as the
existing lifecycle programs: no clang, no bpf2go, no CO-RE, no CGO.
Alongside it, sampling and persistence are split into separate cadences -
&lt;code&gt;sample_interval_ms&lt;/code&gt; (2000) into memory, &lt;code&gt;persist_interval_ms&lt;/code&gt; (15000)
with a ring capped at &lt;code&gt;persist_max_samples&lt;/code&gt; (60) - which is 7.5× finer
sampling AND 7.5× fewer row rewrites, with the stored column the same size
as before and independent of the sample rate. &lt;code&gt;MetricSample&lt;/code&gt; gains
&lt;code&gt;net_rx&lt;/code&gt;/&lt;code&gt;net_tx&lt;/code&gt;/&lt;code&gt;net_measured&lt;/code&gt; as additive JSON on the existing ring, so
no migration; old rings decode with the fields absent, which reads as
unmeasured. TCP payload bytes only - no UDP, so QUIC/HTTP-3 is invisible -
stated in the field docs, the config and the operator docs. NOT VERIFIED:
the eBPF happy path; the authoring host runs
&lt;code&gt;kernel.unprivileged_bpf_disabled=2&lt;/code&gt;, so the programs have never been
through the kernel verifier. The degradation path is verified.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(dashboard): live CPU/RSS/disk charts on the Session Cockpit.&lt;/strong&gt; The
cockpit's System section rendered three 48×14px sparklines with no axes,
units, tooltip or time base, and three defects underneath: only ONE
process was charted (measured on a real session - 458 processes, 455 with
samples, 33 with the ≥2 samples a rate needs, exactly one drawn);
&lt;code&gt;cpu_ms&lt;/code&gt;, &lt;code&gt;rb&lt;/code&gt; and &lt;code&gt;wb&lt;/code&gt; are cumulative monotonic counters plotted RAW, and
no differentiation code existed anywhere in the repo. New
&lt;code&gt;GET /api/session/&amp;lt;id&amp;gt;/metrics?bucket=&lt;/code&gt; aggregates the process subtree onto
an epoch-anchored common grid, differentiates each consecutive pair with
overlap weighting, and sums per-process rates (RSS is instantaneous and is
summed, never differentiated). Each trap is pinned by a test: mid-window
entry is a baseline not a delta against an implicit zero, mid-window exit
contributes nothing after its last sample, a counter reset drops that pair
for that metric only, a pair spanning &amp;gt;8 buckets is a sampling gap rather
than a fake plateau, and a counter reading zero in every sample of every
process is reported UNMEASURED. Every rate is nullable - null is a real
gap, 0 is covered-and-idle - and &lt;code&gt;cpu_scale&lt;/code&gt; is &lt;code&gt;per_core_sum&lt;/code&gt; with
&lt;code&gt;cpu_cores&lt;/code&gt;, unclamped (real data hit 963%). The bucket is the observed
median sample interval; nothing hardcodes a cadence. Rendered pixels are
NOT verified: reaching the cockpit needs a live agent terminal.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(attach): native auto-resume on 18 of 19 launchers.&lt;/strong&gt; v1.25.0 held
auto-resume-on-daemon-restart to claude and codex. Two live PTY
verification waves (bare binaries, bounded, no input typed, read-only
store inspection) confirmed 15 more tools reopen the SAME transcript by
the observer-captured id - opencode, kilo, cline-cli, goose, gemini,
copilot-cli, pi, qwen, grok, kimi, devin, hermes, kiro, qoder,
antigravity - and a follow-up authenticated run added cursor, whose
&lt;code&gt;chatId&lt;/code&gt; is our &lt;code&gt;SessionID&lt;/code&gt; verbatim (Cursor names its on-disk chat
directories with the same uuid the adapter already stores). Cursor's id is
passed JOINED as &lt;code&gt;--resume=&amp;lt;id&amp;gt;&lt;/code&gt; because the flag declares an OPTIONAL
value; &lt;code&gt;resumeTranslation&lt;/code&gt; grew a &lt;code&gt;joined&lt;/code&gt; field for it. Implemented as 15
&lt;code&gt;Resume: ResumeSpec&lt;/code&gt; registry rows + 5 new id mechanisms
(&lt;code&gt;flag:--session&lt;/code&gt; / &lt;code&gt;--session-id&lt;/code&gt; / &lt;code&gt;--id&lt;/code&gt; / &lt;code&gt;--conversation&lt;/code&gt; /
&lt;code&gt;--resume-id&lt;/code&gt;) driving one shared table-driven
&lt;code&gt;cmd/observer/resume_launcher.go&lt;/code&gt;; claude/codex stay bespoke for their
session-id/fork interplay. Grounded nuances captured in the table: gemini
resumes by full UUID, goose strips the &lt;code&gt;@hash8&lt;/code&gt; scope suffix while
announcing the stored scoped id for correlation, kimi wants the
&lt;code&gt;session_&lt;/code&gt;-prefixed id, kiro's flag rides the &lt;code&gt;chat&lt;/code&gt; subcommand. openclaw
is now the sole &lt;code&gt;ResumeNone&lt;/code&gt; launcher (picker-only, runtime-blocked from
probing). Recorded honestly: cursor's resume is flaky over some networks
(&amp;quot;RetriableError: WritableIterable is closed&amp;quot;), affecting non-resume calls
alike, so it is transport rather than a broken mechanism.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(attach,integration): the launching shell's credentials now reach an
attached child.&lt;/strong&gt; Retires the v1.25.0 accepted caveat that an attached
child inherits the DAEMON's environment, so a shell-exported-only API key
that worked bare vanished under attach-by-default. New
&lt;code&gt;Capability.AuthEnv []string&lt;/code&gt; carries the env-var NAMES (never values) a
tool reads credentials from, with seven grounded rows - claude-code,
codex, hermes, pi, copilot-cli (BYOK key plus the documented GitHub-token
precedence chain), gemini-cli (upstream-verified 6-var set across
AI-Studio and Vertex auth modes) and grok; every other row stays
zero-valued with candidate/exclusion comments, and kiro-cli's AWS
credential chain is a deliberate exclusion. &lt;code&gt;forwardAuthEnv&lt;/code&gt; is
presence-aware (an explicit empty &lt;code&gt;KEY=&lt;/code&gt; forwards verbatim and overrides
the daemon value at the child, last-wins) and wired ONCE in
&lt;code&gt;launcherAttach&lt;/code&gt; by capability dispatch - no per-launcher edits, bare
launch untouched. New &lt;code&gt;[terminal.attach].forward_auth_env&lt;/code&gt;, default TRUE.
Values transit the owner-only attach socket once per launch, are never
logged (count-only audit, test-pinned) and are never persisted.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(predict): billed tokens beside the next-message cost band.&lt;/strong&gt; The
predictor showed a dollar band and a fan-out pill with no token figure.
Every dimension was already on the wire, so this is a pure read-side
change - no API, no Go model, no migration. The figure is
&lt;code&gt;turns × (prefix + fresh_input + output)&lt;/code&gt;, the term-for-term counterpart
of the priced &lt;code&gt;P·cache_read + S·input + O·output&lt;/code&gt;, so the tokens and the
dollars count the same things; showing only &amp;quot;new&amp;quot; tokens was the tempting
alternative and is wrong by roughly three orders of magnitude against the
price. It is called BILLED, never &amp;quot;total tokens&amp;quot; or &amp;quot;context&amp;quot; - cache-read
tokens genuinely are billed, and the cockpit already uses the same
&lt;code&gt;prefix_tokens&lt;/code&gt; field as a context-fill gauge. The composition is shown
rather than hidden (&amp;quot;420.7K tok billed · 702 new&amp;quot;); a percentage was tried
and rejected because 420,702 against 420,000 rounds to &amp;quot;100% cached&amp;quot;.
Arithmetic verified end-to-end through the real CLI against the pinned
fixture: &lt;code&gt;2.0 × (210,000 + 1 + 350) = 420,702&lt;/code&gt;, new &lt;code&gt;2 × 351 = 702&lt;/code&gt;. Same
figure added to the CLI band table; the docs disclose that cache-WRITE is
neither read nor priced, so both the dollars and the tokens are a lower
bound on a message that seeds new cache.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(dashboard): sortable columns on the session messages table.&lt;/strong&gt; The
table was chronologically ascending with server-side pagination, so new
messages landed on the LAST page while page 1 stayed pinned to the oldest
rows - following a live session meant paging manually to the end. Every
header now toggles asc/desc with the &lt;code&gt;DataTable&lt;/code&gt; arrow convention, and the
sort is SERVER-side (a client-only sort would have reordered just the 25
rows of the current page). New allow-listed &lt;code&gt;sort_by&lt;/code&gt; + &lt;code&gt;sort_dir&lt;/code&gt; mirror
&lt;code&gt;parseSessionsSortParams&lt;/code&gt;; an absent OR unrecognised key reproduces
today's exact chronological order rather than erroring. Three details
carry the correctness: &lt;code&gt;elapsed_ms&lt;/code&gt; and &lt;code&gt;tps_ms&lt;/code&gt;/&lt;code&gt;tps_basis&lt;/code&gt; are derived
from neighbouring rows over the whole timeline, so the reorder runs
strictly after those derivations and immediately before the offset/limit
slice; the &lt;code&gt;#&lt;/code&gt; column is now a server-assigned whole-timeline ordinal
(&lt;code&gt;seq&lt;/code&gt;) instead of a page-relative array index; and every comparator falls
through to &lt;code&gt;seq&lt;/code&gt; ascending, without which equal-valued rows would visibly
reshuffle between 4s polls. &lt;code&gt;tail=N&lt;/code&gt; still selects the last N
chronologically and then sorts those for display, and &lt;code&gt;locate&lt;/code&gt; computes
its page in the post-sort order. Suggested-by: @smoochy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(website): IA + aesthetics rework - generated marketing pages,
&lt;code&gt;/features&lt;/code&gt; and &lt;code&gt;/faq&lt;/code&gt;.&lt;/strong&gt; The homepage was 22.4 mobile screens and the
product screenshots were hand-crops cut mid-column; the root cause the
operator named is that the site had two mandatory pre-ship gates and both
are CORRECTNESS gates - neither asks whether the page is any good. So
&lt;code&gt;docs/website-design-guide.md&lt;/code&gt; gains a third mandatory gate (editorial &amp;amp;
aesthetic review, 13 items each tracing to a real observed defect) plus a
quarterly cadence. The top-level marketing pages are now GENERATED from
&lt;code&gt;website/pages-src/*.html&lt;/code&gt; through one shared shell
(&lt;code&gt;docs-tools/pagegen&lt;/code&gt;) via &lt;code&gt;make website-build&lt;/code&gt;, gated by
&lt;code&gt;make verify-website-build&lt;/code&gt; - which kills a materialised drift class,
since the chrome had already forked into 4 &lt;code&gt;#topnav&lt;/code&gt; and 3 footer variants
with mismatched analytics attributes and stale build markers. The gate
runs in &lt;code&gt;website-deploy.yml&lt;/code&gt; BEFORE the strip step, not only in &lt;code&gt;ci.yml&lt;/code&gt;,
because &lt;code&gt;ci.yml&lt;/code&gt; is a separate workflow and cannot block a deploy. The
homepage goes 19054px / 22.4 screens / 1787 words → 11294px / 13.3 / 897
with ZERO points deleted: the removed prose moved to new &lt;code&gt;/features&lt;/code&gt; and
&lt;code&gt;/faq&lt;/code&gt; pages, with the FAQPage JSON-LD moved WITH it (parity is checked by
same-file verbatim presence). 20 pixel icons redrawn at 16×16; the nav and
footer drop the &amp;quot;S&amp;quot; glyph for a wordmark - six chrome sources needed
updating, not the three expected, because &lt;code&gt;/docs&lt;/code&gt;, &lt;code&gt;/arcade&lt;/code&gt; and
&lt;code&gt;legal/eula&lt;/code&gt; each carried their own lockup. Density and a11y: the privacy
prose-run 4418→437px, enterprise 14 tiny fonts / 11 sub-44px targets →
0/0, all five support pages at 0/0. The public site and READMEs also gained
a terminal-capability content wave (dashboard launch, Jump-in,
native→local→remote lease movement, Session Cockpit, per-terminal
Files/Git), a new &lt;code&gt;website/docs-src/guides/terminals.md&lt;/code&gt;, and matching
README sections regenerated through &lt;code&gt;docs/distribution/README-body.md&lt;/code&gt;.
&lt;code&gt;security.html&lt;/code&gt; / &lt;code&gt;privacy.html&lt;/code&gt; corrected: raw content ships under
&lt;code&gt;full_content&lt;/code&gt; OR &lt;code&gt;admin_managed&lt;/code&gt;, not &lt;code&gt;full_content&lt;/code&gt; alone.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Fixed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;fix(web,dashboard): the mobile terminal is usable.&lt;/strong&gt; Reported from a
phone: tapping a running-terminal pill rendered the panel clipped on BOTH
sides, scrolling did nothing in either presentation, and the soft keyboard
offers no Ctrl/Alt/Esc/Tab/arrows. Panel geometry -
&lt;code&gt;min-w-[480px]&lt;/code&gt; beats &lt;code&gt;max-w-[96vw]&lt;/code&gt; (CSS 10.4: min wins over max), so the
box resolved to 480px on a 393px viewport and the &lt;code&gt;justify-center&lt;/code&gt;
backdrop split the overflow evenly, making the LEFT half unreachable
(before: panel 480×511 @ left −43, 3 text overflows; after: 393×852 @
left 0, 0 overflows). The breakpoint is a CAPABILITY query -
&lt;code&gt;(pointer: coarse) and (max-width: 1023px)&lt;/code&gt; - so a desktop user who merely
narrows their window keeps a fine pointer and is untouched; desktop
geometry is bit-identical. Touch scroll was never a CSS problem: xterm
gates its ONLY touch-scroll path behind
&lt;code&gt;!coreMouseService.areMouseEventsActive&lt;/code&gt;, so scrolling dies the moment a
TUI enables mouse reporting - an identical 150px drag moved −30px with
mouse mode off and 0px with it on. Own handlers now drive
&lt;code&gt;term.scrollLines()&lt;/code&gt; for vertical-dominant gestures on a scrollable normal
buffer, so a tap still reaches the TUI as an SGR mouse report. On the
ALTERNATE buffer (captured live from &lt;code&gt;claude&lt;/code&gt; 2.1.220, which sets &lt;code&gt;?1049h&lt;/code&gt;
with &lt;code&gt;?1000h ?1002h ?1003h ?1006h&lt;/code&gt;) there is no scrollback at all and the
app scrolls on WHEEL events - which a finger does not have, and which is
exactly why this never reproduced on desktop; a vertical drag there now
dispatches a &lt;code&gt;WheelEvent&lt;/code&gt; and lets XTERM encode it, so the writer-lease
gate applies with no second input path. The on-screen key bar writes
through &lt;code&gt;term.input(seq, true)&lt;/code&gt;, inheriting both the &lt;code&gt;disableStdin&lt;/code&gt; and
&lt;code&gt;canWrite&lt;/code&gt; gates, with exact bytes asserted per button including SS3 under
DECCKM. Keys are now labelled by ACTION (Interrupt / End input) with caret
notation demoted to a sub-label - the operator read &lt;code&gt;^C&lt;/code&gt;/&lt;code&gt;^D&lt;/code&gt; as
&amp;quot;Alt+C / Alt+D&amp;quot; - and Mac labelling (⌃ Control, ⌥ Option) is driven by the
DAEMON's OS via a new &lt;code&gt;host_os&lt;/code&gt; on &lt;code&gt;/api/status&lt;/code&gt;, not the browser's
user-agent, since the browser is usually a phone that is not the machine
being typed into. There is deliberately no ⌘ button: a PTY receives bytes,
Ctrl+C is 0x03 on every OS, and ⌘ never reaches a terminal at all. Also:
a visible &amp;quot;▾ Minimize&amp;quot; with a filled background so the SAFE exit catches
the eye (all three of minimize's previous doors are shut on a phone - no
hardware Escape, no backdrop under a full-viewport panel, and an icon-only
▾ carrying its meaning only in an aria-label, which left the operator
believing the destructive ✕ was the only exit); horizontal swipes are now
swallowed rather than declined, so the OS edge-swipe no longer unloads the
whole dashboard; tap targets 19px → 44px; a Copy action, because xterm's
mouse-drag selection leaves no way to get an error off a phone; and focus
mode renders honestly disabled naming its missing dependency instead of
vanishing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(web): the on-screen keyboard costs the terminal zero rows.&lt;/strong&gt; The
first fix here rested on a wrong premise - per the CSSWG a virtual
keyboard does not affect ANY CSS viewport unit, &lt;code&gt;dvh&lt;/code&gt; included - and the
second (&lt;code&gt;interactive-widget=resizes-content&lt;/code&gt;) broke Chrome/Android touch
scrolling with the keyboard DISMISSED and could not be tested at all, since
the Playwright suites run desktop Chromium where the key is inert. Both are
gone. Shrinking the panel turned out to be the defect itself: measured live
from the operator's own session, the keyboard took the PTY from rows=29 to
rows=8, and a live &lt;code&gt;claude&lt;/code&gt; 2.1.220 driven in a PTY at fixed sizes caps its
composer at 2 lines and shows only the tail at 8 rows - so a third typed
line looked like it overwrote the second. Nothing was wrong with the
emulation; the app was being handed an 8-row terminal. The panel now keeps
its UNOCCLUDED height and TRANSLATES up instead, putting the composer and
key bar at the bottom of the visible area while the row count never
changes, with the header sliding off the top as the deliberate trade. The
unoccluded height is the running maximum of &lt;code&gt;visualViewport.height&lt;/code&gt; at the
current width - a keyboard only ever reduces that height and never changes
the width, so the maximum IS the no-keyboard height, obtained without
asking any engine-specific &amp;quot;is a keyboard present&amp;quot; question. Width changes
reset it, which is rotation. The two keyboard specs are inverted to pin the
new contract, and the test fake's viewport snapshot (taken in an init
script that runs BEFORE Playwright applies the emulated viewport, so every
consumer inherited a baseline no test asked for) is now live getters.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(terminal): a reattached terminal renders at its own width, and
repaints.&lt;/strong&gt; Operator-reported from a phone after a page reload: every line
missing its first character, that character appearing at the end of the
line above - the signature of content wrapped at one width being rendered
at another. &lt;code&gt;Manager.Subscribe&lt;/code&gt; started every new subscriber at the replay
ring's OLDEST byte, and the ring stores raw PTY bytes with no geometry
tagging, so a session that lived at 152 columns on a desktop and later at
47 on a phone replayed both eras into whichever width the reconnecting
client happened to be. The ring's absolute offset is now recorded at each
real geometry change (planted in &lt;code&gt;recordResize&lt;/code&gt; and nowhere else, so
geometry keeps its single owner) and every subscriber starts at
&lt;code&gt;max(currentBase(), that offset)&lt;/code&gt;. The stated trade: a genuine resize
shortens the replay available to the NEXT attach - those bytes were
unrenderable at the new width anyway, and already-attached subscribers are
untouched. It never self-healed because the client's post-replay resize is
a no-op: Linux &lt;code&gt;tty_do_resize()&lt;/code&gt; skips SIGWINCH when the winsize is
unchanged, measured directly as three &lt;code&gt;TIOCSWINSZ&lt;/code&gt; calls and only two
SIGWINCH delivered - and a full-screen TUI on the alternate buffer owns
every cell and only rewrites what it believes changed, so a stale frame
persists indefinitely. A one-shot repaint nudge (resize by one row and
immediately back, &lt;code&gt;rows-1&lt;/code&gt; so the PTY never exceeds the client's real
viewport) now fires once per reattach on the writer path only, skipped when
geometry is unknown or when the client's resize already differs from the
live size.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(terminal): mobile backgrounding no longer kills terminals or forces a
fresh capability code.&lt;/strong&gt; Leaving the browser to copy a code out of email
tore down the view of every running terminal. The PTYs never died -
unsubscribe detaches a viewer without killing the process and idle reaping
is off by default - but &lt;code&gt;ws.onclose&lt;/code&gt; latched status &amp;quot;exited&amp;quot;, a terminal
state, and the socket-setup effect depended only on &lt;code&gt;[token, isRemote]&lt;/code&gt;, so
nothing ever reopened it; only a full page reload recovered. There is now a
distinct &amp;quot;reconnecting&amp;quot; status that counts as live, retry with exponential
backoff and jitter, and a &lt;code&gt;visibilitychange&lt;/code&gt;/&lt;code&gt;pageshow&lt;/code&gt; handler that
reconnects immediately on return, with the standing-secret auto-present in
&lt;code&gt;onopen&lt;/code&gt; so control is regained with no user action. Server side, three
expiries each forced a new code and each moved with a config key whose
default is the new value: capability TTL 2m → 10m (two minutes is shorter
than the round trip to a mail app; still single-use, still bound to
session+action+handle), device-session idle 1h → 24h with the absolute cap
12h → 48h (an absolute cap below the idle target makes the target
unreachable), and standing-provenance writer leases exempted from the 5m
idle reap while the 30m hard cap stays. WS liveness now needs 5 consecutive
missed pongs (~3.3min) rather than one, so a briefly-frozen tab is not
mistaken for a dead peer; an aged-out lease DEMOTES rather than closing the
socket, while a trust-withdrawing revoke still closes it outright. A
revoked standing secret is classified &lt;code&gt;auth_revoked&lt;/code&gt; (permanent, so the
device clears it) while temporarily-disabled and rate-limited stay
transient - previously any auth-ish denial deleted the saved secret with no
retry. Negative &lt;code&gt;session_ttl_minutes&lt;/code&gt; values previously validated clean and
silently yielded the maximum; they are now rejected at load.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(remote): a paired phone no longer loses authorization within the
hour.&lt;/strong&gt; Returning to the dashboard from a phone gave
&lt;code&gt;401 unauthorized: authentication required&lt;/code&gt; on every API call while the UI
itself still served - a working shell with no data. &lt;code&gt;handlePair&lt;/code&gt; set the
cookie with HttpOnly, Secure, SameSite=Strict, Path &lt;code&gt;/&lt;/code&gt; - and NO Max-Age
and NO Expires, making it a BROWSER-SESSION cookie that mobile
Safari/Chrome discard when they end a browsing session or evict a
backgrounded tab, while the server session stayed live and simply
unreachable. Root-caused by elimination against the live install, with the
session table as the fingerprint: 17 rows from 24 pairings since Jul 14,
ELEVEN with zero seconds between &lt;code&gt;created_at&lt;/code&gt; and &lt;code&gt;last_seen&lt;/code&gt;. MaxAge now
derives from the store's own post-defaults lifetime via a new
&lt;code&gt;SessionStore.TTL()&lt;/code&gt; accessor, tracking &lt;code&gt;[remote].session_ttl_minutes&lt;/code&gt; with
no second constant, clamped to ≥1 (a 0 omits the attribute and silently
restores the bug); nothing was loosened and no TTL was extended. This is
also the true root cause of the symptom the 2026-07-25 TTL widening treated
&lt;ul&gt;
&lt;li&gt;no server-side lifetime can rescue a credential the browser has already
thrown away, which is why the defect survived that work by two days. Two
adjacent defects fixed with it: &lt;code&gt;restore()&lt;/code&gt; loaded every non-expired row
with no Max check while &lt;code&gt;Create&lt;/code&gt; hard-fails &lt;code&gt;ErrTooManySessions&lt;/code&gt;, so the
store could start above &lt;code&gt;max_sessions&lt;/code&gt; and pairing then failed with a bare
503 (restore now keeps the Max most-recently-seen and durably prunes the
surplus; the refusal is a 409 naming the revoke path); and &lt;code&gt;api.ts&lt;/code&gt; gated
401 recovery on &lt;code&gt;unsafeMethod()&lt;/code&gt;, which is FALSE for GET, so EVERY read had
no recovery and no UX - recovery is now gated on &lt;code&gt;isRemoteView()&lt;/code&gt; with a
single-flight whoami probe and a one-shot latch, rendering a full-screen
re-pair prompt on a confirmed loss and latching nothing on a probe failure.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(remote): the pairing audit was never wired, so mobile auth was
unfalsifiable.&lt;/strong&gt; &lt;code&gt;buildRemoteController&lt;/code&gt; built &lt;code&gt;dashboard.RemoteOptions&lt;/code&gt; and
never set &lt;code&gt;Audit&lt;/code&gt;, and &lt;code&gt;remoteController.auditSession&lt;/code&gt; returns early on a
nil func - so every session-lifecycle event was silently discarded:
&lt;code&gt;session_paired&lt;/code&gt;, &lt;code&gt;session_revoked&lt;/code&gt;,
&lt;code&gt;terminal_control_standing_acquire&lt;/code&gt;, and the six reasons &lt;code&gt;handlePair&lt;/code&gt;
distinguishes. Only the DIFFERENT &lt;code&gt;Options.RemoteAudit&lt;/code&gt; seam was ever set,
which is why &lt;code&gt;http_request&lt;/code&gt; rows existed in abundance and hid the gap.
Measured on this install: the audit window 2026-07-13..2026-07-27 covers
all 17 rows in &lt;code&gt;remote_sessions&lt;/code&gt; and contains zero &lt;code&gt;session_paired&lt;/code&gt; rows to
explain any of them, so the &amp;quot;maybe it's the max_sessions limit&amp;quot; hypothesis
had been untestable the whole time. Second half: a deny row could not tell
a missing credential from a rejected one - &lt;code&gt;Principal&lt;/code&gt; collapses no cookie,
unknown session, expired session and failed CSRF into &lt;code&gt;CapabilityPublic&lt;/code&gt;,
and those have opposite fixes. The deny row now carries &lt;code&gt;no_cookie&lt;/code&gt; or
&lt;code&gt;cookie_rejected&lt;/code&gt;, appended to the row that is already written so it adds
no audit volume on a hot auth path. Both changes are metadata-only and
neither alters an authorization decision.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(dashboard): &lt;code&gt;/api/health/doctor&lt;/code&gt; withholds local paths and user names
from remote callers.&lt;/strong&gt; The route is capability V, so a paired REMOTE device
could read the checks' free text verbatim - and that text carries absolute
paths and user names pervasively, because most checks are built as
&lt;code&gt;&amp;quot;read X: &amp;quot; + err.Error()&lt;/code&gt; and a Go path error stringifies the whole path.
Measured on a live host before designing anything, and the finding that
mattered is that the disclosure is in the HEALTHY report, not just on
errors: the &lt;code&gt;windows proxy routes&lt;/code&gt; check emits the Windows USER NAME on a
passing run. The sibling ETW route already withheld exactly this class, so
the two were inconsistent in the ordinary case. One choke point now mirrors
the ETW route: for a remote-exposed caller a &lt;code&gt;pathRedactor&lt;/code&gt; performs
EXACT-SUBSTRING substitution of roots the server already holds -
deliberately NOT a &amp;quot;looks like a path&amp;quot; regex, on the precedent that
heuristic predicates in this tree have shipped critical bypasses four times
&lt;ul&gt;
&lt;li&gt;longest-root-first with dedupe, both cleaned and as-given spellings
registered, roots under 4 chars discarded, and cross-OS homes from
&lt;code&gt;crossmount.AllHomes()&lt;/code&gt; given INDEXED placeholders because several homes can
carry the config. &lt;code&gt;local_detail_withheld&lt;/code&gt; is set UNCONDITIONALLY so the
client knows which projection it is rendering, and the UI notice says the
redaction is partial rather than implying it is complete. Named residuals:
a path under no known root, OS-convention system paths left readable on
purpose, and non-path identity - the org enrolment check reports the
enrolled user's EMAIL, which substitution structurally cannot touch.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(cost,cachetrack,routing): Claude Opus 5 was unregistered and priced
live traffic at $0.00.&lt;/strong&gt; &lt;code&gt;LookupWithSource&lt;/code&gt; MISSed &lt;code&gt;claude-opus-5&lt;/code&gt; because
the family ladder had no bare &lt;code&gt;claude-opus&lt;/code&gt; key and &lt;code&gt;&amp;quot;claude-opus-4&amp;quot;&lt;/code&gt; is
not a prefix of &lt;code&gt;&amp;quot;claude-opus-5&amp;quot;&lt;/code&gt;. Measured on a live node: 78 Opus-5 turns
over ~3 days (16.76M cache-read + 1.26M cache-write) reported $0.00 and
re-cost to $18.04 - an under-count that grew with every turn. Three
registries were wrong, not one: &lt;code&gt;cost/pricing.go&lt;/code&gt; gains an exact row at
$5/$25 per MTok (cache read 0.50, 5m write 6.25, 1h write 10, web search
0.01) with &lt;code&gt;FastMultiplier&lt;/code&gt; 2, plus a bare &lt;code&gt;claude-opus&lt;/code&gt; family net so a
future SKU inherits current rates instead of MISSing to $0;
&lt;code&gt;cachetrack/tier.go&lt;/code&gt; gains the 512-token min-cacheable tier (Opus 5 halved
Opus 4.8's 1024, and Fable 5 and Mythos 5 shared the same bug, so
512-1023-token prefixes were labelled &lt;code&gt;below_min_cacheable&lt;/code&gt; though they
cached); &lt;code&gt;routing/tiers.go&lt;/code&gt; gains an explicit &lt;code&gt;TierOpusClass&lt;/code&gt; pin plus the
&lt;code&gt;seedRepresentatives&lt;/code&gt; opus-class swap. Adversarial review caught four
pre-existing errors in the same tables, each re-verified against the vendor
card: &lt;code&gt;opus-4-7&lt;/code&gt; was 4096 where 2048 is published (it survived because a
test asserted the 4095/4096 boundary - a passing test defending the bug);
&lt;code&gt;claude-mythos-preview&lt;/code&gt; had no row and fell through to 1024 instead of
2048, erring in the dangerous direction where the engine predicts a cache
write that never happens and then grades a mispredict; there were no bare
&lt;code&gt;claude-sonnet&lt;/code&gt; / &lt;code&gt;claude-haiku&lt;/code&gt; rows, the identical MISS-to-$0 hole, added
at the STANDARD $3/$15 rather than Sonnet 5's introductory rate which
expires 2026-08-31; and legacy alias &lt;code&gt;claude-opus-4-0&lt;/code&gt; resolved through the
current-gen family row at $5/$25 instead of $15/$75, a 3× under-bill.
Non-shadowing was proven empirically by resolving a 277-id corpus against
both the old and new tables - 259 rows byte-identical, every delta
intended.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(policy,guard): R-155 launcher-wrapper bypass.&lt;/strong&gt; R-155 (persistence
installs) is SeverityCritical/DecisionDeny, but &lt;code&gt;matchPersistenceCommand&lt;/code&gt;
switched on &lt;code&gt;Command.Base&lt;/code&gt;, so any launcher wrapper put the real program in
a positional slot and the rule never saw it - measured ALLOW in
&lt;code&gt;ModeEnforce&lt;/code&gt;, in all three dialects, for &lt;code&gt;Start-Process&lt;/code&gt; (positional,
&lt;code&gt;-FilePath&lt;/code&gt;, &lt;code&gt;saps&lt;/code&gt;/&lt;code&gt;start&lt;/code&gt; aliases, &lt;code&gt;-Verb RunAs&lt;/code&gt;), &lt;code&gt;wsl.exe -d &amp;lt;d&amp;gt; --&lt;/code&gt;
and cmd's &lt;code&gt;start&lt;/code&gt;, and for the crontab / &lt;code&gt;systemctl enable&lt;/code&gt; / Run-key arms
too. Fixed at the PARSE layer rather than inside R-155:
&lt;code&gt;internal/policy/launcher.go&lt;/code&gt; resolves a launcher into the launched argv so
EVERY rule inherits the coverage (verified through R-101 &lt;code&gt;rm -rf /&lt;/code&gt;, R-110
force-push and R-153 secret-read). Three further rounds each found the same
class again, each after clean mutation proofs: a &lt;code&gt;bound&lt;/code&gt; flag computed over
the whole argv SUPPRESSED the cmd-&lt;code&gt;START&lt;/code&gt; reading (the tell was that ADDING
an argument made a denied command allowed) and is deleted, with ambiguity
now emitted as a full cross-product; four fail-OPEN exits became
fail-CLOSED via &lt;code&gt;Command.Unanalyzed&lt;/code&gt;, a new rule R-157 and a
&lt;code&gt;maxParseUnits&lt;/code&gt; budget; &lt;code&gt;pwsh -CommandWithArgs&lt;/code&gt;/&lt;code&gt;-cwa&lt;/code&gt; was absent from the
host vocabulary, substitutions were never stripped under the cmd dialect at
any depth, and &lt;code&gt;parseDepth&lt;/code&gt; stopped stripping at the cap without marking -
all fixed vocabulary-wide with a ~30-row &lt;code&gt;psHostParams&lt;/code&gt; table. Found
unprompted while fixing: a PANIC (seven matchers sliced &lt;code&gt;Argv[1:]&lt;/code&gt;
unguarded, so a line lexing to no words crashed the whole evaluation on
attacker-influenced input), and that .NET ignores whitespace in base64
while Go rejects it, so &lt;code&gt;powershell -e &amp;quot;&amp;lt;b64 with spaces&amp;gt;&amp;quot;&lt;/code&gt; was silently
undecodable. Because mutation proofs verify the change you made and never
the class, the defence is now GENERATED:
&lt;code&gt;TestLauncher_WrappingNeverRelaxes&lt;/code&gt; walks 2,385 command lines / 7,155
verdicts asserting that wrapping never turns a deny into an allow, and it
found four further holes in the fix's own drafts. Recorded rather than
papered over: &lt;code&gt;ssh&lt;/code&gt;, &lt;code&gt;docker run&lt;/code&gt;, &lt;code&gt;psexec&lt;/code&gt;, &lt;code&gt;conhost&lt;/code&gt;, &lt;code&gt;wt.exe&lt;/code&gt; and
&lt;code&gt;Invoke-Command&lt;/code&gt;/&lt;code&gt;Start-Job -ScriptBlock&lt;/code&gt; are still unresolved and still
allow. The ETW setup carve-out was deliberately not widened - it now fails
closed on any launcher-wrapped unit, and its predicate is a tokenizer plus
closed allow-lists (subcommand must be the FIRST argument, &lt;code&gt;/TN&lt;/code&gt; must
match, the schtasks flag set is closed, the program extension must be
&lt;code&gt;.exe&lt;/code&gt; or absent, &lt;code&gt;--connect&lt;/code&gt; must name a loopback address) after two
adversarial passes each found a critical bypass in permissive parsing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(processobs,termsession,store): process attribution reaches
non-claude-code tools.&lt;/strong&gt; Resource charts and process trees were blank for
almost every AI tool - measured against a real DB, 101 direct-attribution
rows out of ~2.67M, with &lt;code&gt;session_pid_bridge&lt;/code&gt; holding only claude-code and
hermes. Three independent causes. (1) The terminal knew the pid and threw
it away: &lt;code&gt;termsession&lt;/code&gt; spawns the PTY child and held &lt;code&gt;proc.Pid&lt;/code&gt; only to set
the process group, so a terminal launched from the dashboard - exactly
where the operator clicks &amp;quot;Session&amp;quot; - was never directly attributed. It is
now published through an injected &lt;code&gt;OnProcess&lt;/code&gt; seam (nil = clean no-op) on
both unix and Windows ConPTY, each pinned by a compile-time assertion, and
seeded ON CORRELATION rather than on run identity, because putting a
run_id in the session_id column would fabricate a session that the PROXY
then stamps onto &lt;code&gt;api_turns&lt;/code&gt;, corrupting cost attribution. (2) Attribution
resolved once at exec and never again, so a correlation-time seed was a
race against the poll: measured over 103 real runs, out-of-band correlation
lands in 0.2-1.9s and usually wins, while &lt;code&gt;discovered&lt;/code&gt; correlation takes
30-266s and ALWAYS lost - i.e. precisely the non-claude tools. A deferred
pass now re-resolves a tracked-but-unattributed run when a seed appears and
re-inherits down its subtree, upgrade-only
(&lt;code&gt;none&amp;lt;low&amp;lt;medium&amp;lt;high&lt;/code&gt;), bounded to the live in-memory tree with a 15-min
age cut and 512 lookups/pass; steady state is zero lookups. (3) The store
was erasing attribution it had already resolved:
&lt;code&gt;upsertProcessRunSQL&lt;/code&gt; wrote &lt;code&gt;session_id&lt;/code&gt; / &lt;code&gt;attribution_source&lt;/code&gt; /
&lt;code&gt;attribution_confidence&lt;/code&gt; unconditionally from &lt;code&gt;excluded&lt;/code&gt;, so the exit
persist wiped whatever &lt;code&gt;CorrelateCrossOS&lt;/code&gt; had since set - and
&lt;code&gt;cross_os_correlation&lt;/code&gt; is the ONLY attribution path for every non-claude
tool. Now a SQL MAX-upgrade guard mirroring the &lt;code&gt;token_usage&lt;/code&gt; ON CONFLICT
discipline, five columns gated on one shared predicate so they move as a
unit. The guard stops future erasure but does not repair already-blanked
rows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(dashboard,web): the per-process network series reaches the chart.&lt;/strong&gt;
The network chart was invisible on Linux with the eBPF probes live and
measuring, and the cause was on both sides of the wire:
&lt;code&gt;sampleNetworkRx&lt;/code&gt;/&lt;code&gt;Tx&lt;/code&gt; were hardcoded &lt;code&gt;return 0, false&lt;/code&gt; stubs whose comment
(&amp;quot;MetricSample carries no network counters today&amp;quot;) had been stale since the
fields landed, forcing &lt;code&gt;MetricSeriesAvailability.Network&lt;/code&gt; false forever;
and &lt;code&gt;ResourceCharts.tsx&lt;/code&gt; had no network chart at all - &lt;code&gt;ChartSpec.dataKey&lt;/code&gt;
was typed &lt;code&gt;&amp;quot;cpu&amp;quot; | &amp;quot;rss&amp;quot; | &amp;quot;disk&amp;quot;&lt;/code&gt; - so the server would have emitted the
fields and the browser discarded them. Both sides now land, gated on
&lt;code&gt;series.network&lt;/code&gt; exactly the way the other charts gate on their
availability flags, so an unmeasured host gets no chart rather than a flat
zero line that would read as &amp;quot;no traffic&amp;quot; when the truth is &amp;quot;not measured&amp;quot;.
&lt;code&gt;ok&lt;/code&gt; is gated on &lt;code&gt;NetMeasured&lt;/code&gt; alone and never inferred from the byte
value; mixed rings produce an honest gap. Also fixes &lt;code&gt;anySeries&lt;/code&gt;, which
ORed only cpu/rss/disk, so a host measuring network but none of those
rendered &amp;quot;No resource samples in the retained window.&amp;quot; over a non-empty
points array. The series is TCP-only and the chart says so.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(dashboard): the &lt;code&gt;etw&lt;/code&gt; process backend is runnable, and the whole
vocabulary is pinned.&lt;/strong&gt; &lt;code&gt;processBackendRunnable&lt;/code&gt; mirrors
&lt;code&gt;selectProcessBackend&lt;/code&gt;'s construction vocabulary and had silently drifted:
&lt;code&gt;&amp;quot;etw&amp;quot;&lt;/code&gt; was correctly false while the selector returned &amp;quot;not yet
implemented&amp;quot; and STAYED false after the selector began constructing a real
Backend. Nothing went red, because the only coverage was a handler test
asserting the OLD answer - the test defended the staleness rather than
catching it. The consequence was not cosmetic: the enable verb switches a
non-runnable backend to &lt;code&gt;auto&lt;/code&gt;, so an operator who had configured
&lt;code&gt;backend = &amp;quot;etw&amp;quot;&lt;/code&gt; and granted elevation would have had it quietly
rewritten, discarding the ETW feed they set up, with the response reporting
success. A table-driven test now covers the ENTIRE vocabulary, each row
stating the selector behaviour it claims.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(termsvc): a correlate-before-registration race dropped the
out-of-band session link.&lt;/strong&gt; &lt;code&gt;drainOOB&lt;/code&gt; starts INSIDE &lt;code&gt;Spawn&lt;/code&gt; but
&lt;code&gt;s.byRun[runID]&lt;/code&gt; is only assigned after &lt;code&gt;Spawn&lt;/code&gt; returns, so a trusted OOB
session frame could reach &lt;code&gt;Correlate&lt;/code&gt; before the run was registered.
&lt;code&gt;Correlate&lt;/code&gt;'s liveness guard exists to stop an ENDED run being resurrected,
but &lt;code&gt;byRun&lt;/code&gt; is equally empty for a NOT-YET-REGISTERED one, so a legitimate
early correlation was silently discarded - and the frame is one-shot, so
the link was lost for the life of the run and &amp;quot;Jump in&amp;quot; stayed blank. Not
theoretical: the full &lt;code&gt;-race&lt;/code&gt; suite failed on
&lt;code&gt;TestAttachCorrelationAssembledThroughHTTP&lt;/code&gt;. Fixed with a &lt;code&gt;launching&lt;/code&gt;
reservation taken under &lt;code&gt;s.mu&lt;/code&gt; BEFORE &lt;code&gt;Spawn&lt;/code&gt; and released in the SAME
critical section that installs &lt;code&gt;byHandle&lt;/code&gt;/&lt;code&gt;byRun&lt;/code&gt;; &lt;code&gt;releaseLaunching&lt;/code&gt; drops
the reservation AND any &lt;code&gt;bySession&lt;/code&gt; entry on the Spawn-error path plus a
deferred catch-all, because an entry written while the run was only
reserved would otherwise be unreachable by &lt;code&gt;EndRunByHandle&lt;/code&gt; (keyed by
handle) - i.e. fixing the bug naively would have reintroduced the
resurrection leak the guard exists to prevent.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(hermes): &lt;code&gt;observer hermes&lt;/code&gt; supplies a model whenever it injects
&lt;code&gt;--provider&lt;/code&gt;.&lt;/strong&gt; The launcher prepended &lt;code&gt;--provider observer&lt;/code&gt; and nothing
else; hermes rejects that combination outright
(&lt;code&gt;--provider requires --model (or HERMES_INFERENCE_MODEL)&lt;/code&gt;) and exits
before issuing a single API call, so every wrapped run died at argument
validation while the same agent was healthy run natively. The bug survived
live verification because the documented invocation always carried an
explicit &lt;code&gt;--model&lt;/code&gt; - the one form anybody tested was the one form that
worked. The launcher now resolves a model the way hermes would, via an
ordered rule table: a foreign &lt;code&gt;--provider X&lt;/code&gt; leaves argv untouched with a
not-proxy-routed warning; an already-supplied model injects the provider
only; otherwise hermes' own &lt;code&gt;model.default&lt;/code&gt; is injected alongside; and
failing that, nothing is injected and the run launches unrouted with a loud
notice (deliberately fail-open - injecting &lt;code&gt;--provider&lt;/code&gt; without a model is
guaranteed to fail, and refusing to launch would break a command that works
natively). Also fixed while hardening the arg scanner: &lt;code&gt;hermesConfigPath&lt;/code&gt;
ignored &lt;code&gt;HERMES_HOME&lt;/code&gt; and &lt;code&gt;--profile&lt;/code&gt;, so with a profile active the
provider entry was written to the wrong file AND the injected model came
from the wrong home; the &lt;code&gt;chat&lt;/code&gt; subcommand re-declares
&lt;code&gt;--model&lt;/code&gt;/&lt;code&gt;--provider&lt;/code&gt;, so top-level flags were silently discarded and are
now placed after &lt;code&gt;chat&lt;/code&gt;; &lt;code&gt;--oneshot&lt;/code&gt; and &lt;code&gt;chat -q&lt;/code&gt; did not trip the
attach-incompatible gate, so scripted headless runs were handed to a
daemon-owned PTY; argparse abbreviations (&lt;code&gt;--prov openrouter&lt;/code&gt;) bypassed the
foreign-provider guard; and an option-looking token is no longer accepted
as a flag value. &lt;code&gt;stripUpstreamPrefix&lt;/code&gt; now warns once per unknown upstream
id - it fails open by design but did so silently, returning an opaque 404
with nothing to debug from. Reported-by: @Pranjal-Godhat.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(obs): the &lt;code&gt;budget-band-cheaper&lt;/code&gt; egress starter template routed to a
retired model.&lt;/strong&gt; It suggested &lt;code&gt;claude-3-5-haiku-20241022&lt;/code&gt;, retired
2026-02-19, so an operator applying the template as-is would route
budget-pressured end-users to a model that now 404s upstream. Swapped to
&lt;code&gt;claude-haiku-4-5&lt;/code&gt;, the documented drop-in replacement. Test fixtures and
the historical pricing-registry row keep the old id by design - they price
observed data, not suggestions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix(website): mobile visual density and three tap/overflow defects.&lt;/strong&gt; The
complaint was &amp;quot;the mobile site is very text-heavy&amp;quot;; measurement said the
intuition was right but the cause was not text volume - word count is
IDENTICAL desktop vs mobile and words/screen is actually LOWER on a phone.
What collapses is the visual supply: text:visual 0.59 at 1280px vs 1.69 at
393px, with 6 of 13 sections carrying zero visual coverage - 6.2 phone
screens without an image, diagram, chart or code block. Two mechanisms: a
16:9 embed loses height exactly as fast as prose gains it (648px at 1280
becomes 201px at 393, −69%, while the same copy grows 751 → 1963px), and
the 860px collapse stacks visuals BELOW copy instead of beside it. So the
fix adds visual supply rather than cutting text - nothing deleted, hidden,
collapsed or reordered, which keeps the deliberately text-first indexable
homepage intact: text:visual @393 1.69 → 0.879, longest visual-free run
2936 → 1023px, longest prose run 1916 → 318px, sections at 0% visual
6 → 0. The cheapest step was surfacing what already shipped - &lt;code&gt;pixel-icons.js&lt;/code&gt;
defines 20 pixel-art glyphs, loads on every page except index and arcade,
and its 13 domain icons rendered nowhere. The two dashboard screenshots
were 1920×1080 rendered into 355 CSS px, a 5.4× reduction putting the UI's
own 13px labels at ~2.4px, and are now 3:2 detail crops whose numbers are
readable. Defects: the arcade rotate-banner dismiss button was 100%
unreachable at every phone width and tapping it navigated the visitor OFF
the arcade (the real cause was a full-screen z-index:200 scrim on first
paint, not the top bar that appeared to steal the tap); all six support
pages scrolled horizontally below 344px (+21px at 320 - iPhone SE, Galaxy
Fold cover), and the earlier 7px-font hack attempting this is deleted; two
homepage images had no intrinsic size, reserving 0px before load for ~400px
of cumulative shift; the install command - the page's primary CTA - was
visually truncated and now wraps; footer legal links were 17px tall. Site
download and stars figures refreshed from authoritative sources (the npm
registry range API, pepy.tech for the all-time PyPI figure since pypistats
only exposes a 180-day window, and the Marketplace extensionquery).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Changed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;perf(db): the &lt;code&gt;quick_check&lt;/code&gt; integrity probe is opt-IN, not opt-out.&lt;/strong&gt;
&lt;code&gt;observer remote status&lt;/code&gt; took 3m59.971s on a 14.7GB install - not because
the data was too large to read, but because &lt;code&gt;db.Open&lt;/code&gt; ran
&lt;code&gt;PRAGMA quick_check&lt;/code&gt;, which reads and checksums every page, so a read-only
status command paid a full-database verification to print a table. Measured
after: 0.189s, same output. The polarity was the defect: under the opt-out
spelling (&lt;code&gt;SkipIntegrityCheck&lt;/code&gt;) the same class had already been patched
three times at individual call sites - the MCP server, the daemon, and
&lt;code&gt;observer run&lt;/code&gt; (re-measured 0.16s vs &amp;gt;120s) - and each patch left the trap
armed for the next caller. The real blast radius was never 11 files:
&lt;code&gt;cmd/observer&lt;/code&gt;'s &lt;code&gt;loadConfigAndDB&lt;/code&gt; reached 85 call sites across 40 files,
every read-only reporting command among them. An opt-out flag must be
remembered at each new site and is silent when forgotten; an opt-in flag
fails safe. &lt;code&gt;Options.SkipIntegrityCheck&lt;/code&gt; becomes &lt;code&gt;Options.IntegrityCheck&lt;/code&gt;,
and the &lt;code&gt;loadConfigAndDB&lt;/code&gt; / &lt;code&gt;loadConfigAndDBFast&lt;/code&gt; twins collapse into one
function - two names for identical behaviour is how callers picked wrong in
the first place. Nothing loses the probe: it runs once per daemon via
&lt;code&gt;RunStartupMaintenance&lt;/code&gt; (off the readiness path) and as &lt;code&gt;observer doctor&lt;/code&gt;'s
&lt;code&gt;db.integrity&lt;/code&gt; check, which ran its OWN &lt;code&gt;quick_check&lt;/code&gt; all along, so doctor
had been paying for it twice. The one caller that opts in is
&lt;code&gt;observer db import&lt;/code&gt;, which validates an untrusted foreign database before
merging it. The schema-034 path-hash backfill also moves to a single owner
(&lt;code&gt;RunStartupMaintenance&lt;/code&gt;) rather than whichever &lt;code&gt;Open&lt;/code&gt; happened to come
first.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ci: the Windows cross-compile is gated.&lt;/strong&gt; &lt;code&gt;go test ./...&lt;/code&gt; never compiles
a &lt;code&gt;//go:build windows&lt;/code&gt; file and the build step's only Windows target was
&lt;code&gt;cmd/antigravity-bridge&lt;/code&gt;, so a Windows-only break in &lt;code&gt;internal/processobs&lt;/code&gt;
shipped undetected - a gap that widens with the almost entirely
windows-tagged ETW backend. Compile-only; the tree was verified clean
before adding, so this pins a property that already held. &lt;code&gt;make test-race&lt;/code&gt;
also gains a &lt;code&gt;-timeout&lt;/code&gt; (&lt;code&gt;cmd/observer&lt;/code&gt; measures 593-698s against Go's 600s
default, so the release checklist's full race suite could have failed RED
for no reason).&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v1.25.0 - 2026-07-24</title>
    <link href="https://superbased.app/docs/changelog#v1-25-0" rel="alternate"/>
    <id>https://superbased.app/docs/changelog#v1-25-0</id>
    <updated>2026-07-24T00:00:00Z</updated>
    <published>2026-07-24T00:00:00Z</published>
    <content type="html">&lt;h3&gt;Added&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;feat(terminal): dashboard-launched terminals joinable by default.&lt;/strong&gt;
&lt;code&gt;/api/attach/sessions&lt;/code&gt; widened to every live daemon-owned run kind
(fresh/handoff/attach/resume) - a terminal launched from the dashboard is
now itself a Jump-in candidate, not just an &lt;code&gt;--attach&lt;/code&gt; session. A handoff
terminal's row keys by the FORKED session (not the source it continued
from), so it's joined from the fork's session detail once correlation links
it. &lt;code&gt;JumpInButton&lt;/code&gt;'s copy and newest-row selection (picking the most
recently created live row when more than one matches a session) were
updated to match the wider row set.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(attach): attach-by-default for all 19 CLI launchers.&lt;/strong&gt; Every
&lt;code&gt;observer &amp;lt;verb&amp;gt;&lt;/code&gt; launcher (claude, codex, opencode, cursor, copilot-cli,
kilo, cline-cli, hermes, gemini, openclaw, pi, antigravity-cli, qwen, kiro,
grok, kimi, devin, qoder, goose) now attaches by default the same way
claude/codex have - a shared launcher gate plus 19 new integration-registry
Attach rows (tool key → launcher verb). Auto-resume-on-daemon-restart stays
gated to the two tools with a verified native resume (claude, codex) - every
other launcher gets an honest degraded-mortality notice instead (a daemon
restart ends the session outright; &lt;code&gt;observer &amp;lt;verb&amp;gt; --continue-from &amp;lt;session-id&amp;gt;&lt;/code&gt; is the manual fork fallback). Proxy env forwarding and
&lt;code&gt;[terminal.attach].route_proxy&lt;/code&gt; / &lt;code&gt;--no-proxy&lt;/code&gt; remain claude/codex-scoped -
every other tool's daemon-spawned inner launcher handles its own
base-URL routing itself. Note the attached child inherits the DAEMON's
environment, not the launching shell's - a credential exported only in the
launching shell won't reach it (config-file/OAuth auth unaffected; export
it where &lt;code&gt;observer start&lt;/code&gt; runs, or use &lt;code&gt;--no-attach&lt;/code&gt;). &lt;code&gt;JumpInButton&lt;/code&gt;'s verb map extended to cover
all 19 tools.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v1.24.1 - 2026-07-24</title>
    <link href="https://superbased.app/docs/changelog#v1-24-1" rel="alternate"/>
    <id>https://superbased.app/docs/changelog#v1-24-1</id>
    <updated>2026-07-24T00:00:00Z</updated>
    <published>2026-07-24T00:00:00Z</published>
    <content type="html">&lt;h3&gt;Added&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;feat(terminal): generic terminal→session correlation sweep.&lt;/strong&gt; Closes the
Session Cockpit gap where only claude-code (out-of-band, 0.95 confidence)
and codex (rollout discovery, 0.75) could link a dashboard-launched
terminal to its observer session - every other launcher stayed
uncorrelated. A 10s daemon-side, tool-agnostic discovery pass
(&lt;code&gt;termsvc.Correlate&lt;/code&gt;) now links any LIVE uncorrelated run to a UNIQUE
candidate session (matched on tool + project root + a launch-time window
of [−5s, +30m]) at &lt;code&gt;SourceDiscovered&lt;/code&gt; 0.75 confidence - unique-or-abstain
with a 2-tick dwell before committing a link, and tick-wide abstention on
any unsound tick (hit caps, transient failures) rather than a partial or
best-guess link. Both sides are revalidated immediately before a link
commits; store queries use julianday-precise window arithmetic;
dashboard-handoff runs are resolved via the source session's own project
root; a new integration reverse map (launcher-verb → tool) normalizes the
match. Open Session Cockpit panels self-heal through the existing 15s
link poll - no frontend change needed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(dashboard): themed tooltips.&lt;/strong&gt; Finished the migration to the
existing floating-ui &lt;code&gt;Tooltip&lt;/code&gt; primitive across the sidebar collapsed
rail, terminal toolbars (⊙ Session/Files/Git, focus/grid/minimize/close,
size-mode, standing-secret), the Launch Dock, and the New Terminal
dialog - aria-labels preserved or added throughout, and the Playwright
specs flipped from &lt;code&gt;title&lt;/code&gt; to &lt;code&gt;aria-label&lt;/code&gt; assertions in lockstep. Native
&lt;code&gt;&amp;lt;option&amp;gt;&lt;/code&gt; titles are deliberately kept as-is, and the terminal-resize
modal hint deliberately stays a native &lt;code&gt;title&lt;/code&gt; (a persistent tooltip
hovering a live terminal is worse than a native one).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat(dashboard): Tailscale setup flow.&lt;/strong&gt; The Configuration card's &amp;quot;Pair
a device&amp;quot; action now gates on tailnet reachability: disabled with the
exact missing step plus a &amp;quot;Go to Tailscale setup&amp;quot; scroll-link when the
tailnet is known-unreachable, and enabled-with-caution when serve status
can't be detected on older Tailscale CLIs. Device-side guidance was added
to the serve-active step and the QR reveal (&amp;quot;install Tailscale on your
phone/device and sign into the same tailnet&amp;quot;, with iOS/Android/download
links). The HTTPS-consent (&lt;code&gt;enable_url&lt;/code&gt;) path now states plainly that
approval alone does not start serving, and offers a Retry serve action.
&lt;code&gt;docs/remote-access.md&lt;/code&gt; updated to match.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Notes&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Adversarial review: two codex GPT-5.6 passes (all findings fixed) plus an
independent Claude Opus pass (verdict SHIP; its remaining findings -
bounding the forward correlation window at 30 minutes, reconciling the
remote-language e2e case, reverting the resize-hint tooltip, and a
watcher-lag accessibility fix - were all applied). codex usage stayed
capped through this work (resets 2026-07-28); the Opus substitution was
operator-approved.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v1.24.0 - 2026-07-24</title>
    <link href="https://superbased.app/docs/changelog#v1-24-0" rel="alternate"/>
    <id>https://superbased.app/docs/changelog#v1-24-0</id>
    <updated>2026-07-24T00:00:00Z</updated>
    <published>2026-07-24T00:00:00Z</published>
    <content type="html">&lt;h3&gt;Added&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Session Cockpit: a live per-terminal floating panel.&lt;/strong&gt; Every embedded
dashboard terminal running an AI tool gains a &amp;quot;⊙ Session&amp;quot; button that
opens a compact, draggable cockpit next to the terminal - the glanceable
companion to the session-detail page, not a clone of it. It shows, live:
a now strip (last activity, tokens/sec with an honest measured/estimated
basis badge, live process count), total cost with the AI/tool split and
the next-message cost band, context fill against the model budget, token
buckets, the 5h/7d rate-limit gauge (proxy-routed sessions), prompt-cache
expiry countdown chips, system telemetry (CPU/memory/disk sparklines and
the spawned-process tree from process observation, plus proxied API
traffic with byte totals when body capture measures them), and the last
five turns deep-linking into the session-detail page.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Terminal→session live linkage.&lt;/strong&gt; New &lt;code&gt;GET /api/terminal/session/&amp;lt;token&amp;gt;&lt;/code&gt;
resolves a running terminal to its correlated observer session (id +
correlation confidence, refusal-ordered so remote callers can never probe
token existence); the cockpit keeps polling so a later authoritative
correlation re-points the panel, and links below the out-of-band tier
carry an explicit &amp;quot;≈ linked&amp;quot; badge.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;One-click process-capture enable.&lt;/strong&gt; When process observation is off, the
cockpit's System section explains what's missing and offers an atomic
server-side enable (&lt;code&gt;POST /api/process/enable-capture&lt;/code&gt;): non-runnable
backend selections switch to automatic with the previous value named in
the notice, hosts with no runnable capture backend get an honest
&amp;quot;unavailable on this machine&amp;quot; instead of a false success, and capture
honestly starts only after the daemon restarts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;?tail=N&lt;/code&gt; on the session messages API&lt;/strong&gt; - returns the true last N rows
of the full timeline for fast pollers (explicitly rejected when combined
with pagination parameters).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;?summary=1&lt;/code&gt; on the session network API&lt;/strong&gt; - a server-side aggregate
separating proxied API calls (with request/response byte sums from body
metadata) from OS-observed process connections.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tool-binary resolution with classified verdicts.&lt;/strong&gt; Every embedded-
terminal launcher now resolves its tool binary through a shared ladder -
process PATH, then a memoized login-shell PATH capture, then native
install-location probing, then (WSL only) a foreign-Windows-home check -
and classifies the result as &lt;code&gt;ok&lt;/code&gt;, &lt;code&gt;ok_off_path&lt;/code&gt;, &lt;code&gt;shadowed&lt;/code&gt;,
&lt;code&gt;foreign_only&lt;/code&gt;, or &lt;code&gt;not_found&lt;/code&gt;. Fixes the class of bug where a
Windows-installed npm shim shadowed (or stood in for) a native binary on
WSL, and the launcher's stale process PATH meant a fresh native install
wasn't picked up without restarting the daemon.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Guided one-click install.&lt;/strong&gt; When a tool isn't natively resolvable, the
New Terminal dialog shows the verified official install command and an
&amp;quot;Install in terminal&amp;quot; button that runs it in a visible PTY. Gated by the
new &lt;code&gt;[terminal.launch].allow_install&lt;/code&gt; config key (default on).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;observer doctor&lt;/code&gt; and &lt;code&gt;observer adapters&lt;/code&gt; surface binary-resolution
health&lt;/strong&gt;, including a &lt;code&gt;foreign_only&lt;/code&gt; bucket (tool installed on Windows
only, not launchable from a WSL daemon) and a best-effort Windows
proxy-route reachability check.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;observer init&lt;/code&gt; writes Windows-side proxy routes.&lt;/strong&gt; When the daemon
runs in WSL, &lt;code&gt;init&lt;/code&gt; can now also point a Windows-installed claude-code or
codex at the daemon's proxy (&lt;code&gt;localhost:8820&lt;/code&gt;, relying on WSL2's
&lt;code&gt;localhostForwarding&lt;/code&gt;), so accurate token capture works even when the AI
tool itself is installed on the Windows side.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;[launch.tools.&amp;lt;tool&amp;gt;].path&lt;/code&gt;&lt;/strong&gt; config override to pin a specific binary
path per tool, bypassing the resolution ladder.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Custom terminal project paths typed in Windows form (&lt;code&gt;C:\Users\…&lt;/code&gt;) are
now translated to their WSL mount equivalent before validation.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Fixed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Concurrent dashboard config saves can no longer lose updates.&lt;/strong&gt; All
in-process config read-modify-write paths - section saves, pricing,
backup restore, remote-manage toggles, terminal limits/policy,
experiments, and the admission-policy persister - now serialize on one
shared lock in the config package (cross-process CLI writes remain
outside a mutex's reach and are documented as such).&lt;/li&gt;
&lt;li&gt;The attach-replay bound test no longer flakes on slow runners (the
precondition now waits for the pump to drain the full produced stream).&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v1.23.0 - 2026-07-23</title>
    <link href="https://superbased.app/docs/changelog#v1-23-0" rel="alternate"/>
    <id>https://superbased.app/docs/changelog#v1-23-0</id>
    <updated>2026-07-23T00:00:00Z</updated>
    <published>2026-07-23T00:00:00Z</published>
    <content type="html">&lt;h3&gt;Added&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;superbased&lt;/code&gt; CLI alias.&lt;/strong&gt; The binary now also runs as &lt;code&gt;superbased&lt;/code&gt;,
selected from &lt;code&gt;argv[0]&lt;/code&gt; - &lt;code&gt;observer&lt;/code&gt; is unchanged and stays canonical
(no deprecation yet). npm and PyPI ship &lt;code&gt;superbased&lt;/code&gt; alongside &lt;code&gt;observer&lt;/code&gt;
as console entry points, and release tarballs/zips include a &lt;code&gt;superbased&lt;/code&gt;
alias next to the &lt;code&gt;observer&lt;/code&gt; binary.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;First-run guided dashboard tour.&lt;/strong&gt; A spotlight-and-coach-mark
walkthrough (Overview → Live → Sessions → Cost → Cache → Terminals →
Security → Settings → global filter/help) auto-starts once on new
installs and is replayable any time from the Help drawer or the command
palette.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Per-terminal Files/Git project explorer.&lt;/strong&gt; Every dashboard terminal
(floating window or grid tile) gets Files/Git panel buttons: a read-only
file tree + viewer and a git view (branch, ahead/behind, changes,
100-commit history). Panels are floating, draggable, multi-panel windows
&lt;ul&gt;
&lt;li&gt;one per terminal, open simultaneously - with a right-click context
menu to copy the selected path (relative or absolute) and, on a live
write-capable terminal, paste it straight into that terminal.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authenticated remote terminal takeover.&lt;/strong&gt; A fully-authorized remote
dashboard can now take over control of a terminal from a local/native
writer or from another remote seat, completing the native → local →
remote handoff. Default-on; see the config change below.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Playwright e2e regression suites&lt;/strong&gt; covering the guided tour, terminal
key/paste handling, and the new project panels.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VS Code extension lint gate.&lt;/strong&gt; &lt;code&gt;npm run lint&lt;/code&gt; (eslint) is now runnable
in the extension's dev workflow; dev-only, not part of the packaged
extension.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pricing: the 2026 model-release wave.&lt;/strong&gt; ~35 new cost-engine rows for
Claude Mythos 5 (Fable-5-equivalent pricing); the Qwen 3.5 family
(plus/flash/omni-plus/omni-flash) plus 3.7-Plus and a 3.8-Max-Preview
placeholder row (no published rate yet - anchored to 3.7-Max's exact
price pending an official card); GLM-5.2; MiniMax M3; Tencent Hy3;
StepFun Step-3.5-Flash; ERNIE 5.1; ByteDance Seed 2.0 (provisional,
Volcengine has no official card yet); Meta Muse Spark 1.1; Cohere North
Mini Code (genuinely free); Sakana Fugu Ultra; Thinking Machines
Inkling; Jamba Mini 2; Gemini Omni Flash; and Sarvam (free). A
researched-but-not-priced ledger is kept in code comments for models
with no public rate card (Cohere Command A+, the original pre-1.1 Muse
Spark, Phi-4-reasoning-vision-15B, Falcon H1R 7B) so they aren't
re-researched needlessly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Website repositioned around the AI-agent control-plane story.&lt;/strong&gt;
superbased.app now leads with seeing agents' actions and provider-
reported token usage across 26 tools, then controlling the supported
sessions (dashboard terminals, paired-device session attach/takeover,
model routing, egress guardrails); four decorative Canvas animations
from the marketing library embed on the homepage
(&lt;code&gt;prefers-reduced-motion&lt;/code&gt;-aware, pause when hidden/offscreen).
&amp;quot;Observer Quest&amp;quot; renamed &amp;quot;SuperBased Quest&amp;quot;. 12 README + 3 website
dashboard screenshots refreshed against the current UI.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Changed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;[remote].allow_terminal_view&lt;/code&gt; now defaults to &lt;code&gt;true&lt;/code&gt;.&lt;/strong&gt; A paired,
authenticated remote device can view (read-only) attach/resume terminal
output by default; set it to &lt;code&gt;false&lt;/code&gt; to restore the prior deny-by-default
posture.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;New &lt;code&gt;[remote].allow_remote_terminal_takeover&lt;/code&gt;, defaults to &lt;code&gt;true&lt;/code&gt;.&lt;/strong&gt;
Pairs with the takeover feature above; set it to &lt;code&gt;false&lt;/code&gt; to keep refusing
a remote takeover of an existing writer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;[terminal].idle_timeout&lt;/code&gt; now defaults to &lt;code&gt;&amp;quot;0&amp;quot;&lt;/code&gt;.&lt;/strong&gt; Idle embedded
terminals are no longer reaped after 30 minutes of no PTY I/O (a quiet
agent sitting at its prompt was being killed mid-session); set it back to
&lt;code&gt;&amp;quot;30m&amp;quot;&lt;/code&gt; to restore the old cleanup behavior.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Product renamed &amp;quot;SuperBased Observer&amp;quot; → &amp;quot;SuperBased&amp;quot;&lt;/strong&gt; in prose and UI
only. Every technical identifier - the &lt;code&gt;observer&lt;/code&gt; CLI, package names, the
&lt;code&gt;[observer]&lt;/code&gt; config section, &lt;code&gt;~/.observer&lt;/code&gt;, the &lt;code&gt;observer.db&lt;/code&gt; filename -
is unchanged. VS Code extension display strings (command titles, activity
bar, output channel, notifications) were renamed the same way; the
Marketplace listing name updates at the next publish.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Fixed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;observer run&lt;/code&gt; no longer mangles multi-line commands or shell builtins
(&lt;code&gt;cd&lt;/code&gt;, &lt;code&gt;export&lt;/code&gt;, …) when wrapping them for hooks, and the wrapped command
now skips the daemon's integrity check on that path - about 750× faster
to start (measured 0.16s vs. over 120s against a large database).&lt;/li&gt;
&lt;li&gt;STT/dictation paste into the embedded terminal: xterm.js was silently
canceling plain Ctrl+V, so dictation tools' fallback paste landed a stale
clipboard instead of the transcription; plain Ctrl+V now reaches the
browser's native paste handling.&lt;/li&gt;
&lt;li&gt;Terminal-dock drag gestures: an interrupted drag (pointer cancel or lost
pointer capture) can no longer leave the gesture armed for a later stray
pointer move to resume from a stale origin.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v1.22.0 - 2026-07-21</title>
    <link href="https://superbased.app/docs/changelog#v1-22-0" rel="alternate"/>
    <id>https://superbased.app/docs/changelog#v1-22-0</id>
    <updated>2026-07-21T00:00:00Z</updated>
    <published>2026-07-21T00:00:00Z</published>
    <content type="html">&lt;h3&gt;Added&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Take control back at your native terminal.&lt;/strong&gt; The missing leg of the
session-control triangle: after a dashboard Jump-in, just start typing in
the terminal that launched the session (&lt;code&gt;observer claude&lt;/code&gt;/&lt;code&gt;codex&lt;/code&gt;) - the
daemon returns the writer lease, delivers that keystroke, prints a
one-line notice, and re-pushes your terminal's geometry so a TUI the
dashboard left at foreign dimensions heals in the same gesture. Machine
bytes never reclaim (terminal emulators auto-answer TUI queries on stdin);
arrow keys or a bare ESC alone won't either, by design. Config:
&lt;code&gt;[terminal.attach].reclaim_on_input&lt;/code&gt; (default on). The dashboard seat goes
honestly read-only - &amp;quot;control returned to the native terminal - click to
take back&amp;quot;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Original-size restore for broken TUIs.&lt;/strong&gt; The daemon now tracks each
session's launch-time and current PTY dimensions; every dashboard terminal
gets a fit / original-size toggle that pins the launch geometry (auto-refit
suppressed) to recover a TUI corrupted by resizes, and a seat re-asserts
its own geometry whenever it regains control.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keyboard shortcuts reach the dashboard terminal.&lt;/strong&gt; Ctrl+A/E/K/. and
friends now go to the TUI instead of the page while the terminal is
focused; Ctrl+Alt push-to-talk chords pass through untouched;
copy-with-selection stays native. Browser-reserved keys (Ctrl+W/T/N)
honestly can't be intercepted in a normal tab - the new fullscreen
&lt;strong&gt;focus mode&lt;/strong&gt; (Keyboard Lock, Chromium) is where they reach the TUI.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Watch a bare session read-only.&lt;/strong&gt; Sessions started outside observer
(plain &lt;code&gt;claude&lt;/code&gt;, &lt;code&gt;codex&lt;/code&gt;, …) that are actively producing events now show a
&amp;quot;live · watch&amp;quot; badge: a read-only, auto-following view of the conversation
(4s refresh, stick-to-bottom) in the session panel. &amp;quot;Jump in&amp;quot; stays
honestly disabled - a bare launch's terminal belongs to the shell that
started it - with &amp;quot;Watch instead (read-only)&amp;quot; offered in its place.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Collapsible sidebar.&lt;/strong&gt; The dashboard's left nav collapses to a compact
icon rail on desktop (persisted, tooltips); the mobile drawer is unchanged.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Fixed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Post-v1.21.0 CI red: six golangci-lint findings in the release's new code
(behavior-preserving refactors) and the missed website version sweep.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v1.21.0 - 2026-07-21</title>
    <link href="https://superbased.app/docs/changelog#v1-21-0" rel="alternate"/>
    <id>https://superbased.app/docs/changelog#v1-21-0</id>
    <updated>2026-07-21T00:00:00Z</updated>
    <published>2026-07-21T00:00:00Z</published>
    <content type="html">&lt;h3&gt;Added&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Browser-chat capture (opt-in MV3 extension).&lt;/strong&gt; Full-detail capture of
ChatGPT, Claude.ai, Perplexity, Gemini, and consumer Copilot web sessions
from Chrome (WSL + Windows) via a native-messaging bridge into the new
&lt;code&gt;browserchat&lt;/code&gt; adapter - prompts, responses, models, and estimated tokens,
with best-effort redaction and health telemetry (&lt;code&gt;observer browser health&lt;/code&gt;).
Load-unpacked only for now. See &lt;a href="docs/browser-extension.md"&gt;&lt;code&gt;docs/browser-extension.md&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Session attach: join and drive live sessions from the dashboard.&lt;/strong&gt;
Observer-launched &lt;code&gt;claude&lt;/code&gt;/&lt;code&gt;codex&lt;/code&gt; sessions are daemon-owned PTYs the
dashboard can now &lt;em&gt;join&lt;/em&gt; (&amp;quot;live · joinable&amp;quot; badge → Jump in), while your
native terminal stays fully interactive. Closed sessions gain one-click
native &lt;strong&gt;Resume&lt;/strong&gt; (&lt;code&gt;observer claude --resume &amp;lt;id&amp;gt;&lt;/code&gt; composed server-side)
from the session panel. Remote (paired-device) viewing of attach/resume
terminals stays deny-by-default behind the new &lt;code&gt;[remote].allow_terminal_view&lt;/code&gt;
read opt-in.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resilient default-on attach.&lt;/strong&gt; Interactive &lt;code&gt;observer claude&lt;/code&gt;/&lt;code&gt;observer codex&lt;/code&gt;
launches attach by default when the daemon is reachable
(&lt;code&gt;[terminal.attach].default_on&lt;/code&gt;, Settings-togglable; &lt;code&gt;--no-attach&lt;/code&gt; opts out
per launch). Graceful daemon restarts stamp a durable &lt;code&gt;end_reason&lt;/code&gt;
(migration 072) and the attach client offers prompt-with-timeout
auto-resume onto the same transcript; every skipped default-attach prints
an honest one-line reason.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Terminal Workspace dock grid.&lt;/strong&gt; The Terminals page is now a workspace:
an auto-compacting responsive grid of live terminals - drag tiles by their
header, resize from edges, add running sessions from the tray, &amp;quot;⊞ Add to
grid&amp;quot; directly on any floating terminal window, &amp;quot;⬈ Open as window&amp;quot; to
undock a tile back into a &lt;strong&gt;user-resizable, size-persisted floating
window&lt;/strong&gt;. Layouts persist server-side (node-local &lt;code&gt;workspace_layouts&lt;/code&gt;,
migration 073) and render read-only on paired remote devices. Honest close
semantics: &amp;quot;Remove from grid&amp;quot; keeps the session running; &amp;quot;Stop &amp;amp; close&amp;quot;
actually ends the process. &lt;code&gt;[terminal].max_concurrent&lt;/code&gt; default raised to 9.
Existing policy/status/history content lives under a Settings tab.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Standing-access hardening toggle.&lt;/strong&gt; Opt-in
&lt;code&gt;[remote].revoke_standing_on_takeover&lt;/code&gt;: a desktop takeover of a remote
writer that held control through the standing secret also revokes the
standing secret itself (identical teardown to the explicit revoke). Default
stays seamless - takeover revokes only the live lease.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Fixed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Daemon-down no longer breaks claude launches.&lt;/strong&gt; &lt;code&gt;observer init&lt;/code&gt; bakes the
proxy route into claude's own &lt;code&gt;settings.json&lt;/code&gt;, which outranks the process
environment - so a &amp;quot;bare&amp;quot; fallback launch used to route API calls into a
dead proxy. The launchers now resolve the &lt;em&gt;effective&lt;/em&gt; route across every
settings scope claude honors (managed/CLI/local/project/user, including
inline-JSON &lt;code&gt;--settings&lt;/code&gt; and &lt;code&gt;--continue-from&lt;/code&gt; working directories) and
neutralize observer routes with a one-shot CLI-scope &lt;code&gt;--settings&lt;/code&gt; override
(signal-safe temp file); un-overridable cases (managed scope, your own
&lt;code&gt;--settings&lt;/code&gt;, codex's config-file route) refuse with copy naming the exact
fix. Third-party gateway routes are always honored, never clobbered.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;quot;Stop &amp;amp; close&amp;quot; now actually stops the process.&lt;/strong&gt; Since detach-replay, a
websocket close only detached the embedded terminal; every stop control now
issues the explicit server-side reap.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mobile layout no longer breaks on long project paths.&lt;/strong&gt; One shared
tail-preserving truncation primitive (ellipsis at the head, leaf visible,
full path on hover) across all pages, plus explicit horizontal-scroll
containment on the Overview table.&lt;/li&gt;
&lt;li&gt;Terminal runs killed by a daemon shutdown no longer show as running forever
in the run history; floating-terminal resize no longer minimizes the window
on release.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v1.20.0 - 2026-07-17</title>
    <link href="https://superbased.app/docs/changelog#v1-20-0" rel="alternate"/>
    <id>https://superbased.app/docs/changelog#v1-20-0</id>
    <updated>2026-07-17T00:00:00Z</updated>
    <published>2026-07-17T00:00:00Z</published>
    <content type="html">&lt;h3&gt;Added&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Remote dashboard + terminal control (Phase 4, explicit opt-in).&lt;/strong&gt; Drive a
node from another device over your tailnet: multi-device pairing, a draggable
launch dock, in-dashboard terminals, and a mobile-friendly dashboard layout.
Remote &lt;strong&gt;execute&lt;/strong&gt; (launching AI tools / running terminal commands from the
dashboard) is gated behind an explicit standing grant
(&lt;code&gt;[remote].allow_standing_terminal_control&lt;/code&gt;, default off) with per-session
terminal leases, fanout bounds, revoked-lease handling, an execute-tier CSP,
and a full audit lifecycle. Tailnet-only; nothing is exposed to the public
internet. See &lt;a href="docs/remote-access.md"&gt;&lt;code&gt;docs/remote-access.md&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Process-network body capture + attribution wave.&lt;/strong&gt; For observed processes
routed through the proxy, capture proxied/plaintext request/response bodies
into the new &lt;code&gt;process_network_bodies&lt;/code&gt; store (agent migration 067) - never a
claim of TLS visibility. Broader process observation and attribution: five
adapters seed the pid bridge directly, a background attribution sweep and
per-wave basenames tighten which session a process belongs to, and the
dashboard gains process + raw-events surfaces. See
&lt;a href="docs/process-observability.md"&gt;&lt;code&gt;docs/process-observability.md&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPT-5.6 / OpenAI cache-write token capture.&lt;/strong&gt; The proxy now parses
&lt;code&gt;input_tokens_details.cache_write_tokens&lt;/code&gt; from OpenAI/Responses usage (both
the provider and streaming paths), nets cache-write against gross input
correctly, and feeds the cachetrack engine so implicit-write events are
observed instead of silently dropped. Wire field + expiry semantics
documented in &lt;code&gt;docs/general_info/openai_cache_expiry.md&lt;/code&gt; and
&lt;code&gt;docs/cache-tracking.md&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dashboard time-window dropdown.&lt;/strong&gt; A new date-range control adds &lt;strong&gt;1h / 12h /
1d&lt;/strong&gt; windows plus explicit custom ranges alongside the existing options,
resolving &lt;code&gt;since&lt;/code&gt;/&lt;code&gt;until&lt;/code&gt; with hours taking precedence over days. The range
params thread through every dashboard page.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Benchmark integrity: retry-as-attempt + ephemeral runs.&lt;/strong&gt; Each retry is now
recorded as its own attempt (agent migration 068) so benchmark integrity
reflects real attempt counts instead of collapsing retries. New ephemeral
runs execute without persisting into the main corpus.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compression: no-drop capability + honest lossy-eviction display.&lt;/strong&gt; A new
&lt;code&gt;disable_drops&lt;/code&gt; capability lets the &lt;code&gt;codex-safe&lt;/code&gt; recipe compress without lossy
content eviction. All lossy eviction now routes through one classifier owner,
and evicted bytes are &lt;strong&gt;subtracted&lt;/strong&gt; from reported compression savings so
&amp;quot;saved&amp;quot; reflects genuine, retrievable compression only - evicted content is
surfaced additively (still recoverable via &lt;code&gt;search_past_outputs&lt;/code&gt; markers,
never counted as a saving).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;M365 Copilot org analytics + browser-extension capture fixes.&lt;/strong&gt; New
&lt;code&gt;observer-org m365&lt;/code&gt; command and M365 Copilot analytics surface (Graph auth +
&lt;code&gt;surface_graph&lt;/code&gt;) on the org server - server-side only, never on the agent
wire. Browser-extension capture (native-messaging host + service worker + the
loopback ingest receiver) is fixed, with per-browser/per-OS host manifest
writers including Windows registry hostfiles.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;[dashboard].addr&lt;/code&gt; config knob (#8).&lt;/strong&gt; The dashboard bind address is now
configurable via &lt;code&gt;[dashboard].addr&lt;/code&gt; (and the &lt;code&gt;OBSERVER_DASHBOARD_ADDR&lt;/code&gt;
environment override).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kimi K3 model pricing&lt;/strong&gt; added to the cost engine and the settings surface.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Changed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Codex fork/subagent token de-duplication + session lineage.&lt;/strong&gt; Replayed
fork/subagent turns are now skipped so a forked Codex session no longer
double-counts tokens already attributed to its parent. New parent/child
session-lineage tracking (agent migration 069, surfaced in the session-detail
panel) makes the relationship explicit, and the new &lt;code&gt;--codex-fork-dedup&lt;/code&gt;
backfill pass reconciles historical fork double-counting.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Fixed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;VS Code extension activation stall (#5).&lt;/strong&gt; Fixed extension activation and
observer-binary resolution; a new &lt;code&gt;preferPathBinary&lt;/code&gt; setting lets the
extension use a &lt;code&gt;PATH&lt;/code&gt;-resolved observer instead of its bundled copy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Codex 16 MiB record limit (#7).&lt;/strong&gt; The Codex JSONL scanner's 16 MiB record
cap is replaced with a shared &lt;code&gt;readRecord&lt;/code&gt; (64 MiB bound + per-record skip) so
an oversized record no longer aborts a whole session parse.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prune now reclaims disk space.&lt;/strong&gt; &lt;code&gt;observer prune&lt;/code&gt; actually reclaims disk
instead of only shedding rows, and startup latency previously spent in
on-open integrity work is cut.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Upgrade notes&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Agent DB migrates to schema 69 (migrations 061-069); the org server stays at
schema 21 - both automatic.&lt;/li&gt;
&lt;li&gt;Restart the daemon via the safe order (route off → stop → relaunch → route
on; &lt;code&gt;scripts/restart-daemon.sh&lt;/code&gt;) so the new binary and migrations load.&lt;/li&gt;
&lt;li&gt;Remote execute + standing terminal control stay fully inert until you set
&lt;code&gt;[remote].allow_standing_terminal_control = true&lt;/code&gt;; pairing and remote viewing
are tailnet-only.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;observer backfill --codex-fork-dedup&lt;/code&gt; (or &lt;code&gt;observer backfill --all&lt;/code&gt;) to
reconcile historical Codex fork double-counting.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v1.19.0 - 2026-07-11</title>
    <link href="https://superbased.app/docs/changelog#v1-19-0" rel="alternate"/>
    <id>https://superbased.app/docs/changelog#v1-19-0</id>
    <updated>2026-07-11T00:00:00Z</updated>
    <published>2026-07-11T00:00:00Z</published>
    <content type="html">&lt;h3&gt;Added&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Email notifications.&lt;/strong&gt; New &lt;code&gt;[email]&lt;/code&gt; config block (stdlib SMTP:
STARTTLS/implicit-TLS, AUTH PLAIN/LOGIN; default &lt;strong&gt;off&lt;/strong&gt;, fail-soft -
a delivery failure never affects evaluation). Rides the existing alert
evaluators: org budget alerts, org obs-alert rules, and node-side
&lt;code&gt;[observability.alerts]&lt;/code&gt;. See &lt;code&gt;docs/email-notifications.md&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scheduled cost digests.&lt;/strong&gt; Weekly/monthly digest emails on both the node
(&lt;code&gt;[digest]&lt;/code&gt;) and the org server: period spend, per-model/per-project (org:
per-developer) breakdowns, movers vs prior period. Restart-safe send-once
de-dup via the new &lt;code&gt;digest_state&lt;/code&gt; table (agent migration 060, server
migration 021). Test on demand with &lt;code&gt;observer digest send --dry-run&lt;/code&gt; /
&lt;code&gt;observer-org digest send --dry-run&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Shareable cost card.&lt;/strong&gt; &lt;code&gt;observer report share [--period week|month] [--markdown]&lt;/code&gt; renders a 1200×630 SVG social card + markdown summary of your
observed spend (period total, cache-read share, model/tool leaderboards).
Aggregates only - project names/paths never appear (pinned by test). No
network.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Admin dashboard (web2) onboarding &amp;amp; navigation.&lt;/strong&gt; First-run checklist for
a fresh org server, command-palette &lt;strong&gt;data search&lt;/strong&gt; (teams / projects /
people / recent sessions), teaching empty states across pages, breadcrumbs
on detail routes, and sidebar count badges.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Plane-A general-observability upgrades.&lt;/strong&gt; web2 &lt;strong&gt;Admission center&lt;/strong&gt;
(&lt;code&gt;/trajectories/admission&lt;/code&gt;, read-only policy viewer) + &lt;strong&gt;T6 admission
org-wire tier&lt;/strong&gt; (&lt;code&gt;[org_client.share.obs].admission&lt;/code&gt;, default off; server
migration 019) with audited deep reads; &lt;strong&gt;T7 per-item eval tier&lt;/strong&gt;
(&lt;code&gt;.eval_items&lt;/code&gt;, server migration 020) with per-item EvalRun detail and
run-vs-run compare; &lt;strong&gt;per-end-user spend page&lt;/strong&gt;; node-side &lt;strong&gt;alert
evaluation for share-off deployments&lt;/strong&gt; (&lt;code&gt;[observability.alerts]&lt;/code&gt;, default
off); LLM-judge robustness (map-reduce chunking, per-criterion prompts,
hardened client) + &lt;code&gt;observer obs admission verify&lt;/code&gt;; SDKs attach
prompt/response content by default (&lt;code&gt;OBSERVER_CAPTURE_CONTENT=0&lt;/code&gt; to
disable) and target the correct node port &lt;code&gt;:8081&lt;/code&gt;; &lt;code&gt;POST /policy?persist=1&lt;/code&gt;
write-through.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;M365 Copilot org-tier connector&lt;/strong&gt; (server-side native-console poller,
server migration 018; never on the agent wire).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Browser-chatbot capture extension (preview).&lt;/strong&gt; Opt-in MV3 extension
capturing ChatGPT / Claude.ai / Perplexity / Gemini / consumer-Copilot web
chats via a native-messaging bridge (&lt;code&gt;observer browser hook&lt;/code&gt;). Load-unpacked
only for now - &lt;strong&gt;not yet published to the Chrome Web Store&lt;/strong&gt;; all token
counts are estimates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Website.&lt;/strong&gt; Text-first, fully indexable homepage (the Observer Quest
arcade lives on at &lt;code&gt;/arcade&lt;/code&gt;); product deck at &lt;code&gt;/deck&lt;/code&gt; with a downloadable
PDF; 28 per-tool &amp;quot;track &lt;!-- raw HTML omitted --&gt; costs&amp;quot; pages generated from the adapter
registry; 6 comparison pages; 21-term glossary; a public two-planes
explainer; &lt;code&gt;llms.txt&lt;/code&gt; + JSON-LD + an explicit GEO robots posture
(retrieval crawlers allowed, training crawlers opted out).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Changed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;READMEs and store listings overhauled&lt;/strong&gt; around the durable story:
proxy-accurate billed-token attribution, local-first privacy, free node →
team layer. One true adapter count (26) everywhere; npm/PyPI/VS Code
listing descriptions rewritten; MCP tool census corrected to 25 (21
always-on + 4 conditional) and &lt;code&gt;docs/mcp-tools.md&lt;/code&gt; fully rewritten.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Org-server retention is now enforced.&lt;/strong&gt; &lt;code&gt;server.data_retention_days&lt;/code&gt;
(default 730) actively prunes: &lt;strong&gt;upgraded org servers begin deleting
rows older than the configured window&lt;/strong&gt; (identity/config/audit/guard-chain
tables are never pruned). Set the knob before upgrading if you need longer
retention.&lt;/li&gt;
&lt;li&gt;Guard alerting (desktop toasts, Slack/Discord/PagerDuty webhooks) and
process observability are now documented on the main surfaces.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Fixed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;VS Code walkthrough listed a nonexistent &amp;quot;Continue&amp;quot; adapter; stale
&amp;quot;seventeen tools&amp;quot; counts across README/website/listings; dead help entries
in the node dashboard; org migrate-test schema assertion; a date-dependent
test (&lt;code&gt;TestAggregateForOrg&lt;/code&gt;) that failed once its hardcoded day aged out.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Upgrade notes&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Agent DB migrates to schema 60; org server to 21 - both automatic.&lt;/li&gt;
&lt;li&gt;Restart the daemon via the safe order (route off → stop → relaunch →
route on; &lt;code&gt;scripts/restart-daemon.sh&lt;/code&gt;) so the new binary and migrations
load.&lt;/li&gt;
&lt;li&gt;Email/digests stay inert until you set &lt;code&gt;[email].enabled = true&lt;/code&gt; plus the
per-consumer opt-ins.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v1.18.0 - 2026-07-10</title>
    <link href="https://superbased.app/docs/changelog#v1-18-0" rel="alternate"/>
    <id>https://superbased.app/docs/changelog#v1-18-0</id>
    <updated>2026-07-10T00:00:00Z</updated>
    <published>2026-07-10T00:00:00Z</published>
    <content type="html">&lt;h3&gt;Added&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;observer devin --continue-from&lt;/code&gt; launcher.&lt;/strong&gt; Devin CLI joins the
session-handoff launchers: &lt;code&gt;observer devin --continue-from &amp;lt;session-id&amp;gt;&lt;/code&gt;
distills a handover and seeds it as Devin's first prompt. Devin takes its
prompt as a clap last-only positional after the &lt;code&gt;--&lt;/code&gt; separator
(&lt;code&gt;devin -- &amp;quot;&amp;lt;prompt&amp;gt;&amp;quot;&lt;/code&gt;, operator-verified on a real TTY), so the launcher
uses a new &lt;code&gt;injectTrailingPositionalAfterDashDash&lt;/code&gt; inject kind. The launch is
seed-only and &lt;strong&gt;non-proxied&lt;/strong&gt; (Cognition backend, &lt;code&gt;native_exempt&lt;/code&gt;, no
base-URL knob); &lt;code&gt;child.Dir&lt;/code&gt; is threaded from the continue-from cwd per the
cross-OS handoff contract. The launchable set grows to &lt;strong&gt;19 launchers&lt;/strong&gt;
(&lt;strong&gt;17 Seeded&lt;/strong&gt; + 2 DocAssisted); the Devin registry row gains &lt;code&gt;InjectPrompt&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Launch&lt;/code&gt; and drops its unverified-seed caveat.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Changed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;qwen-code&lt;/code&gt; promoted to a live, observer-driven proxy route.&lt;/strong&gt; qwen-code
resolves its active model by the &lt;code&gt;(id, baseUrl)&lt;/code&gt; pair, so rewriting
&lt;code&gt;model.baseUrl&lt;/code&gt; alone was ignored when it matched no &lt;code&gt;modelProviders&lt;/code&gt; entry -
the grounded 2026-07-09 probe failure (qwen fell back to &lt;code&gt;api.openai.com&lt;/code&gt; and
bypassed the proxy). &lt;code&gt;RegisterQwenCode&lt;/code&gt; now &lt;strong&gt;also retargets every OpenAI-lane
&lt;code&gt;modelProviders&lt;/code&gt; entry on the known default host&lt;/strong&gt; to the proxy URL, keeping
each entry's &lt;code&gt;id&lt;/code&gt; + &lt;code&gt;envKey&lt;/code&gt; untouched, tolerating both live schema shapes
(array + object form), and synthesizing an entry only when none matched (same
guard matrix: refuse-foreign-URL, idempotent, &lt;code&gt;.bak&lt;/code&gt;, temp+rename,
ConfigMissing skip; API keys never touched). Live-verified 2026-07-09: a
&lt;code&gt;qwen -p&lt;/code&gt; turn through &lt;code&gt;:8820&lt;/code&gt; landed &lt;code&gt;api_turns&lt;/code&gt; 23728-23730 (gpt-4o,
&lt;code&gt;provider=openai&lt;/code&gt;). The registry row is promoted to &lt;code&gt;routable_now&lt;/code&gt; with an
observer-driven &lt;strong&gt;Proxy&lt;/strong&gt; route; &lt;code&gt;ProxyProbe&lt;/code&gt; is KEPT - it remains the
persistent config-lane writer &lt;code&gt;observer init&lt;/code&gt; dispatches on.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPT-5.6 cache/effort grounding closed against live traffic.&lt;/strong&gt; A live
gpt-5.6 session (&lt;code&gt;019f4801&lt;/code&gt;) confirms the launch pricing: the model ids
&lt;code&gt;gpt-5.6-{sol,terra}&lt;/code&gt; hit their pricing rows exactly and a live terra turn
recomputes to the stored cost to the digit; no effort levels beyond
low/medium/high manifested. &lt;strong&gt;NO cache-write usage field exists on the Codex
wire&lt;/strong&gt; - only &lt;code&gt;cached_input_tokens&lt;/code&gt; (read discount). OpenAI docs confirm the
write tier we priced (1.25× uncached input, 90% read discount, 30-min minimum
TTL, explicit-breakpoint mode), but Codex's ChatGPT-plan credit formula has no
write term, which is why the field never appears on our wire. The shipped
write-tier pricing therefore stays &lt;strong&gt;present-but-dormant and harmless&lt;/strong&gt;, and
parsing a &lt;code&gt;cache_write_tokens&lt;/code&gt; field is deliberately DEFERRED until the
netting semantics can be arithmetic-grounded on live traffic - additive
billing without grounding would repeat the reasoning-double-bill trap.
&lt;code&gt;docs/cache-tracking.md&lt;/code&gt; gained a GPT-5.6 cache-expiry subsection.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Fixed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Codex reasoning tokens were double-billed.&lt;/strong&gt; The OpenAI/Codex wire reports
&lt;strong&gt;GROSS&lt;/strong&gt; &lt;code&gt;output_tokens&lt;/code&gt; with reasoning as a &lt;strong&gt;subset&lt;/strong&gt; (&lt;code&gt;input + output == total&lt;/code&gt; on every live &lt;code&gt;token_count&lt;/code&gt; event - arithmetic-verified on gpt-5.6
traffic). The codex adapter emitted that gross value alongside
&lt;code&gt;ReasoningTokens&lt;/code&gt;, and the cost engine's additive reasoning-at-output-rate
rule then billed every codex reasoning token twice. The adapter now nets
reasoning out at both emit sites (clamped ≥ 0, mirroring the &lt;code&gt;netInput&lt;/code&gt;
pattern), and &lt;code&gt;TokenBundle.Reasoning&lt;/code&gt; gained a hard documented precondition:
netting is a &lt;strong&gt;per-wire property&lt;/strong&gt; - OpenAI/Codex fold reasoning into output
(subset), whereas gemini/antigravity report it disjoint (the additive rule is
correct only for disjoint wires). &lt;strong&gt;Migration 058 corrects the stored history
one-shot&lt;/strong&gt; (1,991 gross codex rows / 436k double-billed reasoning tokens on
the reference node): historical rows are corrected automatically at the first
startup of the upgraded binary, because a rescan cannot lower counts past the
&lt;code&gt;ON CONFLICT&lt;/code&gt; MAX-upgrade and the run-once ordering makes the subtraction
idempotent by construction. Scoped to &lt;code&gt;tool='codex'&lt;/code&gt; only -
gemini/antigravity are disjoint-correct.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;grok ACP update content was dropped when polymorphic.&lt;/strong&gt; &lt;code&gt;tool_call_update&lt;/code&gt;
content arrives as an &lt;strong&gt;array&lt;/strong&gt; of text/diff blocks (and &lt;code&gt;rawOutput.output&lt;/code&gt;
as a byte array); the single-object decode dropped 38 records across the two
fresh captures. &lt;code&gt;search_replace&lt;/code&gt; (grok's in-place edit) was also unmapped and
landed as &lt;code&gt;unknown&lt;/code&gt;; it now maps to &lt;code&gt;edit_file&lt;/code&gt; (with defensive
&lt;code&gt;deletefile&lt;/code&gt;/&lt;code&gt;removefile&lt;/code&gt; handling - grok exposes no distinct delete tool).
Rescan: warnings 38 → 0, unknown 2 → 0.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adapter rescans now reclassify &lt;code&gt;action_type&lt;/code&gt; from the &lt;code&gt;unknown&lt;/code&gt; sentinel.&lt;/strong&gt;
&lt;code&gt;insertActionSQL&lt;/code&gt;'s &lt;code&gt;ON CONFLICT&lt;/code&gt; clause never refreshed &lt;code&gt;action_type&lt;/code&gt;, so a
rescan (&lt;code&gt;observer scan --force&lt;/code&gt;) could not reclassify rows stored as
&lt;code&gt;unknown&lt;/code&gt; before a mapping fix landed - which blocked the grok
&lt;code&gt;search_replace&lt;/code&gt; fix above from healing the two live &lt;code&gt;unknown&lt;/code&gt; rows. The
conflict clause now upgrades &lt;strong&gt;only&lt;/strong&gt; &lt;code&gt;unknown&lt;/code&gt; → a real type; it never
rewrites one known type to another and never downgrades to &lt;code&gt;unknown&lt;/code&gt;/empty
(all three invariants pinned by table-driven tests).&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v1.17.0 - 2026-07-09</title>
    <link href="https://superbased.app/docs/changelog#v1-17-0" rel="alternate"/>
    <id>https://superbased.app/docs/changelog#v1-17-0</id>
    <updated>2026-07-09T00:00:00Z</updated>
    <published>2026-07-09T00:00:00Z</published>
    <content type="html">&lt;h3&gt;Added&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Nine new tool adapters - the 10-tool adapter wave&lt;/strong&gt; (freebuff descoped).
Observer now captures &lt;strong&gt;26 adapters&lt;/strong&gt; total. Each new adapter ships with a
testdata fixture, an operator doc, an integration-registry row, a dashboard
tool color, and a &lt;code&gt;docs/cross-adapter-schema-mapping.md&lt;/code&gt; section (§3.11-3.19):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;qwen-code&lt;/code&gt;&lt;/strong&gt; - Qwen Code CLI (Gemini-CLI fork), Claude-Code-shaped JSONL
under &lt;code&gt;~/.qwen&lt;/code&gt;; GROSS input netted against cached.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;kiro-cli&lt;/code&gt;&lt;/strong&gt; - AWS Kiro CLI; mode-dependent dual store (interactive flat
bundles vs &lt;code&gt;--no-interactive&lt;/code&gt; SQLite &lt;code&gt;conversations_v2&lt;/code&gt; keyed by the RAW
cwd, translated through crossmount); SigV4, native-exempt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;crush&lt;/code&gt;&lt;/strong&gt; - Charmbracelet Crush; project-local &lt;code&gt;.crush/crush.db&lt;/code&gt;
discovered via &lt;code&gt;projects.json&lt;/code&gt;; Unix-SECONDS timestamps.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;kimi-code&lt;/code&gt;&lt;/strong&gt; - Moonshot Kimi CLI; &lt;code&gt;wire.jsonl&lt;/code&gt; &lt;code&gt;usage.record&lt;/code&gt;
(&lt;code&gt;inputOther&lt;/code&gt; is already NET); no seed lane (DocAssisted only).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;grok&lt;/code&gt;&lt;/strong&gt; - xAI Grok CLI; 8-file ACP session bundles, with per-request
token splits pulled from the GLOBAL &lt;code&gt;~/.grok/logs/unified.jsonl&lt;/code&gt;
correlated by &lt;code&gt;sid&lt;/code&gt; (no timestamp heuristics).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;devin&lt;/code&gt;&lt;/strong&gt; - Devin CLI; SQLite &lt;code&gt;message_nodes&lt;/code&gt; TREE walked along
&lt;code&gt;main_chain_id&lt;/code&gt; to dedupe regeneration branches so tokens never
double-count; per-message &lt;code&gt;metadata.metrics&lt;/code&gt; tokens.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;aider&lt;/code&gt;&lt;/strong&gt; - Aider; per-repo &lt;code&gt;.aider.chat.history.md&lt;/code&gt; Markdown, with watch
roots = discovered transcript FILE paths (a bounded breadth-first
native-home walk memoized once per process); prose tokens GROSS→netted.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;qoder&lt;/code&gt;&lt;/strong&gt; - Alibaba Qoder CLI; Claude-Code-shaped JSONL under
&lt;code&gt;~/.qoder/projects&lt;/code&gt;; NO local model or tokens (server-side only -
honest-zero, native-exempt).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;goose&lt;/code&gt;&lt;/strong&gt; - Block Goose; WAL SQLite &lt;code&gt;sessions.db&lt;/code&gt; with SESSION-level
tokens only (&lt;code&gt;accumulated_*&lt;/code&gt; + &lt;code&gt;accumulated_cost&lt;/code&gt;); input GROSS→netted vs
&lt;code&gt;cache_read&lt;/code&gt;; &lt;code&gt;SessionID&lt;/code&gt; is store-scoped (&lt;code&gt;&amp;lt;id&amp;gt;@&amp;lt;sha8(store)&amp;gt;&lt;/code&gt;) so the
&lt;code&gt;YYYYMMDD_seq&lt;/code&gt; ids can't collide across a WSL + Windows store pair.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Fresh installs pick all nine up automatically; an EXPLICIT &lt;code&gt;enabled_adapters&lt;/code&gt;
list must add the new tool names (&lt;code&gt;qwen-code&lt;/code&gt;, &lt;code&gt;kiro-cli&lt;/code&gt;, &lt;code&gt;crush&lt;/code&gt;,
&lt;code&gt;kimi-code&lt;/code&gt;, &lt;code&gt;grok&lt;/code&gt;, &lt;code&gt;devin&lt;/code&gt;, &lt;code&gt;aider&lt;/code&gt;, &lt;code&gt;qoder&lt;/code&gt;, &lt;code&gt;goose&lt;/code&gt;) - the startup WARN
names any that are missing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Seeded session-handoff launchers for the new adapters&lt;/strong&gt; - &lt;code&gt;observer qwen&lt;/code&gt;,
&lt;code&gt;observer kiro&lt;/code&gt;, &lt;code&gt;observer kimi&lt;/code&gt;, &lt;code&gt;observer grok&lt;/code&gt;, &lt;code&gt;observer qoder&lt;/code&gt;, and
&lt;code&gt;observer goose&lt;/code&gt; accept &lt;code&gt;--continue-from &amp;lt;session-id&amp;gt;&lt;/code&gt; to distill a handover
and seed it as the tool's first prompt (&lt;strong&gt;18 launchers total&lt;/strong&gt;). &lt;code&gt;qwen&lt;/code&gt;,
&lt;code&gt;kiro&lt;/code&gt;, &lt;code&gt;grok&lt;/code&gt;, &lt;code&gt;qoder&lt;/code&gt;, and &lt;code&gt;goose&lt;/code&gt; seed directly; &lt;code&gt;kimi&lt;/code&gt; is DocAssisted
(no &lt;code&gt;-p&lt;/code&gt; seed lane). &lt;code&gt;devin&lt;/code&gt;, &lt;code&gt;aider&lt;/code&gt;, and &lt;code&gt;crush&lt;/code&gt; deliberately ship no
launcher (no scriptable seed lane).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The watcher and adapter registry now accept a FILE as a watch root&lt;/strong&gt;
(not only a directory), which the &lt;code&gt;aider&lt;/code&gt; adapter needs for its per-repo
transcript-file watch set.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Guarded proxy-route config-lane writers&lt;/strong&gt; - &lt;code&gt;internal/proxyroute&lt;/code&gt; gained
&lt;code&gt;RegisterKimiCode&lt;/code&gt; (TOML &lt;code&gt;base_url&lt;/code&gt; in &lt;code&gt;~/.kimi-code/config.toml&lt;/code&gt;),
&lt;code&gt;RegisterCrush&lt;/code&gt; (JSON map-merge in &lt;code&gt;crush.json&lt;/code&gt;), and &lt;code&gt;RegisterQwenCode&lt;/code&gt;
(rewrites &lt;code&gt;~/.qwen/settings.json&lt;/code&gt; &lt;code&gt;model.baseUrl&lt;/code&gt;, stricter guard: refuses
any custom host). Each backs up (&lt;code&gt;.bak&lt;/code&gt;) and writes via temp/rename, skips
benignly when the config is missing, is idempotent when already observer,
and refuses a foreign URL; API keys are never touched. A new additive
registry field &lt;code&gt;Capability.ProxyProbe&lt;/code&gt; marks &amp;quot;writer ready, promotion
pending a live probe&amp;quot;; these writers fire ONLY through &lt;code&gt;observer init&lt;/code&gt; -
batch under &lt;code&gt;--all&lt;/code&gt; (honoring &lt;code&gt;--skip-proxy-route&lt;/code&gt;), or one per-tool consent
prompt in the interactive checklist (default NO). ⚠️ Once a tool is routed,
stopping the daemon breaks it until reverted (the standard routed-tool
caveat - see the daemon-restart runbook).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Per-adapter Backfill scan modes in the dashboard&lt;/strong&gt; - Settings → Backfill
now derives one &lt;code&gt;scan-&amp;lt;tool&amp;gt;&lt;/code&gt; row per integration-registry adapter (26 rows),
backed by the generic &lt;code&gt;observer scan --force --adapter &amp;lt;tool&amp;gt;&lt;/code&gt; lane
(idempotent; overrides &lt;code&gt;enabled_adapters&lt;/code&gt; for the run). A future adapter's
Backfill row appears automatically.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pricing: GPT-5.6 and Grok 4.5 model launches.&lt;/strong&gt; Added &lt;code&gt;gpt-5.6-sol&lt;/code&gt;
($5/$30), &lt;code&gt;gpt-5.6-terra&lt;/code&gt; ($2.50 in / $15 out at launch), &lt;code&gt;gpt-5.6-luna&lt;/code&gt;
($1 in / $6 out at launch; OpenAI cut Terra and Luna prices on 2026-07-30 -
the current table reflects the cut), and a
&lt;code&gt;gpt-5.6&lt;/code&gt; family row. GPT-5.6 introduces the &lt;strong&gt;first non-Anthropic explicit
cache-write tier&lt;/strong&gt; (writes at 1.25× uncached input, reads keep the 90%
discount); the write rate is wired into the cost table but INERT until a live
5.6 response grounds the cache-write usage field. Added &lt;code&gt;grok-4.5&lt;/code&gt; ($2/$6,
the new xAI flagship - previously under-billed via the &lt;code&gt;grok&lt;/code&gt; family row at
4.3 rates) and &lt;code&gt;grok-build-0.1&lt;/code&gt; / &lt;code&gt;grok-build&lt;/code&gt; ($1/$2); bumped the &lt;code&gt;grok&lt;/code&gt;
family prefix to flagship rates. &lt;code&gt;docs/pricing-reference.md&lt;/code&gt; updated.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Changed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Adapter routability promotions.&lt;/strong&gt; &lt;code&gt;aider&lt;/code&gt;, &lt;code&gt;goose&lt;/code&gt;, and &lt;code&gt;grok&lt;/code&gt; were
live-grounded through the &lt;code&gt;:8820&lt;/code&gt; proxy and promoted to &lt;code&gt;routable_now&lt;/code&gt;
(observer drives no route today; the launchers stay non-proxied).
&lt;code&gt;kimi-code&lt;/code&gt; and &lt;code&gt;crush&lt;/code&gt; were promoted further to observer-driven &lt;strong&gt;Proxy&lt;/strong&gt;
routes after live turns landed &lt;code&gt;api_turns&lt;/code&gt; rows through their config-lane
writers. &lt;code&gt;qwen-code&lt;/code&gt; stays route-blocked - its (empty) &lt;code&gt;modelProviders&lt;/code&gt; map
overrides &lt;code&gt;model.baseUrl&lt;/code&gt;, so the env/base-URL lanes are grounded-dead and
the writer needs a matching provider entry first.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dashboard tool-identity colors&lt;/strong&gt; for the 10 previously-uncolored adapters
(light + dark tokens, CVD-validated), plus the missing &lt;code&gt;tools.ts&lt;/code&gt; entries.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Fixed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Actions page window selector was a no-op.&lt;/strong&gt; The 7d/14d/30d window computed
&lt;code&gt;windowDays&lt;/code&gt; but never passed it to &lt;code&gt;/api/actions&lt;/code&gt; (only the Timeline
day-counts honored it). &lt;code&gt;/api/actions&lt;/code&gt; gained the same optional &lt;code&gt;days&lt;/code&gt;
contract as &lt;code&gt;/api/sessions&lt;/code&gt; (0 = unwindowed; legacy callers unchanged) and
the page now threads the selected window.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;antigravity-cli cross-OS + guard coverage.&lt;/strong&gt; Added the antigravity-cli
cross-OS project-root anchors and its guard watcher-conformance row.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v1.16.0 - 2026-07-07</title>
    <link href="https://superbased.app/docs/changelog#v1-16-0" rel="alternate"/>
    <id>https://superbased.app/docs/changelog#v1-16-0</id>
    <updated>2026-07-07T00:00:00Z</updated>
    <published>2026-07-07T00:00:00Z</published>
    <content type="html">&lt;h3&gt;Added&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Richer session-handoff content&lt;/strong&gt; - two complementary &amp;quot;full&amp;quot; carry modes.
&lt;code&gt;full&lt;/code&gt; carries the excerpted flow plus a &lt;code&gt;[msg &amp;lt;id&amp;gt;]&lt;/code&gt; tag on every message
and an MCP-hint line; a target with the Observer MCP pulls any full body on
demand via the new &lt;strong&gt;&lt;code&gt;get_session_message&lt;/code&gt;&lt;/strong&gt; tool (always-on MCP tool count
19 → 20), which re-reads ONE un-excerpted message by
&lt;code&gt;(session_id, message_id|index)&lt;/code&gt; from the source transcript and never
persists it. &lt;code&gt;full_cache&lt;/code&gt; inlines the un-excerpted read/tool bodies INTO the
handover doc so the new session starts warm with zero MCP round-trips (uses
the &lt;code&gt;FullTranscriptReader&lt;/code&gt; capability - claude-code + codex; other tools
degrade to &lt;code&gt;full&lt;/code&gt; with a stated reason), size-capped by
&lt;code&gt;[handoff] max_cache_bytes&lt;/code&gt; (8 MB default). &lt;code&gt;models.TranscriptMessage&lt;/code&gt; gained
an &lt;code&gt;ID&lt;/code&gt; lifted from each source format's own record id where grounded.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Antigravity CLI (&lt;code&gt;agy&lt;/code&gt;) adapter&lt;/strong&gt; - the newer Antigravity CLI is now a
first-class, separately-tagged adapter (&lt;code&gt;antigravity-cli&lt;/code&gt;):
plaintext-protobuf SQLite &lt;code&gt;.db&lt;/code&gt; conversations parsed directly, &lt;code&gt;.pb&lt;/code&gt;
conversations via the existing transcript fallback, name-gated so the desktop
and CLI layouts each claim only their own files, with
&lt;code&gt;observer backfill --antigravity-cli-rescan&lt;/code&gt; and an integration-registry row.
Add &lt;code&gt;&amp;quot;antigravity-cli&amp;quot;&lt;/code&gt; to an explicit &lt;code&gt;enabled_adapters&lt;/code&gt; list to enable it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;observer antigravity-cli&lt;/code&gt; handoff launcher&lt;/strong&gt; (aliases &lt;code&gt;antigravity&lt;/code&gt;,
&lt;code&gt;agy&lt;/code&gt;) - &lt;code&gt;--continue-from&lt;/code&gt; distills a handover and seeds it via &lt;code&gt;agy -i&lt;/code&gt;
(non-proxied).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Community links&lt;/strong&gt; surfaced in the dashboard Settings page and the
&lt;code&gt;observer init&lt;/code&gt; footer.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Changed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Obs share flags nested under &lt;code&gt;[org_client.share.obs]&lt;/code&gt;; the dashboard Settings
Observability section is now plane-tagged (Plane A admin vs Plane B
developer) for legibility.&lt;/li&gt;
&lt;li&gt;Website download counter refreshed (npm 14,893 / PyPI 9,242).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Fixed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Antigravity CLI sessions are now tagged &lt;code&gt;antigravity-cli&lt;/code&gt; instead of blending
into the desktop &lt;code&gt;antigravity&lt;/code&gt; tool - the parse helpers hardcoded the tool
constant; &lt;code&gt;ParseSessionFile&lt;/code&gt; now re-tags every event to the adapter's own
name at the boundary.&lt;/li&gt;
&lt;li&gt;MCP &lt;code&gt;observer serve&lt;/code&gt; skips the SQLite &lt;code&gt;quick_check&lt;/code&gt; so a large DB can't blow
the init timeout.&lt;/li&gt;
&lt;li&gt;Session handoff resolves a foreign-OS project root for the doc + launch cwd
(cross-OS WSL case).&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v1.15.0 - 2026-07-06</title>
    <link href="https://superbased.app/docs/changelog#v1-15-0" rel="alternate"/>
    <id>https://superbased.app/docs/changelog#v1-15-0</id>
    <updated>2026-07-06T00:00:00Z</updated>
    <published>2026-07-06T00:00:00Z</published>
    <content type="html">&lt;h3&gt;Added&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Session Handoff (continue-anywhere)&lt;/strong&gt; - &lt;code&gt;observer handoff &amp;lt;session-id&amp;gt; [--to &amp;lt;tool&amp;gt;]&lt;/code&gt; distills any captured session from the source tool's OWN
transcript files into a scrubbed &lt;code&gt;HANDOFF-&amp;lt;id&amp;gt;.md&lt;/code&gt; 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
(&lt;code&gt;observer handoff&lt;/code&gt;, &lt;code&gt;handoff list&lt;/code&gt;), dashboard session-detail
&amp;quot;Continue in…&amp;quot; modal with fork picker
(&lt;code&gt;GET /api/session/&amp;lt;id&amp;gt;/handoff/estimate&lt;/code&gt; + &lt;code&gt;POST /api/session/&amp;lt;id&amp;gt;/handoff&lt;/code&gt;),
MCP &lt;code&gt;continue_session&lt;/code&gt; (tool count 19 → 20). Transcript readers:
claude-code, codex, cursor, cline, cline-cli, hermes, opencode. Node-local
&lt;code&gt;handoffs&lt;/code&gt; table (migration 055) stores counts/enums/hashes only - never
the doc. Docs: &lt;code&gt;docs/session-handoff.md&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Session Handoff - dashboard &amp;quot;Launch &lt;code&gt;&amp;lt;tool&amp;gt;&lt;/code&gt; here&amp;quot; (embedded web
terminal).&lt;/strong&gt; 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
&lt;code&gt;observer &amp;lt;tool&amp;gt; --continue-from &amp;lt;id&amp;gt;&lt;/code&gt; in a PTY inside its own OS and
streams the TUI into an xterm.js panel over a &lt;code&gt;/ws/launch/&amp;lt;handle&amp;gt;&lt;/code&gt;
websocket - working uniformly local, remote, or WSL-daemon/Windows-browser
(no cross-OS shell). New pure-logic &lt;code&gt;internal/termsession&lt;/code&gt; (PTY session
registry behind an injected spawner; process-group reaping on unix,
concurrent cap + idle reaper) and the &lt;code&gt;HandoffCapability.Launch&lt;/code&gt; registry
field. Server-derived argv only; CSWSH-defended (256-bit &lt;code&gt;crypto/rand&lt;/code&gt;
handle minted only by the Origin-checked &lt;code&gt;POST /api/session/&amp;lt;id&amp;gt;/launch&lt;/code&gt;,
plus &lt;code&gt;coder/websocket&lt;/code&gt; cross-origin rejection). On by default, kill-switch
&lt;code&gt;[handoff].allow_dashboard_launch&lt;/code&gt;. &lt;code&gt;GET /api/launch/sessions&lt;/code&gt; +
&lt;code&gt;DELETE /api/launch/&amp;lt;handle&amp;gt;&lt;/code&gt; for the live-session list. Unix-only PTY
backend (native-Windows daemon reports unsupported → run under WSL). Docs:
&lt;code&gt;docs/session-handoff.md&lt;/code&gt; (Launch here), &lt;code&gt;docs/security.md&lt;/code&gt; ledger.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Session Handoff - armed hook delivery (&lt;code&gt;--deliver hook&lt;/code&gt;, claude-code).&lt;/strong&gt;
&lt;code&gt;observer handoff &amp;lt;id&amp;gt; --to claude-code --deliver hook&lt;/code&gt; arms the handover
for the NEXT claude-code session in the project: it injects as SessionStart
&lt;code&gt;additionalContext&lt;/code&gt; (same seam as the advisor digest), one-shot, expiring
after &lt;code&gt;[handoff] hook_ttl_minutes&lt;/code&gt; (default 240). The payload is hard-
budgeted to &lt;code&gt;[handoff] hook_max_bytes&lt;/code&gt; (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 &lt;code&gt;HANDOFF-*.md&lt;/code&gt;. Doc content stays on disk; the
&lt;code&gt;handoffs&lt;/code&gt; row (migration 056: &lt;code&gt;hook_expires_at&lt;/code&gt; / &lt;code&gt;hook_delivered_at&lt;/code&gt; /
&lt;code&gt;project_root&lt;/code&gt;) records only the arming window and file path. The claim is
a single guarded &lt;code&gt;UPDATE … RETURNING&lt;/code&gt; (race-safe). Delivery dispatches on
the target's &lt;code&gt;integration.HandoffCapability&lt;/code&gt; inject set - only claude-code
declares &lt;code&gt;inject_hook&lt;/code&gt;; other tools error honestly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Session Handoff - launcher &lt;code&gt;--continue-from&lt;/code&gt; (prompt delivery).&lt;/strong&gt;
&lt;code&gt;observer claude --continue-from &amp;lt;session-id&amp;gt;&lt;/code&gt; and
&lt;code&gt;observer codex --continue-from &amp;lt;session-id&amp;gt;&lt;/code&gt; run the handoff for the
launcher's OWN tool (delivery &lt;code&gt;inject_prompt&lt;/code&gt;) and seed the rendered
handover as the tool's first user prompt before exec'ing it - no
copy/paste. Mirrors &lt;code&gt;observer handoff&lt;/code&gt; flags (&lt;code&gt;--carry&lt;/code&gt;, &lt;code&gt;--from-message&lt;/code&gt;,
&lt;code&gt;--from-time&lt;/code&gt;; default fork = last message). claude gets the doc prepended
as its leading positional prompt, codex appended as the trailing positional
(TUI + &lt;code&gt;exec&lt;/code&gt;); forwarding your own positional prompt errors honestly (two
prompts - forward value-flags as &lt;code&gt;--flag=value&lt;/code&gt;). Handovers over 100KB
degrade to a marker-carrying pointer prompt (the full doc is on disk). The
&lt;code&gt;observer handoff … --to claude-code|codex&lt;/code&gt; output now prints a
&lt;code&gt;--continue-from&lt;/code&gt; tip. Delivery still dispatches on the target's
&lt;code&gt;integration.HandoffCapability&lt;/code&gt; - a prompt handoff to a tool without the
lane errors honestly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Session Handoff - &lt;code&gt;--continue-from&lt;/code&gt; extended to &lt;code&gt;observer gemini&lt;/code&gt; and
&lt;code&gt;observer pi&lt;/code&gt;.&lt;/strong&gt; Both now accept &lt;code&gt;--continue-from&lt;/code&gt; (plus &lt;code&gt;--carry&lt;/code&gt;,
&lt;code&gt;--from-message&lt;/code&gt;, &lt;code&gt;--from-time&lt;/code&gt;), seeding the handover as the tool's first
prompt: gemini via its &lt;code&gt;-i/--prompt-interactive&lt;/code&gt; flag (&amp;quot;Execute the
provided prompt and continue in interactive mode&amp;quot;), pi as a trailing
positional message (pi &lt;code&gt;[messages...]&lt;/code&gt; start an interactive session). The
injection strategy is now a declared &lt;code&gt;promptInjection&lt;/code&gt; descriptor (leading
positional / trailing positional / flag value) applied by a shared
&lt;code&gt;injectPrompt&lt;/code&gt; helper - no &lt;code&gt;switch tool&lt;/code&gt;; claude and codex are refactored
onto the same helper. &lt;code&gt;hermes&lt;/code&gt; stays deferred: its only prompt flag
(&lt;code&gt;-z/--oneshot&lt;/code&gt;, &lt;code&gt;chat -q&lt;/code&gt;) is headless one-shot (answer once and exit),
not an interactive seed, so wiring it would change the run mode.
&lt;code&gt;opencode&lt;/code&gt; (TUI positional is a project path), &lt;code&gt;copilot-cli&lt;/code&gt; (headless
&lt;code&gt;-p&lt;/code&gt; only), &lt;code&gt;openclaw&lt;/code&gt; (proxy runtime-block) and &lt;code&gt;cline-cli&lt;/code&gt; (not
verifiable on the grounding node) also remain deferred.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Session Handoff - best-effort target-session linker.&lt;/strong&gt; Every rendered
handover carries a &lt;code&gt;&amp;lt;!-- superbased-handoff &amp;lt;shortid&amp;gt; --&amp;gt;&lt;/code&gt; marker that
rides into the target session on every delivery lane (injected prompt,
SessionStart context, or the model reading &lt;code&gt;HANDOFF-&amp;lt;shortid&amp;gt;.md&lt;/code&gt;).
&lt;code&gt;observer handoff list&lt;/code&gt; 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 &lt;code&gt;handoffs.target_session_id&lt;/code&gt; on the first whose transcript carries
the marker. The link is written once (guarded UPDATE); the list gains a
&lt;code&gt;TARGET&lt;/code&gt; column. Pure marker scan lives in &lt;code&gt;internal/handoff&lt;/code&gt;
(&lt;code&gt;ScanMarkers&lt;/code&gt; / &lt;code&gt;ContainsMarker&lt;/code&gt;); store seam adds &lt;code&gt;LinkTargetSession&lt;/code&gt;,
&lt;code&gt;ListUnlinkedHandoffs&lt;/code&gt;, &lt;code&gt;CandidateTargetSessions&lt;/code&gt;. Short-id is recovered
from the delivered doc's file name (&lt;code&gt;delivery_ref&lt;/code&gt;). Everything is
best-effort - an unreadable candidate is skipped and one handoff's failure
never aborts the sweep.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Session Handoff - &lt;code&gt;handoff_rehydration&lt;/code&gt; cache accounting.&lt;/strong&gt; 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
&lt;code&gt;HANDOFF-&amp;lt;id&amp;gt;.md&lt;/code&gt; read). It is now annotated as a new
&lt;code&gt;cause=handoff_rehydration&lt;/code&gt; (same &lt;code&gt;reanchor&lt;/code&gt; kind, so kind-based
denominators are unchanged) instead of a plain &lt;code&gt;reanchor&lt;/code&gt;, so it no
longer trips the advisor's &lt;code&gt;session_balloon&lt;/code&gt; / &lt;code&gt;cache_write_waste&lt;/code&gt;
detectors or &lt;code&gt;observer cache-health&lt;/code&gt;'s cause-concentration WARN. Fired
live in cachetrack when the &lt;code&gt;superbased-handoff&lt;/code&gt; marker is present on the
first observed turn (proxy &lt;code&gt;parseRequest&lt;/code&gt; body scan + Tier-2 store
block-body scan), and applied retroactively by the advisor via
&lt;code&gt;handoffs.target_session_id&lt;/code&gt; (the belt for non-proxied targets). Docs:
&lt;code&gt;docs/cache-tracking.md&lt;/code&gt; → &amp;quot;Session-handoff accounting&amp;quot;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Session Handoff - implicit-cache lane consults the handoff marker.&lt;/strong&gt; The
§15.3 implicit / OpenAI-Codex attribution path now mirrors the Anthropic
lane: on the bootstrap turn with the &lt;code&gt;superbased-handoff&lt;/code&gt; marker set,
&lt;code&gt;ruleImplicitHandoffRehydration&lt;/code&gt; fires &lt;code&gt;cause=handoff_rehydration&lt;/code&gt; with the
same &lt;code&gt;implicit_write&lt;/code&gt; kind the plain reanchor uses, so every
denominator/exclusion is unmoved (the kind routes to &lt;code&gt;bucketSkipped&lt;/code&gt; +
&lt;code&gt;isRateSkipped&lt;/code&gt;, and the bootstrap turn is already excluded from
&lt;code&gt;ImplicitCacheConsistency&lt;/code&gt;) - only the cause differs. The marker flag,
already scanned provider-agnostically by the proxy's &lt;code&gt;parseRequest&lt;/code&gt;, is now
threaded through the OpenAI branch of &lt;code&gt;buildCacheObserveInput&lt;/code&gt; (it was
previously dropped) and consumed by &lt;code&gt;observeImplicit&lt;/code&gt;. Live coverage is
proxy-only; a non-proxied &lt;strong&gt;codex&lt;/strong&gt; Tier-2 target carries no reconstructed
block bodies to scan, so that lane stays covered by the advisor's
retroactive handoff-target belt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Session Handoff - retention sweep + &lt;code&gt;observer doctor&lt;/code&gt; probe (P4).&lt;/strong&gt; The
node-local &lt;code&gt;handoffs&lt;/code&gt; table is now pruned by the shared retention runner
(&lt;code&gt;observer prune&lt;/code&gt;, and &lt;code&gt;prune_on_startup&lt;/code&gt; on &lt;code&gt;observer start&lt;/code&gt; / &lt;code&gt;watch&lt;/code&gt;)
via &lt;code&gt;store.PruneHandoffRows&lt;/code&gt;, gated by the new &lt;code&gt;[handoff] retention_days&lt;/code&gt;
(default 180; &lt;code&gt;0&lt;/code&gt; = keep forever). The &lt;code&gt;prune&lt;/code&gt; summary line reports
&lt;code&gt;handoff_rows=&amp;lt;n&amp;gt;&lt;/code&gt;. &lt;code&gt;observer doctor&lt;/code&gt; gains a &lt;strong&gt;handoff readers&lt;/strong&gt; 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 &lt;code&gt;read OK&lt;/code&gt; / &lt;code&gt;metadata handover only&lt;/code&gt; /
reader-declared-but-unreadable WARN, dispatched on capability shape (no
tool-name branching).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Changed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The node/developer dashboard is now purely coding-agent (Plane B).&lt;/strong&gt; The
general-observability surfaces - &lt;strong&gt;Trajectories&lt;/strong&gt;, &lt;strong&gt;Evals&lt;/strong&gt;, and the
&lt;strong&gt;Admission&lt;/strong&gt; policy editor / per-end-user budgets - were removed from the
local dashboard nav. These observe an LLM &lt;em&gt;application&lt;/em&gt; you host at the
admin level (end-user traces, evals, and input guardrails), not your own
coding assistant, so their home is the &lt;strong&gt;admin dashboard&lt;/strong&gt; (&lt;code&gt;web2&lt;/code&gt;, the
Trajectories nav group). A node still captures and pushes obs data when
&lt;code&gt;[observability]&lt;/code&gt; is enabled; it just no longer renders the obs UI locally.
The obs backend, &lt;code&gt;/api/obs/*&lt;/code&gt; endpoints, and &lt;code&gt;observer obs …&lt;/code&gt; / &lt;code&gt;observer eval&lt;/code&gt; CLIs are unchanged. See the new [&lt;code&gt;docs/deployment-models.md&lt;/code&gt;].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;New two-plane documentation.&lt;/strong&gt; &lt;code&gt;docs/deployment-models.md&lt;/code&gt; 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. &lt;code&gt;CLAUDE.md&lt;/code&gt;, &lt;code&gt;docs/README.md&lt;/code&gt;, &lt;code&gt;docs/observability.md&lt;/code&gt;,
and the root &lt;code&gt;README.md&lt;/code&gt; were updated to keep the two planes legible, backed
by a full plane-separation audit
(&lt;code&gt;docs/audits/plane-separation-audit-2026-07-06.md&lt;/code&gt;) whose verdict is that
every enforced code boundary between the planes holds.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Community &amp;amp; support card&lt;/strong&gt; added to the node dashboard Overview (star the
repo, report a problem, refer/share, send feedback).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Security&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SQLite DSN path escaping (low; closes ledger item L8).&lt;/strong&gt; Every SQLite
&lt;code&gt;file:&lt;/code&gt; DSN now routes its filesystem path through the new one-owner helper
&lt;code&gt;internal/platform/sqlitedsn.Escape&lt;/code&gt;, which percent-encodes the characters
the SQLite URI parser treats specially (&lt;code&gt;%&lt;/code&gt;, &lt;code&gt;?&lt;/code&gt;, &lt;code&gt;#&lt;/code&gt;). Previously a database
path containing &lt;code&gt;?&lt;/code&gt; was truncated into the query string (and &lt;code&gt;%XX&lt;/code&gt; 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 &lt;code&gt;observer import&lt;/code&gt; read-only ATTACH, and both
first-party database opens. Ordinary paths produce byte-identical DSNs.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v1.14.0 - 2026-07-02</title>
    <link href="https://superbased.app/docs/changelog#v1-14-0" rel="alternate"/>
    <id>https://superbased.app/docs/changelog#v1-14-0</id>
    <updated>2026-07-02T00:00:00Z</updated>
    <published>2026-07-02T00:00:00Z</published>
    <content type="html">&lt;h3&gt;Security&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Whole-product security review + remediation&lt;/strong&gt; (see
&lt;code&gt;docs/audits/security-review-2026-07-02.md&lt;/code&gt;; tracked in &lt;code&gt;docs/security.md&lt;/code&gt;).
A six-surface review plus &lt;code&gt;govulncheck&lt;/code&gt; found and fixed 4 high, 8 medium, and
6 low findings; &lt;code&gt;govulncheck&lt;/code&gt; reachable advisories went 28 → 0.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Org server access control (high).&lt;/strong&gt; Three privileged &lt;code&gt;/api/org/*&lt;/code&gt; routes
(routing-policy publish, routing-summaries export, enrolment-token mint)
were gated on SAML-session presence only, so any SSO-capable member could
reach them - publish a fleet-wide routing policy, export every developer's
email and spend, or mint an enrolment token for an arbitrary user (ingest
impersonation). They now require org-admin authority (&lt;code&gt;admin_emails&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SAML signature bypass (high).&lt;/strong&gt; Bumped &lt;code&gt;goxmldsig&lt;/code&gt; 1.4.0 → 1.6.0
(GO-2026-4753, reachable from assertion validation), &lt;code&gt;golang.org/x/net&lt;/code&gt;
0.53 → 0.55, and the build toolchain to go1.25.11 (clears ~25 stdlib
advisories including &lt;code&gt;html/template&lt;/code&gt; XSS reachable from the org dashboard).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dashboard CSRF / DNS-rebinding (high).&lt;/strong&gt; The local dashboard exposed
state-changing endpoints with no origin or Host validation; a malicious web
page could drive them. Added a same-origin + loopback-Host guard and a
non-loopback-bind warning.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Watcher symlink escape (high).&lt;/strong&gt; A symlink planted under a watch root
could be followed out of the tree and its contents excerpted into the DB;
such symlinks are now skipped.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Privacy / attribution (medium).&lt;/strong&gt; Ingested &lt;code&gt;user_email&lt;/code&gt; is pinned to the
authenticated pusher (was forgeable on aggregate rows), and &lt;code&gt;git_branch&lt;/code&gt; is
no longer shipped in the default metadata-only sharing posture.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Denial-of-service hardening (medium/low).&lt;/strong&gt; Enforced the previously-dead
&lt;code&gt;[watcher].max_file_size_mb&lt;/code&gt;, added watcher panic recovery, a protobuf
recursion-depth cap, and a proxy request-body size cap; plus a proxy
guard-mask JSON backstop, WSL hook-command quoting, git &lt;code&gt;gitdir:&lt;/code&gt; traversal
rejection, and PowerShell path escaping.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Added&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Config auto-migration rail.&lt;/strong&gt; Deprecated config keys are now rewritten
to their current names on disk instead of only being mapped in memory (which
reprinted a &lt;code&gt;config: deprecation:&lt;/code&gt; warning on every load). A new pure,
table-driven registry (&lt;code&gt;internal/config/migrate&lt;/code&gt;) surgically renames keys -
preserving your values, comments, ordering, and every untouched section -
drops keys with no analog, and stamps &lt;code&gt;[observer] config_version&lt;/code&gt;. It runs
automatically once on &lt;code&gt;observer start&lt;/code&gt; (the daemon is the sole writer; a
&lt;code&gt;config.toml.bak&lt;/code&gt; backup is written first) and on demand via &lt;strong&gt;&lt;code&gt;observer config migrate&lt;/code&gt;&lt;/strong&gt; / &lt;strong&gt;&lt;code&gt;observer config migrate --dry-run&lt;/code&gt;&lt;/strong&gt;. Idempotent and
fail-safe: a value it can't edit by line surgery is left untouched, never
corrupted. Registry v1 migrates the decommissioned &lt;code&gt;[compression.code_graph]&lt;/code&gt;
/ &lt;code&gt;[intelligence.code_graph]&lt;/code&gt; blocks onto &lt;code&gt;[codeintel]&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
</feed>
