Repository navigation
Stable release on the stable channel (npm dist-tags latest and stable, PyPI, the VS Code
Marketplace and Open VSX). 1.36.0 is one combined release (D-400): it supersedes the held 1.35.0, which
never shipped as a stable release, so everything below is new since 1.34.0. Where a note says "1.35",
it means the 1.35.0 release candidates that went out on edge and every build after them, this one
included. On top of the 1.35 work it carries modular packaging (components, prebuilt editions, custom
builds, distro-aware updates), the enterprise vendor API connections (synthetic, awaiting live
validation), the post-1.35 correctness and security rounds, and the move to Go 1.26. It is
v1.36.0-rc.5 plus the two dashboard fixes from the rc.5 roll (T-762, T-763); how the release
candidates got here is at the end of this section ("What changed during the release candidates").
Price snapshot: 2026-09-17 (aws us-east-1, azure eastus2, gcp us-central1)
Read this before upgrading (1.36.0)
The first nine items need a decision or an action from you; the rest describe behaviour that changed.
-
Leaving an organization no longer blocks your AI tools, and a managed node now fails open by
default when its organization's budget cannot be verified. Afterobserver unenrolla managed
node used to keep refusing every proxied request withB-625("the organization requires a budget
on this managed node and none has been verified") until a re-enrol or a daemon restart. Now B-625
never fires without a live enrolment, the running daemon recomposes onto your own[guard.budget]
numbers without a restart, and a managed node whose org budget is not verified yet (right after
enrolling, the org unreachable since start, a document that did not verify) runs on its own numbers
and logs it. An organization that wants the old blocking answer pins the new
guard.budget.fail_closed = truethrough node governance.observer unenrollis now an ordered,
structured leave (observer unenroll --planpreviews it; the dashboard's Leave dialog lists the same
steps) that tells the organization it left (anode_leftaudit row, best effort) and ends as a plain
individual node with your local data and config kept. Re-enrolling from the dashboard with an
enrolment link works again on estates whose front end answers/healthzitself, and every refusal on
that page now says what the server actually answered. -
The leave fail-safe never drops your budgets on a slow read, and still applies your own caps.
(REVIEW-4, D-521.) A managed node no longer treats a failed enrolment read (a busy database, a
checkpoint, a 2 s timeout) as "not enrolled": the last composed budget, the organization's caps and
yours, keeps applying until the node confirms it left. After a confirmed leave, or a re-enrol whose
budget has not arrived yet, requests are checked against your own[guard.budget]caps instead of
no caps at all.observer <tool>and the dashboard's New Terminal now agree with the proxy: a leave
that stopped partway does not block launches, and an expired or unverifiable managed grant starts the
tool with a warning unless the organization setguard.budget.fail_closed. That setting now follows
the organization you belong to without a daemon restart. A leave whose credentials step fails can be
run again, and your AI tools' proxy routes are only removed once the leave has completed. The
dashboard's live budget stream accepts at most 16 viewers at a time (the banner falls back to
polling). -
Only the org's super admin can publish the node components policy (D-524). Publishing, rolling
out (create, approve, stage, promote), rolling back or waivingnode.componentsnow needs the super
admin as well aswrite:policy, matching the rule for grantingcomponents.govern. Anyone else gets
403 super_admin_requiredwith the reason (audited), the assistant's proposals for it need the super
admin to approve, and Organization > Node components keeps Publish disabled with the reason while Check
still works. Halting a rollout and every other policy family are unchanged. Anode.componentsversion
a plain policy admin published before this release stays published: review the family's history. -
Republish any
node.governancefeature.lock (MODPKG-16). Before this release a published
feature.lock was dropped from the signednode.governancebody, so it never reached a node: a lock you
published looked in force on the org dashboard while every node ignored it. After upgrading the org
server, publish each existing feature.lock again so nodes receive it. A lock that forces on a feature
whose component thenode.componentspolicy blocks is now refused at publish (409 cross_rail_error). -
Proxy route and Claude Code settings. The daemon is the proxy on
:8820: take the proxy route off
before stopping the old daemon and put it back after the new one is up (scripts/restart-daemon.shdoes
this in one step), or a session pointed at the proxy getsConnectionRefused. On its first start the new
daemon's hook auto-registration ([observer.hooks] auto_register, default on) rewrites an Observer hook
or MCP command written by an older binary once, to the command this release registers: the npm or pip
launcher (<prefix>/bin/observer) when Observer was installed that way, so the next package upgrade no
longer breaks it.observer initand the auto-registration now render that command and its
--configargument the same way, so they no longer rewrite each other's entries (T-725); keep a copy
ofsettings.jsonif you compare it byte for byte. Leaving an organization removes a proxy route
(Claude CodeANTHROPIC_BASE_URL, Codexbase_url) only when the enrolment wrote it, and only after
the leave has completed. -
New hook events, and Codex asks you to trust them. This release registers two more Claude Code
hook events (TaskCreated,TaskCompleted) and three more Codex events (SessionEnd,
SubagentStart,SubagentStop). Codex holds a newly registered hook until you trust it: open Codex
once and run/hooksto mark every Observer entry trusted (observer initprints the count). Until
then Codex runs the hooks it already trusted and skips the new ones. -
The first start migrates the database, and on a large one that takes a while. The new daemon
applies the schema changes on its first start, before the dashboard and the proxy answer. Measured on a
2 vCPU machine it takes about 7 seconds per 500,000 token rows, mostly migration 151's index builds.
Keep the proxy route off until the new daemon is up (the item above). While the old daemon still runs,
observer status,doctorand other commands from the new binary read the database without migrating
it and say the running daemon is older; restarting the daemon finishes the upgrade. -
The minimal edition compiles the proxy out; the dashboard can be compiled out too. The prebuilt
minimalnode edition (staged artifact, not published to npm, PyPI or the Marketplace) is built
withoutcapture.proxy(34 omit tags in all): it captures through hooks and the watcher, has no
accurate proxy token tier and no conversation compression, and its launchers say the build has no proxy
instead of routing to a dead port. It keeps the local dashboard. The dashboard (ui.dashboard) can now
be compiled out as well, through a custom build (sbo-components build --manifest); such a build
starts headless with one reason and every pointer at Settings > Components names the CLI instead. The
developerandmanagededitions keep both; the published channels still ship thefullproduct.
observer doctor <tool>for an adapter an edition leaves out now says "not in this build" (T-726). -
Go 1.26 to build from source. Every binary is built with Go 1.26.9,
golang.org/x/crypto
v0.57.0 andgolang.org/x/netv0.60.0; building from source needs Go 1.26 or later, and CI lints with golangci-lint v2 (see Security
below). -
Code intelligence is now opt-in. The in-process code index (
[codeintel]: symbols, imports,
call graph) is heavy on CPU and disk, so it now runs only when you turn it on: one click under
Settings > Intelligence > Code intelligence, or[codeintel].enabled = true. A config that never
set[codeintel].enabledused to inherit "on" and is now off; if that install already has an index,
observer startprints a one-line note, the index is kept and ages out through
[codeintel].retention_days. A config that setsenabledeither way is untouched; set it totrue
to keep the old behaviour. While it is off, the MCP symbol tools (search_symbols,get_symbols,
get_relations) stay registered and answerdegradedwith acodeintel_disabledwarning
(get_symbolsstill returns its regex fallback),observer indexdeclines, body-collapse
compression does nothing, andobserver doctorreportscodeintel: off by choiceas a pass. On an
org-managed machine an org pin ofcodeintel.enabledstill wins either way. Org Code intelligence
panels stay empty for machines that have not opted in or been pinned on. -
Roll order for orgs: developer machines first, then the org server (or together). Nodes on
1.34.0-rc.7 to rc.11 that newly enrol by token into a 1.35.0 org server show "Governance: ALTERED"
(a known node-side signature bug, GRANT-INTEG-2, fixed in this release; a stored grant verifies again
after the node upgrades, with no re-enrolment). Default managed enrolment tokens now carry a
governance grant, so every new token enrolment of an old node hits it. -
Older nodes and node.governance. Released nodes from v1.31 to v1.34.0 (every release candidate
included) reject a whole node.governance body that names a section, schema or key they do not know,
and then keep their old body. The org server now projects each node's body to what that build
compiles (section vocabulary, body schema and key generation, judged by full version precedence, so
a release candidate counts as older than its release) and re-signs it at the same version. Residual
limit: a v1.33 node that upgrades to v1.34 can lack theprojectssection until the org's next
publish. -
Org server rollbacks now have hazards; run the preflight first.
observer-org upgrade preflight --rollback-to <version>refuses a rollback while any of these is in use, and you should not roll
back around it:- Binding v2 signatures. Policy and guard-bundle deliveries to new nodes are now signed bound to
the org, the developer and the node's advertised target. Rolling the org server back below this
build makes those nodes refuse every policy delivery (they keep their last body) until it rolls
forward again. - Developer-dashboard tab overrides. Ship dashboard overrides and per-tab hiding in the same roll,
and never roll the org server back to a build without per-tab vocabulary while overrides carry tabs. - Budget rail versions. Rolling back below this build makes nodes refuse the lower budget-rail
versions until the counter catches up. - Also guard fallbacks, lock-override grants and AI tool settings policies in force (other live
grants warn).
- Binding v2 signatures. Policy and guard-bundle deliveries to new nodes are now signed bound to
-
Compound model budgets are now enforced at the AI gateway.
member_modelandteam_model
budgets were shown on the node and the Budgets page but never projected to the gateway; from this
release the gateway enforces them. -
About 14 launch verbs now honour an org-disallowed tool. The org's disallowed-tool gate moved onto
the shared launcher helpers, so seededobserver <tool>launchers that never refused an
org-disallowed tool now do (a closed hole). A tool grant still launches it. -
Distinct approvers are always required.
require_distinct_approveris fixed on: nobody approves
their own request, direct grant or extension, except a solo super-admin who is the only holder of the
key (audited asself_approved). A PUT offalseis accepted with a warning so older admin pages keep
working. -
Budget ids and grant fields follow a capability, not a version (T-505, T-625). The org server puts
the namedbudget_idand the request-grant fields (the offline revert) on the signed budget rail only
for a budget fetch that advertises?policy_caps=budget_grants.v1, which every 1.35 build sends,
release candidates and demo builds included. So 1.35.0-rc.14 and later rc nodes DO receive budget ids
and the banner and Requests links name the budget. A node that does not send the token (any build
before 1.35) keeps the id-less body and still receives the granted amount in its cap. No version is
compared, so adevbuild of 1.35 is treated the same; release-runbook step 3d is retired. -
Budget requests and the new request types need a 1.35 org server (T-538, D-342). A budget
increase request without a budget id, and the new request typespage_accessandconfig_edit, are
accepted only by a 1.35 org server: a released server still requiresbudget_idand answers 400 to
the new types. Roll the org server and the nodes together. -
A node OTLP receiver opened beyond loopback now needs a token (T-538, D-343). With
[ingest.otel].allow_non_loopback = true, every exporter must send theX-Observer-Edge-Tokenheader
(gRPCx-observer-edge-token) holding the value in theotlp-ingest-tokenfile beside the node
database; a request without it gets 401, and if the token cannot be resolved the receiver does not
start. Loopback-only receivers (the default) are unchanged. While the receiver requires the token,
Observer refuses to wire a tool's own exporter at it (no token is ever written into a vendor file). -
Enforce-mode org budgets now stop tools that do not route through the proxy (T-519, D-332).
The daemon publishes its own budget decision and each tool's pre-send hook denies at the cap (the next
prompt where the tool has a prompt hook, else the next tool call). Tools that used to keep running past
a hard cap (Cursor among them) are now stopped; tools with no pre-send seam are flagged after send.
The per-tool answer is the "Budget hook stop" column indocs/adapter-parity.md. -
Recover dropped prompts after upgrading. Codex 0.148 and later (Codex Desktop,
codex exec) wrote
each user prompt in a record Observer did not read, so most prompts were missing; run
observer backfill --codex-rescanonce to recover them. Codex subagent rollouts already stored under a
file-name id keep it until a rescan that is tracked on its own (T-583). Qwen Code counted reasoning tokens twice: run
observer backfill --qwen-code-rescan. -
Managed enrolment tokens. A managed token now defaults to the full managed authority set (23
authorities, narrowable). Managed tokens minted earlier with no authority stay ungoverned and must be
re-minted. -
Cost display. The org admin dashboard always shows dollars. Settings > Display holds one choice,
"Developer dashboards show: Dollar costs (default) / Token usage only". The previous admin-facing
setting is retired and NOT carried over; an org that wants developers on token usage selects it once.
A node that cannot verify the org's display policy shows tokens, not dollars. -
Security: org enrichment of individual-tenancy members (INTEL-7). In
observer-orgv1.33.0
through v1.34.0 org enrichment could enrich an individual-tenancy member's sessions without opt-in
(latent unless an admin enabled org enrichment, which is off by default). Until you run this build,
do not enable org enrichment on an org with individual-tenancy members. After upgrading, purge the
hidden results under Intelligence > Session enrichment or with
observer-org intel purge-individual --confirm. -
Cloud Intelligence plans (hosted service). Plan v3 and the GPT-6 Luna route ship inactive until
the service is deployed and attested. When it is rolled,SBCI_PADDLE_PRICESmust move to
plus_beta:3together with cloud migration 0041, or Plus sells fewer enrichments than Free. -
Components and distros (modular packaging). Nothing changes for an existing install: every
channel still ships the full product, and a node with no[components]block runs everything it ran
before. New:observer componentsand Settings > Components choose what runs (inactive components
start nothing and their routes answercomponent_not_installed); an org can govern a managed node's
components with anode.componentspolicy, which needs the newcomponents.governauthority
(super-admin only to grant); a developer can ask the org for a missing component on the Requests page
(new request typecomponent_enable). On a managed enrolment the local[components]block cannot
narrow the node (it is ignored with a warning); the OS-pinned local ceiling stays the one local limit.
The Projects alignment judge tier is in the public source tree (internal/judgeclient). The
minimal, developer and managed editions are published as GitHub release archives with an edition
installer (install.sh/install.ps1, see Added); npm, PyPI and the VS Code extension still ship
the full build. -
Migrations. Node 148 to 161 (158 component purge plans, 159 the enrolment grant's signed initial
component set, 160 the local ceiling's last-known set, 161 the update state's distro columns; all
node-local); org server 192 to 231; PostgreSQL 0058 to 0098 (0063 is a PostgreSQL-only type fix; 206 /
0073 add the vendor export tables; 231 / 0098 the org signing key history); cloud 0041. On the org
server runobserver-org upgrade preflightand thenobserver-org migratebefore starting the new
image. Take an org database backup before upgrading; the PostgreSQL
model-filter index build holds writes on the token tables for about 18 seconds, before the server
serves traffic.
Added
-
Edition installer (T-729).
scripts/install.sh(Linux and macOS, x64 and arm64) and
scripts/install.ps1(Windows) install the minimal, developer, managed or full edition:--edition
(a menu on a terminal;developerotherwise),--version(default the latest final release; a
pre-release only when named),--prefix(default/usr/local/binwhen root or writable, else
~/.local/bin;%LOCALAPPDATA%\SuperBased\Observer\binon Windows),--from-dirfor air-gapped
installs,--dry-run,--uninstall(runsobserver uninstall --allfirst and keeps the binary if
that fails) and, on Linux with systemd, an offer to turn onintegration.serviceand runobserver service install --now. The archive must match the release'sSHA256SUMS, and its vendor
signature (<archive>.sig, the raw Ed25519 signature the update system already verifies) must
verify against the vendor key compiled into the installer; a mismatch or a bad signature is refused,
an unsigned archive or a machine with no Ed25519 verifier is a warning unless
--require-signature. Everyv*tag now publishes the minimal, developer and managed edition
archives for the five platforms (observer-<tag>-<edition>-<os>-<arch>.tar.gz,.zipon Windows;
the full edition keeps today's names), their.sigfiles, the signedrelease-index.jsonand both
installers as release assets, all inSHA256SUMS. No telemetry; curl or wget. -
Distro-aware updates (manifest v2). Publishing a release on the org server now also writes a
distro-aware v2 document beside the unchanged v1 one, served at/api/agent/update/manifest/v2
with the vendor-signed release index. Nodes built asminimal,developerormanagedupdate
within their distro, and move to another distro only when the org's signed component policy names
it, the local ceiling allows it and the channel's distro epoch has advanced. An older node or an
older org server keeps working exactly as before. Agent migration 161 adds the distro columns to
update_state; org server migration 220 (PostgreSQL 0087) addsdistroandcomponents_digest
toorg_update_artifactsand theorg_update_release_indexesandorg_update_publications
tables. Seedocs/enterprise-updates.md"Distro-aware updates". -
Modular packaging, governance round 3 (MODPKG, lane MP-GOV3). The org dashboard has a
Node components page (Organization > Node components) to compose, check and publish the
node.componentspolicy: it shows the stranding estimate and the cross-rail findings and asks for
the stranded-count acknowledgement before publishing. Anode.governancefeature.lock that forces on
a feature whose component thenode.componentspolicy blocks is now an error and refuses the publish
(409 cross_rail_error, either order). Fixed: a published feature.lock was dropped from the signed
node.governancebody and never reached a node (ledger MODPKG-16); republish an existing lock to
deliver it. A teams-to-enterprise grant replacement now carries the managed initial component set
under a second signature, so older nodes accept it unchanged and newer nodes verify the set (org
server migration 227, PostgreSQL 0094). Settings > Components shows the separately installed artifacts
(browser and VS Code extensions, plugin shims, helpers), also onGET /api/componentsas
artifact_states. -
Scheduled component purges in the org audit log (MODPKG, lane MP-GOV4). A node now reports, on
the component posture it already pushes, the state and due date of each purge anode.components
policy scheduled on it (enum values only; no counts or plan ids), and the org server writes an audit
row (node_component_purges_changed) each time a node's list changes: scheduled, eligible, ran,
expired or cancelled. Updates > Fleet versions carries the list per node and counts the nodes with an
open purge. Optional both ways: older nodes and older servers keep working. Org server migration 228
(PostgreSQL 0095) adds one column toorg_node_component_posture. -
Custom builds from a component manifest, staged (modular packaging P7, lane MP-CUST). A
sbo-distro.v1manifest names a prebuilt base (minimal, developer, managed or full) and adds or
omits components;sbo-components build --manifestresolves it to one compiled set, builds with the
matching omit tags and stamps the binary as distrocustomwith its components digest and custom
distro id, andsbo-components proofchecks it like a prebuilt distro. A custom build updates only
from its own manifest's build named in the vendor-signed release index;vendorsign indexcarries
custom archives, andgo run ./web/compgen -manifestleaves the pages of omitted components out of
its web bundle. The vendor build job (custom-build.yml) is manual-dispatch only with an ephemeral
key and publishes nothing; there is no hosted build service and no org-signed custom build yet. No
migrations. Seedocs/custom-builds.md. -
Prebuilt distros, staged (modular packaging P3).
scripts/build-distro.sh <minimal|developer|managed|full>
(andmake distro-build,make distro-all) builds one distro with tags read from the component
catalog, plus itsgo version -mbuildinfo, a CycloneDX SBOM and a proof record. The proof gate
(sbo-components proof) reads the tags back out of the binary, checks withgo list -depsthat every
excluded component claiming compile-out is absent, that the linked modules equal the closure, and that
the binary reports its own distro. A distro binary started with no[components]block runs its
distro's default set; a component the distro excludes whose code this release still carries is inert
and not selectable and is listed asdistro_out. CI builds, proves and smoke-tests the four distros
on every pull request and vets and tests every omit-tag variant;distro-staging.ymlbuilds all
platforms on demand as workflow artifacts. Nothing is published, signed or tagged by any of it. -
Download this build's SBOM.
GET /api/components/sbomreturns the CycloneDX SBOM of the running
binary (the same document the release pipeline renders per artifact). -
Local component ceiling keeps its last valid set. When the OS-pinned ceiling source fails a check
after a valid read, the last valid set stays in force (node migration 160) instead of falling to core
only. -
Model filter. The node dashboard top bar filters by model, with the list narrowed by the chosen
tool, project and window (a selected model outside the selection stays selected and says "no data in
this selection"). Spend pages narrow to that model's own turns; session and action pages keep whole
sessions that used it. The org dashboard gains a global Tool / Project / Model filter row, kept in the
URL only. New indexes make model filtering about 100x faster for rare models. -
Join and manage an organization from the node dashboard. Settings > Enrolment joins by code, link
or IdP sign-in, shows the consent and the org's grant, the status, Push now, re-enrol and Leave.
Leave removes a proxy route (Claude CodeANTHROPIC_BASE_URL, Codexbase_url) only when the
enrolment wrote it, and the confirm names exactly what goes and what stays. Share history sends
activity captured before enrolment (the twin ofobserver org backfill --all --confirm) and warns when
older sessions came from a previous enrolment. Re-send changed rows is the twin of
observer org resync, and the page showsobserver org push-status's push cadence. The CLI and the
page run one enrolment sequence. AI tool settings > Organization and the org dashboard's invite
screens point at the page. (T-642) -
AI tool settings. A new node dashboard page and
observer agent-configread and edit each AI
tool's own settings and instruction files: By tool, Projects, All AI tools, Instructions, Coverage and
History tabs plus a raw editor. Every save is checked and previewed first, then written atomically
under a lock and read back; secrets show only as present or absent; Observer-owned entries are
refused; settings stored inside editor apps are read-only with a note. A per-adapter catalogue of about
4,700 settings and a 21-key common vocabulary sit underneath it, anddocs/adapter-settings-reference.md
is generated from them.observer config setgains the same checks (--dry-run,--yes), and saving
config.tomlfrom the dashboard runs the same sanity check. -
Org AI tool settings policies. Org admins author AI tool settings for the org, a team or a member,
by tool and project, in web2 (Coding-agent policies > AI tool settings), with a pre-publish check and a
team-conflict gate. Managed machines apply and lock them (form, raw editor and CLI refuse, naming the
policy), re-assert drift twice and then back off within the hour, and reportconfig_driftto Fleet
State. An empty signed body withdraws the locks and keeps the written values. Individual machines are
never touched. Re-enrolling into another org clears the previous org's policy first. -
Access requests and grants. A developer can request an exception, a budget increase, or tool,
model or feature access from the node (form, CLIobserver request access, or the "request access"
link every org block now carries). Admins decide in the Requests page and the Approvals inbox; a
grant has an expiry (perpetual grants are super-admin only and flagged for re-review after 90 days),
reaches the machine over a signed rail, and is shown as Issued until a machine confirms it. Grants
change real enforcement on the tool hook, the prompt gate, the proxy, the launchers and New Terminal,
the org AI gateway, and the node-feature and pinned-setting gates. Requests made offline wait in an
outbox. Seedocs/access-grants.md. -
Hook parity across AI tools. Claude Code's hook model now reaches the other tools:
- Tool-call gates (deny, and ask where the host supports it) for Codex (shell,
apply_patchper
file and MCP), Cursor, Qoder, Antigravity, Grok Build, Goose, Cline CLI, Qwen Code, Factory Droid,
Gemini CLI (BeforeTool, plus a BeforeAgent prompt gate), Copilot CLI (preToolUse) and Muse
(PreToolUse, plus a UserPromptSubmit prompt gate), each live-verified and auto-registered by
observer start. Gates for Poolside, zcode, Command Code, Windsurf / Devin Desktop, the Devin CLI
(new writer for~/.config/devin/config.json), Mistral vibe, Cline, Junie, Crush and Open
Interpreter are written byobserver initonly until each is verified on a real install. - A plugin shim gates OpenCode, Kilo CLI and pi tool calls (and Command Code mods), and shows a
withheld or rewritten prompt to the developer in the tool's own UI. Hermes gains a blocking
pre_tool_callgate. - Deny-only hosts turn an enforced ask into a deny whose reason says how to proceed.
- Failure modes. Gate hooks fail closed on Observer's own timeout or crash only while enforcement
is in force, with a plain reason; observe-only hooks stay fail-open; every failure is recorded. - Lifecycle and tasks. Session start and end, compaction (Claude Code and Cursor) and Claude Code
task events are recorded; Cursor retries of one turn fold into one row. - Health.
observer adapters --hooks,observer doctor --hooksand--probe-hook, and a coverage
card on the Security page show every binding as registered, trusted, current or not. Codex hook
trust is detected and explained (Observer never trusts its own hooks for you). A vendor switch that
turns hooks off (for example Claude CodedisableAllHooks) raises a doctor warning and a guard event.
- Tool-call gates (deny, and ask where the host supports it) for Codex (shell,
-
Prompt guard coverage. Tools with no pre-send seam (Freebuff, Kilo Code CLI, Mistral vibe, Kimi
Code unrouted, Pi, Prime Agent) get a post-hoc flag and a desktop toast, and every coverage
surface names the reason. OpenCode Zen is routed through the proxy. -
Dashboard controls for former CLI-only flows. Each runs the CLI's own code:
- Settings > Connected tools: Set up and Remove Observer's wiring (hooks, MCP server, proxy route)
for every adapter with a hook or MCP surface, with a preview and a refusal when the file changed
since Observer wrote it; a per-adapter Run checks (theobserver doctor <tool>report); and,
with the daemon in WSL, a Windows-side home picker (observer init --windows-*-home). - Settings > Health: each doctor finding links to the control that fixes it, and
observer doctor --jsongains an optionalRemediationsfield. - Settings > Profiles: per-tool and per-project profile assignment with a change preview.
- A forced database integrity check (above
integrity_check_max_gb) as a cancelable background job. - Security: test a command, re-judge history, check or write native permission rules, MCP scan and
compliance summary. - Proxy-route undo, egress lint, score, patterns, calibration, summarize, pricing sync, MCP
wrap / relay / doctor, adopt-defaults, update history, benchmark dry run, spend and delete, and the
resolved profile view. - The MCP access card names the relay's Turn on control instead of a command.
- Settings > Connected tools: Set up and Remove Observer's wiring (hooks, MCP server, proxy route)
-
Command wrapping for Windows shells with a WSL daemon.
observer shell-wrap enable --target windows(or the target switch on Settings > Terminal) installs.cmdshims in
%USERPROFILE%\.observer\shimsand a marked, removable PowerShell profile block. A tool with a
Windows build runs on Windows with its routing taken from the WSL daemon (which also applies the org
disallow gate and managed budget admission); a Unix-only tool runsobserver <verb>in WSL; anything
that cannot route runs unrouted with a notice. The Windows user PATH is never edited (cmd.exe users
add the folder themselves). Copilot CLI, Gemini CLI, Grok and Codex launch without routing on this
target and say so. -
Cursor Cloud Agent capture. Cloud Agent (
bc-) chats viewed in the Cursor IDE are captured again,
under the[cursor]placeholder project: session start and end, and the agent's reasoning as a
harness row. Tokens stay honestly absent. For Cloud Agents that ran before this release, run
observer backfill --cursor-hook-usage. -
Budget warnings. Org-governed warnings at 75%, 90% and 100% of a cap, for the admin and the
developer, on by default, including per-tool and per-model caps. The banner's level is the current
reading (a raised cap clears "exceeded"), its label names the state ("Budget exceeded: requests
blocked", "(warning only)", "(report only)", "Approaching budget"), and every banner state offers
Ask for a budget increase, prefilled with the budget that ran out. -
Org changes reach active machines in seconds. An active node holds a policy-version probe open
(it asks for 20 s, the server caps it at 25 s and answers the moment a version moves), so an org
policy, budget or grant change is picked up in about 1 to 3 seconds instead of 30; idle nodes keep
the push cadence. -
Org Cloud Intelligence parity. Managed and individual machines get the same enrichment
experience: consent for individual-tenancy members (which an org can make a condition of membership,
never switched on silently), node-built evidence over a signed rail, per-session Preview and Enrich,
the org's full control set per org, team and member, weekly project digests, and purges that stick and
reach the node even while the feature is off. -
Developer dashboards (managed machines). Managed machines hide the org-level pages by default;
admins choose Hidden, Read-only or Visible per page, Settings section and tab, org-wide or per team or
member. -
Guard bundles for individual members and Remove from audience, with need-to-know headers.
-
Org guard fallbacks for managed machines: block guarded calls while a developer's guard policy is
invalid, and refuse a New Terminal launch of a proxied tool when no sandbox is available. -
New Terminal lists Junie, Poolside, Crush and Aider, and Zed has a GUI launch row (Homebrew, winget,
install script). -
Arena has a model picker per harness; agent step limits and the assistant's per-turn budget are
free numeric fields. -
Uninstall tools that were installed from the dashboard.
-
Node.js runtime check before guided install and launch of npm-distributed CLIs, with a copyable
install command;observer doctorreports the same. -
Compound budget scopes (developer, team or project by tool or model, and "every developer,
separately") and service accounts. -
Docs.
docs/adapter-parity.md(the one living adapter parity record) and the generated
docs/adapter-settings-reference.md, both drift-checked in CI. -
Ask for a budget increase without knowing a budget id. The Requests page offers a picker of the
budgets your machine knows (whose budget, period, cap and current use, defaulting to the one that ran
out); the org server settles the request against your own budgets. The guard's budget deny line points
at/requests?new=budget. New request types: access to a page the org hid (page_access), a time-limited
config edit (config_edit, at most 30 days) and "Something else". Org admins pick members, budgets,
pages and settings from lists in web2 instead of typing ids. -
OpenTelemetry from every AI tool. The node receiver ingests any vendor's own OTLP export (JSON or
protobuf), not only Claude Code's, under the same capture and scrub rules; where a tool also routes
through the proxy, the proxy owns its token counts.observer init --otlp-export <tools>and Connected
tools > Set up > Telemetry export point Claude Code, Codex, Gemini CLI or Qwen Code's own exporter at
the node (opt-in per tool, removable; a collector of your own is never touched). -
Vendor team usage on the org server (unverified live). Settings > Vendor exports receives Cursor
Enterprise and Claude Cowork team-wide OTLP exports, or polls the Cursor Admin API, with one source per
tool, a scoped machine credential, held unmatched identities and an audited read. Vendor rows are shown,
not counted in spend. Seedocs/teams-operations.mdsection 15. -
Machine identities in web2. Settings > Machine identities creates service accounts and mints,
rotates and revokes ingest credentials (secret shown once); deactivating an account revokes its
credentials. -
Member deactivation. An org admin can deactivate a member (bearers and sessions revoked by default,
reversible, never self, the super admin or the last admin) from web2 orobserver-org users deactivate. -
Server maintenance from web2. Support bundle, scrub content, log requeue, import archive, purge
subject, update sync, resolve projects, digest send and seven Agent Access verbs run from the org
dashboard as audited background jobs (the CLI's own code); entity ids are picked from lists. -
Weekly project digests on developer machines. A developer sees the org's weekly digest, read-only,
for projects they pushed sessions in before that week ended; cost, provider, model and tokens are left
out. -
Administrator-managed AI tool settings (MDM). The org AI tool policy renders into each vendor's
managed layer (a file, a.mobileconfigor an HKLM.reg) with an honest per-value hold, from web2
(Device management) orobserver-org agent-config mdm. -
Closed date ranges. Both dashboards take a custom from / to range, not only "last N days".
-
Node dashboard parity. A model filter, a notification bell (budget, requests, guard, cache, update
and org notices; read and dismiss per item), Projects filters, the request-class split in session
detail and a top-bar Export. -
Remote systems and launch policy from the dashboard. Terminals > Settings edits SSH profiles and
the launch policy (both previewed and saved through the config save pipeline) instead of telling you
to editconfig.toml; a remote machine's host name is shown. -
MCP server reputation has a control on the Security page (the same code as
observer guard mcp reputation). -
AI tool settings, round 2. Instruction blocks, the org view of each managed machine's settings
inventory (audited, needsread:content), secret-shaped values scrubbed instead of withheld, project
common values, pickers instead of typed ids, and enforcement of tracked instruction files.
Changed
- Organization > Node components is picked, not typed (D-571). Require, Allow, Deny and "Deny, a
grant may override" are multi-select pickers over the node component catalog: single components by
title under their class, and whole groups (a class, an id group such asadapter.*, a stability
level) with how many components each matches. A choice already in another list, or a Require choice
that matches a component a Deny choice also matches (or the reverse), is listed greyed out with the
reason. The options come fromGET /api/org/policy-resource/node.components/vocab, built from the
same catalog the publish check uses. The stranding estimate, Check and Publish work as before. - The org dashboard offers lists instead of text boxes wherever the options are known (D-571).
Policy rollout target version, egress provider and effort, the model fields (egress, routing rules,
pricing, reprice, intelligence providers, enrichment and overrides) with model suggestions, node
feature tool lists, the governance action allowlist, update ring manifests, members and timezone,
project rule groups, grant rules and targets (tools, models, features, components), invite emails,
client labels, sign-in domains, scopes, claims and IdP groups, Agent Access environments, workspaces,
groups, issuers and rule versions, control-write budgets, machine identity scopes, mirror versions,
AI gateway upstreams, machine ids, observability filters and annotation keys. Fields whose list is
only a suggestion keep free entry.observer-orgmaintenance actions now refuse a release channel
other than stable, lts or edge, and an MCP rollback mode other than observe or enforce. The audit of
every field isdocs/audits/pickers-audit-2026-10-10.md. observer obs admission setuppicks the judge hosting and the local server from numbered menus.
An answer outside the menu asks again instead of silently leaving the judge unchanged.- Node dashboard: known values are picked, not typed (D-571). Every field whose valid values the
daemon already knows is a picker fed by the endpoint that owns the set: the Actions and Security
session filters (recent sessions), the request rule, tool, model, component and feature, the rule
editor's override rule and MCP server, the Policies routing criterion, cohort, content class, model,
user and cohort map, the guardrail topics and judge model, the Terminals allowed project root, the
Remote tailnet host, the experiment tool, the MCP package lookup, the SSH jump host, the Arena context
files, AI tool setting string values, and in Settings the enabled adapters, compress types,
per-action allowlist, project allow and deny lists, disabled rule ids, dialect targets, MCP retrieval
tools, summary models, profile keys and the reprice model. A genuinely open field keeps a "use what I
typed" row, and a value set by hand in config.toml stays visible. - Cloud portal: session correction tags are picked (D-571). Taxonomy tags come from the curated
vocabulary grouped Activity / Area / Outcome; suggested tags stay free-form with the session's own
offered back. - CLI: interactive prompts pick from a list (D-571).
observer obs admission setuppicks the local
judge model from the server's/v1/models, searches the priced models for a hosted provider, and
adopts starter templates from one checklist;observer initpicks the browser extension id from the
unpacked SuperBased extensions found in the browser profiles (paste stays an option), and its
component chooser shows the feature groups as one checklist (numbers toggle, enter accepts, b steps
back) instead of one question per group. - Cloud Intelligence allowances (Signed-in Free and Plus). Signed-in Free rises to 100 enrichments a
day and 3,000 a month; Plus to 500 a day and 15,000 a month (plan v3). Both plans enrich on GPT-6 Luna
with a 1,024-token output ceiling (a truncated answer is retried, then refunded, never stored). Open
assignments move to v3, and renewals can no longer schedule a v3 subscriber back onto an older
version. - One indexing switch.
[compression.indexing].enabled = falsenow also stops the hook path from
writing tool-output excerpts (before, only the watcher obeyed it). - Copilot CLI launches unrouted on a GitHub-subscription sign-in with a plain one-line note; it is
routed only when a BYOK key and a model are set (a key without a model is refused, and a non-OpenAI
provider type launches unrouted).observer geminiroutes only API-key sessions. observer pialways gives pi a model and never switches yours: a default on another provider
launches unrouted with a notice.- Antigravity (agy) prompt hook is warn-only. On agy 1.3.0 the PreInvocation hook fires before every
model call and Observer reads the prompt fromtranscript_full.jsonl, so it is registered again beside
PreToolUse; it can warn, not block, and a tool-less side request carrying the prompt is seen by no hook. - Guard: an unresolved directory before a recursive delete asks instead of blocking. A delete that
resolves to a root, home, root-depth wildcard or a path outside the project is still denied (R-101);
a relative recursive delete after a directory change Observer cannot resolve now asks (new R-102 row),
so ordinary cleanups such ascd $PROJECT_DIR && rm -rf buildare no longer hard-blocked. - A malformed
guard-policy.tomlkeeps the built-in rules and the org bundle in force and is
reported loudly (doctor, a guard event, a Security banner); the dashboard editor refuses to save one.
Managed machines follow the org's fallback setting. - Guided installs run from your home folder, show the exact package-manager command when a program
the vendor script needs is missing, and never stop at an interactive prompt (Goose installs
non-interactively). Observer never runssudo, except the Tailscale guided setup, where you type the
password yourself. - Platform tabs restructure. Long pages in both dashboards are deep-linkable tabs; old URLs
redirect. The node session drawer keeps its tab in?dtab=. - Terminals keep their original colours in light and dark mode. The New Terminal picker no longer
overflows. IntelliJ IDEA installs the unified product. - Org admin writes are audited atomically. Every org admin write route records its audit row in the
same transaction (or before the change on split stores); a failed audit answersaudit_failedand
changes nothing. Publishes take a two-step confirm, and a stale editor gets409 version_conflict
(Policies, setup wizard, guard bundles, developer dashboards). - Enrolment push cadence. Enrolment leaves
push_interval_secondsunset; the documented default
applies. - Every dashboard config write goes through one save pipeline. Section forms, SSH profiles, launch
policy, pricing, process capture, profile assignments, sandbox settings and experiments all preview
(?dry_run=1), refuse a file changed since you loaded it (409 config_changed), validate, read back
and audit.observer config setrefuses to save when the org posture cannot be read. - Token usage mode reaches every surface. An org that shows developers token usage only now gets it
in exports, server prose, the CLI and the statusline too, not only the dashboard pages. - Spend keeps counting what developer machines report. Whatever vendor source an org picks, node
rows still count for spend, budgets and alerts (operator ruling D-359); vendor rows are shown, not
counted, until a live comparison approves them. - Analytics pollers follow current vendor docs (unverified live). Claude Code Enterprise Analytics
forapi_kind = enterprise, local and remote rows summed per user-day; Codex and OpenAI Platform usage
paged at the documented limits and Platform usage shown as its own entry, never as Codex; Copilot
metrics from the current report and billing from AI credits, one day at a time; the Cursor Admin API
asks for all usage. - The capture pill says what it means. "Active", "No Claude Code", "Not routed" or "Checking"
instead of "Paused" whenever Claude Code was not routed. The sidebar watcher line follows the watcher,
not the Claude Code route, and Cursor's chatstore.dbno longer counts as misrouted. - Daemon restarts are safe. The daemon exits promptly on SIGTERM (a second SIGTERM is honoured, a 20 s
watchdog dumps stacks), andscripts/restart-daemon.shwaits for every daemon holding the database,
including one that already released its port, before relaunching. - Hook writers are byte-idempotent. Re-registering an unchanged hook leaves the file's bytes and line
endings alone. - Command wrapping carries its config. A shim enabled under a non-default
--configruns observer
with that config; on an org-governed machine a brokenconfig.tomlrefuses the launch instead of
running it unrouted.
Fixed
-
Hooks and MCP entries survive an npm or pip upgrade (D-590 U1). They used to name the binary
insidenode_modules/@superbased/observer-<platform>/orsite-packages/observer/_bin/, a path the
nextnpm install -gorpip install -Umoves or deletes, so every hook failed after an upgrade.
observer init,observer start's auto-registration and the hook probe now register the package
manager's own launcher (<prefix>/bin/observerfor npm, the console script for pip) when one on PATH,
or in its usual place, runs this binary; otherwise the real path as before. On Windows npm keeps the
real path, because a.cmdshim cannot be an MCP stdio command. -
A stale Observer MCP entry is repaired without
--force(D-590 U2). Anobserver serveentry
whose command no longer exists (the binary an upgrade removed), or that runs this same install, is now
treated as Observer's own and rewritten byobserver init;observer startrepairs such an entry in
place (it never adds one).observer doctornames the exact command to run, with--forceonly where
init would really refuse. -
Commands from a newly installed binary no longer migrate the database under the running daemon
(D-590 U3). After an npm or pip upgrade,observer status,doctor,components statusand every
other command exceptstart/watch/proxy/updateand the capture paths (hooks,serve,
launchers) read the database without migrating it while another observer process holds it, and print
"the running daemon is vX (schema N); restart it to finish the upgrade". The daemon's lockfile now
records its version, andobserver doctorgains adaemon.versioncheck comparing it with the CLI. -
install.sh and install.ps1 no longer install a second copy over an npm or pip install (D-590 U4).
They now look first: anotherobserveron PATH (npm, pip or another copy) or a daemon running another
binary is listed with its version, the installer says which copy a shell runs now and after the next
login, and offers the package manager's own upgrade command. A second copy is installed only on an
explicit menu answer or--force(-Force);--yesor a pipe without--forcestops with the
explanation. The edition defaults to the existing install's (npm and pip shipfull), and with a
daemon from another install running, Next steps never start a second one and no service is offered. -
observer initand the auto-registration render one command (D-590 U5).--configis written
only when it names a config other than~/.observer/config.toml, in both, so neither rewrites the
other's entries. -
A busy database no longer logs a spend-verdict WARN (D-590 U6). The spend-verdict refresh retries
SQLITE_BUSYwith a short backoff (250 ms to 2 s); a lock that outlasts the retries is logged at debug. -
Upgrade hints name the command that applies (D-590 U7). The npm postinstall prints the
observer service upgradeline only for a daemon running under the systemd unit and the
route-off, stop,observer startorder otherwise.observer service upgradewith no unit explains that
restart path, andupgradeis listed inobserver service --help. -
The Codex trust hint counts the hooks it registered (D-590 U8) instead of a fixed number, in
observer initand the enrolment's client wiring. -
observer doctorflags a proxy route on another port (D-590 U9). A Claude Code or Codex route to a
loopback port other than[proxy].portis aproxy.route_portwarning naming theobserver init
command that rewrites it. -
observer initroutes to the configured proxy port (D-591). It wrote every Claude Code and Codex
proxy route on 8820, the--proxy-portdefault, even when[proxy].portnamed another port, so those
routes reached no proxy. The route port is now--proxy-portwhen given, else[proxy].port, else
8820, the orderobserver org enroll --wire-clientsalready used. -
The Cursor watcher reads only your own CLI log directory (D-590 U10). It used to glob every
/tmp/cursor-agent-logs-*, including other users' on a shared machine. It now reads only
cursor-agent-logs-<uid>or-<username>, and only when that directory is owned by you. -
observer guard statuson a node that never enrolled says "not enrolled" (D-590 U11) instead of
reporting the organization's budget as unreachable. -
/api/componentsreports how the binary was installed (D-590 U12): abinary_installobject
(channelnpm/pip/other, version, and whether hooks register the launcher; no path, because a
remote viewer can read the route).observer components statusprints the binary's path, version and
channel. -
The antigravity bridge is described honestly on Linux (D-590 U13). Outside WSL its component state
now says it ships for a daemon running under WSL and is not used here, instead of a generic "not
applicable"; the Linux packages keep shipping it for WSL2. -
An in-place upgrade no longer leaves the old daemon running behind a "started" message (T-753).
Re-running install.sh, ornpm install -gover an older version, replaced the binary underneath the
running daemon, offered the background service again, andobserver service install --nowthen
printed "Service enabled + started." becausesystemctl starton a running unit does nothing; the
old process kept running the deleted binary. install.sh now says "Upgraded X -> Y", does not offer
the service again, and hands a unit that runs this install to the newobserver service upgrade:
it rewrites the unit for the new binary (keeping its--config/--recipe/--port, refreshing
its Description) and restarts the daemon withsystemctl try-restartonly when nothing can be
routed through it (no proxy listener, or no proxy route present and no open proxy connection).
Otherwise it leaves the daemon running and prints the safe order, because the daemon is the proxy.
observer service install --nowon a running unit applies the same rule, and plaininstallno
longer calls a running unit "not started". install.ps1 renames a runningobserver.exeaside
instead of failing, says "Upgraded X -> Y" and names the still-running pid with the safe order; the
npm package's new print-only postinstall names a daemon still running the replaced binary. Neither
installer nor npm restarts anything itself. The "integration.service is off in every edition" next
step now says it is off by default and that the command turns it on. -
The npm restart hint now fires on a real npm 10 global upgrade (T-756). npm 10 renames the old
package directory aside to@superbased/.observer-<platform>-<random>/and runs postinstall before it
deletes that directory, so the running daemon's executable did not read "(deleted)" yet and the hint
stayed silent (rc.4 roll, node 5). The postinstall now also counts a daemon whose@superbased
observer binary lives under such a retired dot-directory, or is any binary other than the one this
install put in place. It still only prints. -
Every
observercommand group refuses an unknown subcommand (T-757).observer service instal
(and the same typo under any other group) printed help and exited 0. A group now fails with exit 1,
names the unknown word, suggests the nearest subcommand when there is one and points at the group's
--help; a bare group still prints its help. One helper covers the whole command tree, extending
the T-746 fix forobserver org; groups that take a positional value keep their own rule. -
Security > Rules > "+ Add override" lets you pick the rule again (T-762). The node dashboard's
override editor locked its Rule picker whenever it was handed a starting row, and "+ Add override"
always handed it a blank one, so it opened as "Edit override -" with an empty, disabled picker and no
override could be added (rc.5 roll). Each opener now says how it opens the editor: "+ Add override"
lets you pick the rule, "Override" on an effective rule opens a new override locked to that rule, and
"Edit" on an existing override keeps its rule and saves in place. -
"Grant an exception" no longer greets you with an error (T-763). The org dashboard's proactive
grant dialog sent the empty form to the server's preview at once and showed its reply, "user_id and
type are required", in red before any input. The dialog now checks the member and the grant type
itself, keeps Grant disabled until both are chosen, says what to choose in plain words ("Choose a
member.") only after you have used the form, and asks the server for its decision once the form is
complete. -
The Agent Access doctors pass on the compose and Helm shape (T-751). There the agentgateway
sidecar runs the stock image, whose own binary is a different build from the upstream release asset
the binary pin names, soobserver-mcpgw doctorD12 could only skip (no binary in the companion's
container) and, pointed at the image's binary, failed G7. The image digest is now the pin on that
shape:--agentgateway-image(default$OBSERVER_MCPGW_AGENTGATEWAY_IMAGE, which the production
compose and the Helm chart now set from the sidecar image) passes D12 on the release digest and
fails another digest or a tag-only reference; with--agentgateway-binthe binary's--versionmust
still be v1.6.0.observer-org doctor agent-accessandupgrade preflighttake the same flag. -
The Fleet versions skew banner names the newest release candidate. It read "to 1.36.0-rc.1"
while three nodes ran 1.36.0-rc.3: the board compared versions by their X.Y.Z core only, so two
release candidates of one release tied and map order picked one. The board's oldest and newest
versions now use full SemVer precedence (rc.3 above rc.1, rc.10 above rc.9, a release above its
candidates), with a stable tie-break for versions that differ only in build metadata. -
A machine that left and re-enrolled with a new machine key is no longer refused (T-747). After a
structured leave and a reinstall that dropped~/.observer, the re-enrolled node's new machine key
was a409 machine_key_conflictand its machine-scoped grants were withheld until an admin reset
the key. A managed node's leave notice now carries its machine key's proof and the org server
retires that key (auditedmachine_key_retire); when the leave could not do that (an older node,
an unreachable server), the bearer of a fresh admin-minted enrolment of the same member replaces
the key (replaced, audited with the enrolment token). A bearer alone, an older bearer, and a
self-minted or IdP device-code enrolment still cannot move a key. -
The installers name real commands, and
observer org <unknown>fails (T-746). install.sh and
install.ps1 printedobserver org enroll <link>andobserver org unenroll, which did not exist,
andobserver orgwith an unknown word printed help and exited 0, so the enrolment silently did
not happen. They now printobserver enroll --link <enrolment link>andobserver unenroll;
observer org <unknown>exits 1 naming the real commands;observer org enrollandobserver org unenrollrun the top-level commands (hidden aliases); the enrolment's config.toml comment, the
config editor andobserver mcp doctornameobserver enroll. A test checks every command the
installers print against the command tree. -
Uninstall from a root-owned prefix changes nothing; no-proxy wording;
init --allwith no tool
(T-744).install.sh --uninstallfrom a directory you cannot write (a root-owned
/usr/local/bin) stopped the service and removed every hook before failing to delete the binary;
it now checks first, changes nothing and prints the per-user commands plus the onesudo rm -f.
The minimal edition's next steps no longer promise a proxy, the systemd unit's Description names
whatobserver startruns on the node (watcher + dashboardwithout capture.proxy), and
observer init --allon a machine with no AI tool says so after any component note instead of
printing onlymcp skipped. -
Accepting the installer's service offer no longer skips the component chooser (T-745). The offer
writes[components] add = ["integration.service"]before the firstobserver init, and any
[components]block skipped the chooser, so the documented install, yes, init flow never showed it
and recorded no edition. An add-only block (nodistro, noremove) now runs the chooser with
those components shown as already on and records the edition base; a block naming a distro or a
remove is still a recorded choice. -
The component chooser asks about browser chat capture (D-561). It never did, so capture.browser
stayed on unless you ranobserver components remove capture.browser. "Browser chat capture" is
now a feature group carrying the five browser-chat adapters bundled with it, asked where the build
includes it and shown unavailable where it does not; "capture only the detected tools" no longer
turns those adapters off behind it. -
observer initandobserver enrollwire only the components you chose, and only tools you have
(T-730, T-742). Without--config, init and the enrolment's--wire-clientsstep treated every
component as active, so they wired hooks, MCP entries and proxy routes for adapters you had removed
(on a fresh full install, ~20 tools you never installed, including a new~/.claude/settings.json
route) and skipped adapters you had added on a minimal or managed build. They now read the default
config and its governance like the daemon does. A component teardown also no longer creates an empty
config directory for every tool it checks (that is what made those tools look installed), and
removing the deepseek or openclaw plugin shim on a machine that never had one is quiet instead of an
error. -
The first components choice on a fresh install writes a minimal config.toml (T-741). With no
config.tomlyet, the first[components]write (the init chooser,observer components select,
Settings > Components) re-serialized every default: a 665-line file with no comments that also
pinned a disabled, empty[org_client]block, so a later enrolment left pushing off. A save to a
missing file now writes only the keys it set. -
An individual enrolment in an enterprise-posture org is offered an individual grant (T-740). The
enterprise auto-grant (every extract.* token,settings.pin, the enforce tokens and a managed consent
class) was signed into every enrolment under the enterprise posture, individual ones included, so the
node listed 22 managed-only authorities and then refused the grant. It now applies to managed
enrolments only (one table,enrolGrantShapes); an individual token carries exactly what it was minted
with, and the Invite form sends an individual token's selection as shown, so nothing ticked offers
nothing. -
The install-time component chooser starts from your build and adds only what you pick (T-731, T-733,
T-737, T-734). It always wrotedistro = "developer", even from a minimal binary (which then warned
about ten components that build lacks); it now writes the binary's own distro. Accepting every default
now writes exactly that distro's defaults: a "yes" to a group used to add every id in it (developer
defaults turned on routing, remote access, the sandbox, the MCP relay and update management) and the
addlist repeated ids that were already on. On a minimal build a detected AI tool can be turned on in
step 1, the summary counts every component the result leaves off, and unavailable groups print with
step 2. On an org-managed node the chooser writes no distro and offers only what a local choice may
add, saying so before it asks, instead of refusing your answers at the summary. Start at login (the
system service) is now offered as its own group. -
observer service installoffers to turn the system service on instead of only refusing (T-734).
integration.serviceis off in every distro, so the documentedobserver service install --now
refused on a fresh machine. On a terminal it now explains why and asks to turn it on (the same as
observer components add integration.service), then installs; piped runs, org-managed nodes and
builds without the service keep the one-line refusal. -
observer enrollwarns about a stopped proxy only for routes it left in place (T-736). It told a
node with no~/.claudethat Claude Code now routes through the proxy via~/.claude/settings.json
although nothing had been written. The warning now names the tools whose route points at the proxy
and prints nothing when there are none. -
The org Fleet marks nodes that left, and the posture page labels exclusions by their reason (T-738).
A node that ranobserver unenroll(or whose member was deactivated) stayed an ordinary row that slid
to "offline / no contact"; Fleet versions now marks it "left", from the node's structured leave at or
after its last contact or from the directory, and says how many rows left. Collection & posture
labelled every structural exclusion "excluded (service account)", including an ordinary developer
whose grant was only wider than the live document; each row now names its reason (holds authority the
fleet document cannot carry, excluded until the next re-issue, or excluded by an admin). Its Excluded
tile counts the rows it lists and no longer counts up from 0: in a background tab the browser runs no
animation frame, so the tile stayed at 0. -
Component status, doctor and service wording say what is true (T-732, T-739). With no
[components]block,observer components statusandobserver doctorsaid every component was
active on distro and managed builds too, then listed the inactive ones; they now say the build's
defaults (or the organization's selection) are active, with the count. On a managed node doctor
printed "(policy source unauthorized)"; it now says in words what decides. The leftovers check
ignores components the build does not contain (capture.browser warned on a minimal build),
observer components --helpno longer calls the feature read-only, andobserver service installno
longer says the service is the proxy on a node where the proxy is not active. -
A node that is not enrolled no longer warns about the org bearer keychain (T-735).
observer proxy startopened the org bearer store on every node and, on a machine without an OS keychain, warned
about a fallback it would never use. It now opens it quietly when[org_client]is not enabled; the
warning stays armed for the first enrolment. The one gooseFOREIGN KEY constraint failedon a first
scan after the upgrade (node 3, data complete afterwards) is recorded indocs/goose-adapter.md; its
writer was not pinned. -
observer uninstall --allandobserver init --allon a machine with no AI tool say so (D-553).
They printed "no tools selected and none auto-detected - pass ... --all" even though--allwas
passed; they now say--allfound no supported AI tool installed and there is nothing to do. -
observer startno longer rewrites an equivalent Claude Code hook (T-725). A daemon started from a
different binary path (sayobserver.135) replaced every existing.../bin/observer hook claude-code <event>entry in~/.claude/settings.jsonwith its own path plus--config, so each relaunch changed
the user's file. Startup auto-registration now keeps an existing observer hook that is equivalent (same
tool and event, same native or WSL-bridge shape, a binary that still runs, the same effective config
file) and leaves the file byte-identical; it rewrites only a missing or broken hook and logs each
rewrite with its reason.observer initstill points every hook at the binary you run it from. -
observer update statusagrees with the daemon on auto-apply (T-727). On a managed node whose
enrolment grant puts it on the managed-fleet default, the CLI said "auto-apply off - the default for a
BYO node" while the daemon log and the org Fleet row said on: the CLI read onlyadmin_managedfrom
the config. It now resolves the enrolment grant the way the daemon does and goes through the daemon's
one auto-apply resolver. -
Leaving an organization turns sharing off in config.toml; re-enrolling rewrites the address (T-728).
After Leave,config.tomlstill said[org_client] enabled = truewith the address of the organization
just left (on the operator's node, a retired server), and a re-enrol never rewrote an existing block.
Leave now setsenabled = falseonce the leave has completed, as a one-line edit that keeps every comment
and every other setting, and says so; a re-enrol sets it back totrueand writes the new
org_server_urlthe same way. The leave plan now also names the per-organization machine key as kept:
it is the machine's identity, grants nothing without the org credentials Leave removes, and keeping it
lets a return to the same organization reuse its registration instead of a 409 that needs an admin reset. -
WebSocket upgrade passthrough off the deprecated
ReverseProxy.Director(LINT-126-2). The proxy's
upgrade passthrough now usesRewrite(Go 1.26) and sends the upstream the same headers as before:
the client'sForwarded/X-Forwarded-*values are kept (Rewrite would strip them), the client address
is appended toX-Forwarded-For, and noX-Forwarded-Host/X-Forwarded-Protois added that was not
sent. No change for clients or upstreams. -
Builds without a component say so everywhere (T-726).
observer doctor <tool>for an adapter the
build leaves out answers "not in this build" and names the builds that include it (it used to say
"active - no adapter"); a teardown step whose undo verb the build lacks says to run it from a build
that includes the component; the OpAMP routes of an org image withoutorg.opampanswer
not_in_imagefrom every binary that links the org server package; and the session MCP-call panel of
a build without the relay returns the session id and an emptycallslist, the full build's shape. -
The minimal edition passes its proof again. A build with
sbo_omit_ui_export_xlsxleft the
spreadsheet export out but did not report it, so the binary listedui.export-xlsxas inert instead of
compiled out andsbo-components proofrefused theminimaledition. The binary now reports it. -
observer update apply/rollbackno longer run under a daemon that has no dashboard. A build
without the dashboard (orobserver start --no-dashboard) answers no update endpoint, and the CLI used
to apply, or restore a database snapshot, underneath the running daemon. It now reads the daemon's start
lock and refuses with the reason and the fix: let the daemon's update loop apply it, or stop the daemon
(proxy route off first) and run the verb again.--dry-runstill runs. -
Builds without the API proxy or the dashboard stop describing them.
observer privacyno longer lists
a proxy listener such a build never binds, the bareobservergreeting describes whatobserver start
runs in this build and sees a headless daemon, OTLP exports keep their token rows when this node serves no
proxy, and the Components pointers name the CLI verb when there is no Settings page. -
Release tooling: the omit-tag test files whose code a tag compiles out now carry that tag, and the
public-tree obs sweep matches obs build lines with extra conjuncts. -
observer enrollno longer moves a running daemon's hooks. Its AI tool wiring step registered
hooks and MCP against whichever binary ran the enrol, so an enrol from a second build pointed Claude
Code's hooks away from the running daemon. It now uses the running daemon's binary and says so;
observer initstill points them at the binary you run it from.observer org push-statusalso
stops printing a stale 900 s fallback interval. (T-642) -
Ingestion stalls on large machines. Several causes, all fixed:
- Replacing a tool-output excerpt scanned the whole full-text table (about one second per tool result
at 500,000 rows) on both the watcher and the hook path; it is now an index seek (0.67 ms). - The initial scan ran before the watcher started, so one slow tree starved every other tool; it now
runs in the background, round-robin across adapters. - The guard's budget cache aged on transcript time, so a replayed backlog paid two slow budget queries
per action even with no budget configured; the cache uses the guard's own clock, and no lookup runs
when nothing reads a budget. - Files whose unread tail exceeded
max_file_size_mbwere skipped forever; they are now read in
capped windows. - The cross-OS process sweep, root registration and the Codex poller no longer repeat full passes.
- The managed (org budget) token read is bounded to the budget window (from about 3 to 4.6 seconds to
under 1 second on a large database), so a large managed machine no longer times out its budget
lookup.
- Replacing a tool-output excerpt scanned the whole full-text table (about one second per tool result
-
Sessions that never reached the org. After the startup orphan sweep, SQLite could reuse session
row ids at or below the push cursor, so new sessions never shipped. The cursor is now clamped in the
same transaction,observer org statusshows a real "eligible" count, and leaving an org clears the
push history. -
Lost lifecycle events. Compaction and session-end events that arrive before the watcher has
ingested the session are held and retried instead of failing on a missing session. -
Droid hooks never fired: Observer wrote
hooks.jsonunder a wrapper Droid ignores. It now writes
the root-level shape and repairs older files. -
Per-project profile writer wrote a zero-valued
[compression]block that turned compression off
for the project, followed a symlinked.observer, and accepted the home directory. -
Quickstart dev sign-in failed its CSRF check (403).
-
Connected tools showed hooks "off" right after registration, and probed only Claude Code, Cursor and
Codex; it now probes every registered hook. -
Governed machines logged 404 console errors for hidden sections; Fleet State showed
node.featuresas
local-only even when published. -
Managed machines now consent to
node.features, including machines enrolled before this fix (added
once atobserver start), so org feature locks apply. -
Mistral vibe 2.25's unified session store is captured.
-
A grant minted on the enrolment-token rail no longer reads as tampered; an org's first policy publish
reaches nodes within seconds. -
A member on two or more teams can reserve at the AI gateway again.
-
Codex prompts dropped on Codex 0.148 and later (see the upgrade notes); a forced rescan now reads a
file over the size cap whole, window by window, instead of only its first window. -
Codex subagent lineage. A subagent rollout whose
session_meta.sourceis an object lost its whole
session_meta(real id,thread_source,parent_thread_id); it decodes now. -
One prompt, counted once. A Codex prompt both the hook and the rollout recorded is counted once in
the Messages tab, the Projects prompt counts, the cost predictor and the Cloud Intelligence prompt
sample. -
Devin was stopped on every launch under a managed hard USD cap, because the budget walk treated
Devin's in-store_versions/currentsymlink as unreadable; links inside the store are walked now. -
A policy stop inside a New Terminal is explained at the terminal for wrapped launches too, instead
of a bareEXITED (255). -
Qwen Code reasoning counted twice and Gemini CLI duplicate events (see the upgrade notes for
the Qwen rescan; Gemini needs none). -
Split control / data org deployments. About fifteen org dashboard handler families answered 404
"no org", and the machine identity routes failed, when control and data lived in different databases. -
observer-healthcheck -printexists, so a roll can read the Agent Access hop state from inside the
distroless image; an idle or zero-vserver hop counts as healthy. -
Ingestion stalls, second round. Five more full-text excerpt reads (the MCP
get_action_details
tool, retention, the reasoning backfill) seek by index instead of scanning the table
(get_action_detailsfor 25 ids: 14.3 s to 18 ms), and the initial scan serves whichever adapter lane
is ready instead of waiting on a stuck one.
Security
-
golang.org/x/netv0.60.0 (HTTP/2 advisories).golang.org/x/netmoves from v0.58.0 to v0.60.0
and closes five advisories in itshttp2package thatgovulncheckfound reachable from Observer code
(the proxy, the org server, the AI gateway andobserver-mcpgw): GO-2026-6612 (double flow-control
refund on server streams), GO-2026-6603 (server memory exhaustion through Trailer headers),
GO-2026-6610 (malformed framing headers forwarded by a reverse proxy), GO-2026-6611 (CPU exhaustion
through repeated initial window changes) and GO-2026-6617 (server crash through an HPACK encoder race).
The image CVE gate forobserver-mcpgwwould otherwise have blocked the release. Minimum version
selection movesgolang.org/x/cryptoto v0.57.0,x/sysv0.48.0,x/textv0.42.0,x/termv0.46.0,
x/syncv0.23.0, and the indirectx/modv0.41.0 /x/toolsv0.49.0. No code changed; the stdlib
half of these advisories was already fixed by Go 1.26.9. -
Agent Access sidecar: stock agentgateway v1.6.0 (glibc CVE-2026-19499). The digest-pinned agentgateway
sidecar moves from v1.5.0 to the stable v1.6.0 (the upstreamagentgateway/agentgatewayimage,
tagv1.6.0, digestsha256:9d3e6044ddcdc0878b1787f77bd401252b95e22684203fb5e874c4c42d2ed90c; the
full image reference is in the Agent Access compose files anddocs/agent-access-cve-patch-runbook.md),
whose image carries Wolfi glibc 2.44-r7. That closes CVE-2026-19499 (High, glibcstrfmonoverflow), whose dated
exception expired today and would have failed the Agent Access image CVE gate, and two Highhickory-resolver
advisories in v1.5.0's lockfile (ledger AA-45). v1.6.0's breaking changes concern LLM routes only; the MCP hop
config is unchanged. If you mirror the sidecar yourself, mirror the new digest and setAGENTGATEWAY_IMAGE
(compose / OpenTofu) or let the chart's newagentAccess.sidecar.imagedefault take it (Helm);
observer-mcpgw doctornow expects agentgateway 1.6.0. -
Signed-rail and component governance fixes from the fourth adversarial review. The org server's
boot re-sign of routing policies, announcements and update manifests now verifies a stored document
only against keys the server has itself served (a new org signing key history, server migration 231 /
PostgreSQL 0098), never against the key the document's own row names, so a forged row can no longer be
re-signed under the org key; rotating the key file keeps working (ledger SIGN-2). A managed node keeps
an initial component set it inherited from an earlier grant together with the grant that signed it, so
an edited set no longer re-verifies (MODPKG-17 (1)). A fleet grant replacement the super admin issues
now carriescomponents.governand the managed initial component set; anyone else's names those
members as excluded with the reason (MODPKG-17 (4)). A scheduled component purge waits instead of
deleting while the node runs on a last-known-goodnode.componentspolicy, and records its request
before the delete (MODPKG-17 (3), (4)). Thedistro-stagingworkflow no longer expands its dispatch
version into shell (CI-INPUT-1). -
A member can no longer lock a colleague out of their machine-scoped grants (REVIEW-4, ledger
GRANT-16 / GRANT-17 / GRANT-18). Machine keys now bind the (member, machine) pair (org server
migration 229 / PostgreSQL 0096, existing keys copied in), so registering someone else's machine id
only ever affects your own grants. Key registration is audited in the same transaction as the write
and a concurrent registration is a 409 instead of a silent replacement. The admin reset takes an
optional member. A node now keeps one machine key per organization, so leaving an organization and
coming back no longer ends in a permanent key conflict. -
Audit and retention fixes on the org server (REVIEW-4, ledger AUDITSTORE-1, VCONN-14, VCONN-15).
The node scheduled-purge audit row is written to the org database before the change (it was lost on
split control / data deployments); three vendor connection tables declared as aging out are now
pruned; and unlinking a vendor identity restores all of the held call's identities (migration 230 /
PostgreSQL 0097). -
Go 1.26 toolchain and
golang.org/x/cryptov0.56.0. Every binary is now built with Go 1.26.9
(go 1.26.0,toolchain go1.26.9), which letsgolang.org/x/cryptomove to v0.56.0 and closes
GO-2026-6354 and GO-2026-6355 (x/crypto/sshdenial of service; never reachable from Observer code, but
carried in every binary). The org server, MCP gateway, cloud and deploy images build ongolang:1.26;
the two dated image-scan exceptions for those advisories (ledger AA-47) are removed. Building from
source now needs Go 1.26 or later. CI lints with golangci-lint v2.12.2 (the v1 linter cannot read a
Go 1.26 module);.golangci.ymlmoved to the v2 schema with the same rule set. -
Guard rule holes closed: a leading shell keyword (
{,if ... then,do,!) hid a command from
every rule (for example{ rm -rf /; }was allowed under enforce); directory changes and links made in
the same command (cd,pushd,ln -s,mklinkand more) could steer a recursive delete around
R-101; a HOME under/tmpexemptedrm -rf ~; Cline CLI'srun_commandsbatches were never judged.
Interpreter one-liners (python -c,node -eand others) that read or delete a protected or secret
path are now judged by the same rules as shell commands. -
Signed rails bound to the org and the developer (binding v2), sticky once a node has held a bound
envelope; a 404 or an unsigned answer never clears a node's cached policy; a withdrawal is a signed
tombstone. Re-enrolling clears every identity-bound signed cache, so one org's policy cannot survive
into another. -
Hook posture file is signed by the daemon and expires after 3 minutes, so a forged or stale
posture cannot open or wrongly close a gate. -
No credential reaches the wrong provider: a proxied request for an unknown
/up/<id>lane is
refused (502) and a malformed lane address answers 400 before any upstream request. -
Credential-bearing vendor files (zcode, Junie, Qwen, Hermes and every MCP config Observer writes)
are edited only inside Observer's own entries, keep their file mode, and are never backed up or
checksummed by Observer. -
Self-approval of grants is refused (see the upgrade notes), rule severity and lock status are
resolved on the server, and a grant on a shared budget row is refused. -
Need-to-know: a composed guard bundle names only the developer's own teams, and a member or team
bundle's free-text note no longer reaches every recipient. A hidden settings section reveals nothing,
not even which secrets exist. -
INTEL-7 (see the upgrade notes).
-
Third adversarial review (REVIEW-3) folded. The machine inventory filter could skip the
read:contentgate (state=observed%20); a dashboard ops job ran as the host user, so its launcher
could approve their own Agent Access rollback; a deactivated service account's credentials still
authenticated; the vendor usage read was not audited; the OTLP token file was accepted with any mode or
owner; a pushed project hash opened another project's digest history; purge-subject could sign out a
member withoutadmin:members. All fixed. Seedocs/security.md(REVIEW3-* rows). -
Vendor export credentials are exclusive at every request, not only when minted (EA-F10), and every
org route reads the org from the control store. -
Guard: sensitive paths follow
cd, PowerShell script blocks are judged. A protected path reached
through an earlier directory change is judged like the full path, and a recursive delete inside a
PowerShell script block is judged (a pipeline$_target and an uncalled function definition ask;
everything else keeps its verdict). -
Hook-path budget stops are fresh. A stop older than 2 minutes is ignored, the file is removed on
unenrol and rewritten when damaged, and a transient spend read failure stops tools only after three
failed ticks (an operator ruling; structural failures still stop at once). -
The notification state write needs the dashboard's confirm token and is audited.
What changed during the release candidates
None of the five 1.36.0 release candidates was tagged or published: each was built locally and rolled
to the demo org server and nodes, and the notes above stayed one list throughout. What each candidate
added:
rc.2 replaces rc.1, which was built and rolled to the demo but never tagged or published, so this
section carries rc.1's notes and what changed after it as one list. New since rc.1: the edition
installer (scripts/install.sh, scripts/install.ps1) and the edition archives as release assets
(T-729), the follow-ups found during the rc.1 roll (T-725, T-727, T-728, LINT-126-2) and the
install and enrolment fixes from the fresh-install check on the demo nodes (T-730 to T-742).
rc.3 replaces rc.2, which was rolled to the demo org server and nodes 1 to 5 but never tagged or
published; this section stays one list. New since rc.2: golang.org/x/net 0.60.0 for four http2
advisories (lane XNET), the agentgateway sidecar re-pinned to v1.6.0, closing AA-45 (lane AGW16),
the fixes from the rc.2 roll (T-744 to T-747 and the browser capture question, lane FIX-RC2), and
release clean-ups: the Antigravity HTTP/2 clients moved off the deprecated x/net http2.Transport
with no behaviour change, the installer scripts executable again, and the Agent Access task-grant
refusal re-grounded on agentgateway v1.6.0 (T-749).
rc.4 replaces rc.3, which was pushed to origin and rolled to the demo org server and nodes 1 to 5
but never tagged or published; this section stays one list. New since rc.3: the fixes from the rc.3
roll (lane FIX-RC3). An in-place upgrade no longer leaves the old daemon running behind a "started"
message: install.sh hands a running unit to the new observer service upgrade, which restarts the
daemon only when nothing can be routed through it and otherwise prints the safe restart order, and
install.ps1 and the npm package name a daemon still running the replaced binary without restarting
anything (T-753). The Agent Access doctors check the compose and Helm sidecar by its image digest
(T-751), and the Fleet versions skew banner orders release candidates by full SemVer precedence.
rc.5 replaces rc.4, which was pushed to origin and rolled to the demo org server and nodes 1 to 5
but never tagged or published; this section stays one list. New since rc.4: the fixes from the rc.4
roll (lane FIX-RC4): the npm restart hint now fires on an npm 10 global upgrade, which moves the old
package aside before the new postinstall runs (T-756), and every observer command group refuses an
unknown subcommand with exit 1 and a hint instead of printing its help and exiting 0 (T-757). And
the pickers rule (lanes PICKERS and PICKERS-2, D-571): wherever the valid values are a known set, the
org dashboard, the node dashboard, the cloud portal and the interactive CLI prompts offer a list to
pick from instead of a text box, starting with Organization > Node components, and a choice that
cannot be used is listed greyed out with the reason (the ### Changed entries).
1.36.0 replaces rc.5, which was pushed to origin and rolled to the demo org server and nodes 1 to 5
but never tagged or published. New since rc.5: the two dashboard fixes from the rc.5 roll (lane
FIX-RC5): Security > Rules > "+ Add override" lets you pick the rule again (T-762), and the org
dashboard's "Grant an exception" dialog no longer shows a server error before any input (T-763).
Downloads
Pre-built binaries for each supported platform are attached below. Linux variants bundle antigravity-bridge.exe next to the observer binary for WSL2 users of the Antigravity adapter.
| Platform | Asset |
|---|---|
| Linux x86_64 | observer-v1.36.0-linux-x64.tar.gz |
| Linux arm64 | observer-v1.36.0-linux-arm64.tar.gz |
| macOS x86_64 (Intel) | observer-v1.36.0-darwin-x64.tar.gz |
| macOS arm64 (Apple Silicon) | observer-v1.36.0-darwin-arm64.tar.gz |
| Windows x86_64 | observer-v1.36.0-win32-x64.zip |
Verify with sha256sum -c SHA256SUMS (or shasum -a 256 -c SHA256SUMS on macOS) from the directory containing the downloads.
Editions and the installer
The archives above are the full edition. The minimal, developer and managed editions ship for the same five platforms as observer-v1.36.0-<edition>-<platform>.tar.gz (.zip on Windows). The installer picks the edition and platform, checks the archive against SHA256SUMS and its vendor signature, and installs it:
curl -fsSLO https://github.com/superbasedapp/observer/releases/download/v1.36.0/install.sh
sh install.sh --version v1.36.0 --edition developerOn Windows: download install.ps1 and run powershell -ExecutionPolicy Bypass -File install.ps1 -Version v1.36.0 -Edition developer. Both installers take --from-dir / -FromDir for an air-gapped install from these files.
Also available via npm: npm install -g @superbased/observer@1.36.0
Org server (Teams)
The self-hosted org server is an enterprise-licensed product distributed from SuperBased's private container registry with a per-customer pull token issued with your enterprise licence; its release assets are not attached here. Contact sales for a pull token. The pull-and-verify recipe for your exact release is the README.md of the deployment bundle (observer-org deploy export).
Enterprise updates
This release publishes on the stable channel.
Each agent archive carries a detached vendor signature (<archive>.sig, raw Ed25519 over the archive bytes) and the release ships a signed update-manifest-stable.json. Self-hosted org servers consume them with:
observer-org update sync --version v1.36.0
observer-org update publish --channel stable --version v1.36.0For a disconnected server, download observer-v1.36.0-airgap-bundle.tar (archives + signatures + SHA256SUMS + the signed manifest + provenance), carry it across the gap, and run observer-org update import --version v1.36.0 --bundle <dir>.
Supply chain
A CycloneDX SBOM for the agent is attached: observer.cdx.json.
SLSA Level 3 build provenance for the binaries is attached below as a *.intoto.jsonl attestation. The build runs on the private origin repo, so pass that as the source when verifying an extracted binary with slsa-verifier v2.7.0 or newer (older versions fail with unexpected tlog entry type: expected intoto:0.0.2, got dsse:0.0.1):
slsa-verifier verify-artifact ./observer \
--provenance-path *.intoto.jsonl \
--source-uri github.com/marmutapp/superbased-observer-private