v1.8.2
Release headline. Quality-of-life follow-up to the v1.8.0 Teams
shipment + release-pipeline hardening on top of v1.8.1's G8 fix, plus
three new AI-tool adapters (Hermes / Cline-CLI / Kilo Code two-product
pair) and the full Observer Quest website-arcade arc: a v1
6-world / 24-level NES platformer expansion, a 12-phase
addictive-modernization layer (skill tree + INSIGHT + mastery +
engine primitives + bestiary + daily challenge + ghost replays +
achievements + cosmetics + FTUE + a11y), a Phase 13 visual + content
expansion (character redesign + 3 new pickups + shoot mechanic +
7-biome remap + +50% level extensions), and a mobile-playable
redesign with dedicated touch band on the arcade and a polished
editorial column on the main page. 166 commits past v1.8.1.
Added — Kilo Code adapters (legacy IDE extension + CLI)
Captures session data from both Kilo Code products:
kilo-code— the legacykilocode.kilo-codeIDE extension
(Cline + Roo Code fork). Persistence is byte-identical to Cline:
<vsCodeGlobalStorage>/kilocode.kilo-code/tasks/<taskId>/api_conversation_history.json.
The newkilocode.LegacyAdapterwraps the existing
internal/adapter/cline.Adapterand re-tags every emitted event
withTool = "kilo-code"so dashboard rollups don't blur Kilo
activity into Cline.kilo-code-cli— the current@kilocode/cli(npm package,
binarykilo), a fork of sst/opencode. The all-new IDE extension
is rebuilt on this CLI runtime. SQLite store at
~/.local/share/kilo/kilo.db— same path on Linux, macOS, AND
Windows (Kilo intentionally mirrors XDG everywhere; Windows does
NOT use%APPDATA%/%LOCALAPPDATA%here). Schema is OpenCode-shaped
(message/part/todo) plus Kilo-specific tables (project,
workspace,event,session_message,account,permission,
session_share). The newkilocode.CLIAdapteris a structural
transposition ofinternal/adapter/opencode/, including the
stageMirrorIfForeigncross-mount pattern (SQLite returns
SQLITE_IOERR_SHORT_READon a /mnt/c-mounted kilo.db while
Windows is actively writing, so the trio copies into a per-source
cache dir before SQLite opens).
Token capture. Per-assistant-message bundle on message.data.tokens = {total, input, output, reasoning, cache: {read, write}} — mirrors
the OpenCode invariant. Step-finish parts carry per-step token slices
summing to the message-level bundle; the adapter surfaces them as
ToolEvents but NEVER as TokenEvents (would double-count). Step-start
parts are skipped entirely (informational marker; would 12× the
per-turn row count without adding signal).
Pricing. Three new entries cover the Kilo Gateway routing:
kilo-auto/free (zero — Gateway free tier confirmed live),
kilo-auto/small (Haiku 4.5 / GPT-4o-mini class alias for the
title-generation slot), and a kilo-auto family prefix (Sonnet 4
family rates for future paid tiers). Direct provider models
(anthropic/claude-…, openai/…) inherit family-prefix fallback
from existing pricing entries.
Live capture confirmed 2026-06-06 on both WSL Ubuntu 24.04 and
Windows 11 — Kilo CLI @kilocode/plugin@7.3.40, 18 SQLite migrations
applied. Tools exercised: read, write, bash, websearch. See
docs/plans/kilocode-adapter-plan-2026-06-06.md (Phase-0 reality
check) and testdata/kilocode/ (reference dumps of both captures).
enabled_adapters default list grows from 15 to 17 with
"kilo-code" and "kilo-code-cli". Existing users with an explicit
enabled_adapters list in ~/.observer/config.toml must add both
strings to capture Kilo activity.
Added — Hermes Agent adapter (Nous Research)
Captures session data from Nous Research's Hermes
Agent — the open-source
multi-platform autonomous AI agent with 70+ built-in tools, MCP
client + server, and 18+ LLM providers. Distinct from the Hermes LLM
family (Hermes 3, 4) — this is the agent runtime.
Capture strategy is hooks-primary + SQLite backfill (same hybrid
model the cursor adapter uses):
- The Python plugin bridge at
~/.hermes/plugins/superbased-observer/
registers callbacks viactx.register_hook("post_tool_call", …)/
"post_api_request"/"on_session_start"/"on_session_end"/
"subagent_stop"and firesobserver hook hermes <event>as a
fire-and-forget subprocess (0.5s timeout, exceptions swallowed). - The watcher walks
~/.hermes/state.db(or
%LOCALAPPDATA%\hermes\state.dbon Windows native, plus
cross-mount candidates on WSL2) and emits ToolEvents + TokenEvents
viamodernc.org/sqliteread-only access. Filters
messages.active = 1to skip rewound / compressed-out rows
(schema-v14 reality-check finding the original plan missed). - The two paths produce comparable rows; dedup happens via
(source_file, source_event_id)UNIQUE — hook rows carry
"hermes:hook", backfill rows carry the absolute state.db path.
Install: observer init --hermes writes the Python plugin +
merges an mcp_servers.superbased-observer entry into
~/.hermes/config.yaml. Hermes auto-discovers plugins at startup —
no separate enable step. --uninstall removes both surgically.
--dry-run shows the would-be writes. --skip-mcp / --skip-hooks
gate each half independently.
Backfill: observer backfill --hermes-rescan walks every
state.db from messages.id=0 for sessions that pre-date plugin
install (or were captured during an observer outage). Included in
--all.
Tool taxonomy (70+ tools): every Hermes tool folds into the
normalized action set — read_file / write_file / patch /
terminal / search_files / web_search / web_extract /
browser_* / delegate_task / todo / clarify / memory / etc.
The unknown-tool fall-through is mcp_call (Hermes is itself an MCP
host so most user-added tools are MCP-shaped); the raw name is
preserved in actions.raw_tool_name.
Token capture: Tier 2 approximate on both paths. Hook path lifts
post_api_request.usage{input/output/cache/reasoning_tokens} (the
plan originally targeted post_llm_call but the §17.1.F reality
check showed it carries no usage payload at all). SQLite path lifts
session-level aggregates. Provider prefix (anthropic/, nvidia/,
openrouter/anthropic/) is stripped before pricing lookup;
OpenRouter :suffix tails (:free, :beta, :fast) are preserved
so the dashboard distinguishes paid vs free tiers in the same model
family.
Reality-check documentation: the schema-v14 dump captured from a
live install (testdata/hermes/sessions.sql / messages.sql,
9 sessions / 62 messages) backs the SQLite integration tests
(coverage 80.9% on the new package). The §17.1 reality-check section
of docs/hermes-adapter-plan.md documents every delta between the
originally-researched v11 spec and observed v14 reality.
Docs: docs/hermes-adapter.md (operator reference),
docs/hermes-adapter-plan.md (research + reality check),
docs/plans/hermes-adapter-implementation-plan-2026-06-05.md
(per-file build order). 12 conventional commits;
feat(adapter): add ToolHermes constant and EnabledAdapters entry
through feat(observer): backfill --hermes-rescan +
test(adapter): hermes SQLite integration tests +
docs(adapter): hermes adapter user docs + README + CHANGELOG.
Added — Cline-CLI adapter (npm-distributed Cline 3.0.20+)
Captures session data from Cline CLI — the
npm-distributed standalone Cline runtime, distinct from the existing
cline VS Code extension adapter (which now lives at
internal/adapter/cline/; the new CLI adapter at
internal/adapter/clinecli/). Persistence at
~/.cline/data/db/sessions.db (SQLite schema v1, 28 columns read)
plus per-session ~/.cline/data/db/<id>.messages.json content-block
files emitting user_prompt / assistant_text / tool_use /
paired tool_result / per-API-call token rows.
Tool taxonomy. 28 tools — 10 core (read, write, bash, etc.) +
18 team_* coordination primitives (team_create, team_join,
team_message, team_handoff, …). Per-message modelInfo
override handles mid-session provider switching cleanly.
Subagent + team linkage. 5 new ActionMetadata fields —
ParentSessionID, ParentAgentID, AgentID, IsSubagent,
TeamName. Extends Invariant #50's IsZero coverage; no rename of
existing fields.
Token capture. Tier 2 per-API-call from a Phase 0 reality-check
upgrade (the originally researched Tier 1 session-level path was
upgraded after testdata showed per-call rows). Message-level
metrics roll up cleanly to session totals.
V2 cross-mount fix. WSL2 observers reading the Windows-side
/mnt/c/Users/<u>/.cline/data/db/sessions.db over the DrvFs bridge
need the same stageMirror pattern as opencode / kilocode —
copies the db into a per-source cache dir before SQLite opens so
mid-write Windows access doesn't surface SQLITE_IOERR_SHORT_READ.
Fixture tests caught zero of this; live operator end-to-end
surfaced it.
SessionHookChecker dedup gate ships by default so cline-cli
avoids the H1 hermes-audit trap (no WARN entries on the live
4-session install: 1 WSL + 3 Windows-native, 44 actions + 25 token
rows captured zero-loss). Opt-in hooks.jsonl tailer (byte-offset
cursor, partial-line tolerant) covers all 9 hook event types from
plan §6.
Install: ToolClineCLI = "cline-cli" constant + EnabledAdapters
default (15 → 16 prior to kilocode bumping it to 17);
observer backfill --clinecli-rescan (also picked up by --all).
49 sub-tests pass on Windows + WSL2.
Docs: docs/clinecli-adapter.md (operator reference),
docs/plans/cline-cli-adapter-plan-2026-06-06.md (build order +
reality check, including the Phase 0 schema-v1 upgrade),
testdata/clinecli/ (live-install fixtures).
Added — Observer Quest (website arcade expansion)
The public superbased.app/arcade rebrands to Observer Quest —
a 6-world (24-level) NES platformer + 1 Konami-hidden bonus world,
each world themed on a real SuperBased Observer subsystem. Ships as
12 commits on top of the Phase 3.1 website (no Go, no docs/distribution,
no release-pipeline impact). Plan-of-record:
docs/plans/arcade-expansion-plan-2026-06-05.md.
What changed for visitors:
- Worlds + bosses. Six worlds (THE WATCHER → VAULT → PROXY →
COMPRESSOR → OBSERVATORY → AUDIT) with named bosses (Runaway Loop,
Stale Read, Rate Limiter, Context Bloat, Token Oracle, The Audit).
Each boss has a 3-4 phase state machine; final boss invokes every
prior boss mechanic. +1 hidden 7th world (BUG STORM) unlocked by
the Konami code on the title screen. - Characters. 6-character roster (OBS default + WATCHER / PROXY /
COMPRESSOR / INDEXER / AUDITOR), each tied to a boss kill. Character
select overlay with 3×2 (responsive) grid. - Difficulty selector. 3 tiers (Easy / Normal / Hard) recorded
per score, per level, per difficulty. Per-difficulty best-score row
on the title screen. - Mobile + touch parity. Full play on phones + tablets with on-
screen LEFT/RIGHT D-pad + A/B/pause buttons, multi-touch, orientation
banner in portrait, safe-area handling, iOS audio unlock. HUD reflows
at ≤720 / ≤480 px. - Save data v2. Per-difficulty bests, per-level highscores + time-
trial slots, tokens (lifetime / spent), character unlocks, secrets
bitmap, meta-shop unlocks. Backward-compat migration from the v1
sb_arcade_highinteger. - Meta-shop. 8 token-currency unlockables; 4 wired with active
effects (+1 base life, starting magnet, world-map fast travel,
time-trial mode). The other 4 are visible cosmetic / stub items. - First-play audio prompt and settings overlay with save reset
(gated by a confirmation modal — the v1 high-score integer is
preserved on reset). - Bestiary. 6 enemy types (carry-forward Crawler + Flyer plus new
Splitter / Charger / Lobber / Tank) and a projectile system shared
by lobbers + bosses.
What's out of scope for this slice (already noted in plan §15):
- Chiptune music (the MUSIC settings toggle persists state but is
silent until a follow-on commit lands the mixer). - Engine primitive library (climb / wind / belt / revGrav / secret /
glyph) deferred; worlds 2-7 use existing primitives + denser
platform layouts to express their themes. - 6 remaining enemy types from the original plan (Phantom / Burrower /
Slammer / Mimic / Echo / Glitch).
The Cloudflare deploy is unchanged — website-deploy.yml ships all
new arcade* assets automatically. Build-marker progression:
phase-4-arcade-split → phase-4b-state-difficulty → ... →
phase-4j-konami.
Changed — /arcade mobile is now editorial Simple View
Mobile visitors (≤920px viewport) to superbased.app/arcade used
to see the canvas + every stacked NES dialog overlay (title, audio
prompt, world-clear) shrunk to fit, which the operator flagged as
"the older version, dialog boxes stacked one on top of the other."
The arcade page now mirrors superbased.app/'s Simple View
pattern on mobile: the game canvas + HUD + overlays are hidden, the
render loop never starts, and an editorial single-page scroll surfaces
instead — sticky nav with logo + back-to-home, hero header with the
OBSERVER QUEST title + tagline + PLAY ON DESKTOP CTA, then six
section cards (What it is · Six worlds + bosses · Roster · Power-ups
× 22 · How to play · Get the observer), then a footer. Desktop gets
the same content via a top-right ☰ SIMPLE VIEW toggle button (parity
with /). Build marker: phase-4r-simple-view.
Files: website/arcade.html (+ #asimpleNav / #asimpleHeader /
#arooms-static / #asimpleFooter), website/arcade.css (+ ~190
lines of simple-view styles incl. body.simple and
@media (max-width:920px) auto-fallback), website/arcade/main.js
(isMobile() + simpleMode state + setSimple() toggle; gates
firstPlayPrompt() and boot() so the rAF loop never starts on
mobile), website/arcade/input.js (early-exit when body.simple so
the virtual D-pad doesn't overlay the editorial cards).
(This mobile-as-editorial behavior was subsequently superseded by
the mobile-playable arc — see the "Changed — Observer Quest +
main page are now mobile-playable / mobile-polished" section
below.)
Added — Observer Quest addictive modernization (Phase 0 → 12)
Layered on top of the v1 6-world expansion: a 12-phase
modernization arc transforming the arcade from "playable demo" to
"real game" with roguelike depth. Plan-of-record:
docs/plans/arcade-addictive-modernization-plan-2026-06-05.md.
Save schema v3 (additive-only over v2 — cosmetics.deathStamp +
ftueSeen added; no migration path needed beyond v2 → v3
detection).
Phase 0 — instrumentation. __OBS_DEBUG runtime surface
(run, state, fx, enemies, projectiles, grant, goto,
setPlayer); Playwright tape harness at website/tools/shoot.mjs;
12-test regression suite (persistence + save-migration). A
RED-then-GREEN P0 tape pair caught a real persistence bug
(perma/fx were dropped across world entry).
Phase 1 — game-feel. Hit-stop, screen shake, particle bursts,
sprite squash-stretch, coyote-time, jump-buffer, variable-height
jump. The bones of modern platformer feel.
Phase 2 — combo system. ×9 NES-honest cap (rolls back to 9,
never double-digit). Stomp / dash-through / phase-through all
participate. End-of-run summary with breakdown.
Phase 3 — skill tree + INSIGHT currency. 20-node global tree
(NOT per-character). Costs scale; nodes branch defense / mobility /
score / synergy. Lifetime-progression metaprogression at ~8-12
runs to complete.
Phase 4 — pickups + shop overhaul. 5 new pickups (FTS5 /
PHASE / DASH / HOVER / CLONE) on top of the 10 base. Tiers + 6
synergy bonuses. Run-shop redesign with rotating stock + reroll.
Meta-shop expanded with tabs + 10 cosmetics (8 trails + 5
coin-skins + 5 HUD themes). Three-currency HUD cluster
(◆ wallet / ₸ tokens / ◉ insight).
Phase 5 — character active abilities + mastery. E keybind +
touch button. 6 distinct abilities: FOCUS (slow-mo, OBS), PING
(reveal, WATCHER), BLINK (teleport, PROXY), CRUSH (stun,
COMPRESSOR), SCAN BURST (INDEXER), OVERDRAFT (AUDITOR).
Per-character mastery XP (+1/level, +5/world), tier thresholds
5 / 15 / 35. Cooldown HUD pip.
Phase 6 — engine primitives. 8 new level primitives: SPRING
(bouncepad), CRUMBLE (collapsing plat), BELT (conveyor), WIND
(zones + W3-2 windy biome), SECRET (closes the PING reveal
loop), GLYPH + DOOR (key-gated), CLIMB (ladders / vines),
REVGRAV (gravity-inversion). 16 of 24 levels re-authored to use
≥1 primitive (boss arenas + W7-1 intentionally untouched).
Phase 7 — bestiary expansion. 6 new enemy types: PHANTOM
(visibility cycle), BURROWER (surfaces-from-below), SLAMMER
(REVGRAV-dependent ceiling drop), MIMIC (disguised as coin),
ECHO (stomp-chain), GLITCH (teleporter). Elite variants
(palette-shifted +1 HP layer).
Phase 8 — daily challenge + ghost replays. Date-seeded run
configs with 4 modifiers (FAST AUDIT / LOW GRAV / COIN BLITZ /
LEGACY MODE). NES-honest single-digit streak chip (9, then
9+). 14-day calendar grid. +15 bonus insight. 10 Hz
position-trace ghost recorder + translucent paper-ghost playback
gated by PB. ~10 KB / ghost.
Phase 9 — achievements. 24 achievements across 6 categories
(5 reachable run 1, 8 in runs 2-5, 11 long-tail). ovAchievements
4-col grid; ★ N/24 chip on the title screen.
Phase 10 — cosmetics + audio. Trails / coin-skins / HUD
themes / death-stamps. New audio events (Sound.achievement,
Sound.dailyStreak). Title-screen music (Music.play('title'))
wired live.
Phase 11 — FTUE. 3×2 currency/system primer modal + "I'M IN"
gate. Mobile pass on Phase 8 / 9 / 10 surfaces.
Phase 12 — reduced-motion + a11y. CSS reduced-motion
hardening. ARIA dialog roles. Esc-to-close. Polite live-region
announcer. Real fps sampler.
Plus a self-driven multimodal visual-verification pass caught 3
visible bugs the 94 green asserts missed: daily-could-force-locked-
character HUD desync, death-stamp placement + ghost-replay copy,
and [hidden] { display:none !important; } global rule restoring
HTML semantics. Methodology established: assertion tapes
catch logic regressions; multimodal screenshot-reads catch paint
bugs. Both layers required for visual-affecting changes.
56 commits between d61d933 → 10d7a66.
Added — Observer Quest Phase 13 (visual + content expansion)
Closes the operator-surfaced gaps the v1 modernization arc left
open: every world reading as night-city, characters looking
identical when swapped, levels feeling "rather short," only 15
pickups + no projectile verb. Plan-of-record:
docs/plans/arcade-phase-13-visual-content-expansion-2026-06-06.md.
§1 character redesign. Shared 8×8 humanoid PLAYER_ART
replaces the per-character S_ART glyph. Three lever-pulls
deliver distinct silhouettes at a glance: per-character body
palette (CHAR_PAL), 3×3 chest emblem (CHAR_EMBLEM — S /
O / > / [] / # / ?), head pip (CHAR_PIP — antenna /
visor / crown / diagonal / top-hat / none). drawGhost re-uses
the new sprite.
§2 power-ups + shoot mechanic. Catalog grows 15 → 18. New
pickups: BLASTER (X-key fires a horizontal teal
kind:'player' projectile, kills basic enemies in one hit,
staggers tank / lobber; HUD chip BLAST × N M; 5 charges per
pickup), TIME STOP (3 s hard-freeze via fx.freezeUntil),
MULTI-SHOT (3 projectiles per fire at ±14 px y-offsets).
Touch parity via a 7th .t-fire button. Shoot is a pure pickup
verb (no skill-tree node).
§3 biome remap. Seven distinct biomes — meadow / cavern /
sky islands / volcanic / desert / snow-capped mountains / jungle.
WORLD_SKY + WORLD_GROUND_TINT per-world tables; skyline:true
now only on W3. Six new render functions: drawMeadow /
drawCavern / drawSun / drawLava / drawPeaks / drawCanopy.
§4 level extension. All 18 standard levels +50% width (boss
arenas at 1800 untouched). New tail content per level: 4-10 plats,
2-3 enemies, 2-3 flyers, 1 BLASTER / FREEZE / MULTI pickup, 10-15
coins. Primitive extensions where natural. W1 4200-5000 →
6300-7500 … W6 5200-6200 → 7800-9300. Save-state best-times
survive cleanly (per-difficulty keys are content-agnostic).
Operator-driven follow-up fixes. RTK → NOISE CHAMBER rename
(7-site sweep), W3 boss reachable (lower cruise + periodic
ground swoop), enemies revert at level.ground gaps
(overGroundGap helper wired into 7 patrol AIs), W4 boss
reachable (re-anchor groundTop each frame, fixes growth-driven
drift), debug URL shortcut (?debug=1&world=N&level=N&char=ID),
W2/W3/W4 biome density fix, ESC pause + controls cheat-sheet +
djump rebalance on first standard levels.
§5.2 acceptance closures. Projectile + freeze + multi-shot +
HUD-chip tapes (4 tracked); 7 light-theme biome captures; 6
tail captures. Surfaced a real W2 light-theme cavern regression
(gray pillars against pale sky read as a city skyline — the very
"every world is night-city" silhouette Phase 13 was meant to fix).
W2 cavern light-theme fix (d8d84e7). drawCavern branches
fillStyle on THEME_LIGHT — pillars in COLOR.gold α 0.28,
stalactites + stalagmites in COLOR.gold α 0.42. Same shapes,
warm color temperature; structures read as torch-lit cavern
strata rather than cold gray skyscrapers. Closes the
carry-forward finding flagged through three handovers.
20 commits between 549373c → d8d84e7.
Changed — Observer Quest + main page are now mobile-playable / mobile-polished
Supersedes the v1 "mobile is editorial Simple View" arcade behavior
(see the older section above) — operator surfaced via screenshot
that mobile visitors to superbased.app/arcade landed on stacked
editorial cards instead of the playable arcade even though the
touch overlay (D-pad + A/B/E/X/pause via .t-btn) had been wired
for several phases. Four commits closed the mobile gap end-to-end;
two cosmetic-sweep follow-ups polished the result.
d79a71darcade mobile playable. FlippedsimpleMode
default tofalse; dropped@media (max-width:920px)
game-elementdisplay:none !importantrules; prefixed editorial
show-rules withbody.simpleso they're opt-in only. Copy:
"PLAY ON DESKTOP" → "PLAY GAME".shoot.mjsgained--touch
flag (PlaywrighthasTouch + isMobile) so headless captures
actually trigger input.js's touch-overlay DOM append.422d0d3touch-band redesign. Dedicated 200 px band above
the HUD on portrait (88 px in landscape after3c9f06b)
reserves space for the touch cluster — buttons never overlap
the canvas. Two-row portrait cluster:X Eupper /◀ ▶ ... B A
lower. Single-row landscape:◀ ▶ ... X E B A. Pause moved to
top-LEFT (out of overlap with the SIMPLE VIEW toggle at
top-right).275c558main-page mobile editorial. Killed the duplicate
.mtopbar(and its meaningless hardcoded★ 10/10chip);
#simpleNavis the single sticky header;#simpleHeader+
#simpleFooterforce-shown on mobile;.grid-3→ 1 column to
kill the orphan-card layout;shoot.mjsgained--no-debug-wait
so non-arcade pages can be captured without the__OBS_DEBUG
global timeout.28dc1f6round-2 polish. Five operator findings: ▶ GAME
VIEW warp at narrow dark mode (font + padding tighten at the
920 break + a 360-break for very narrow phones); PLAY THE FULL
GAME removed from the top hero (GET STARTED carries an arcade
CTA); per-room paper-borders + teal box-shadow removed for
desktop parity; DASHBOARD tile grid overflow at 480 px fixed
viaminmax(0, 1fr)+ 480-break collapse; CONTACT US ↔ PLAY
THE FULL GAME size parity with full-width stacked CTAs.c9b7064#simpleNavopaque. Four selectors bumped from
0.93-0.95 α to fully opaque hex (#0D0D12dark /#DCE7EE
light — same as--baseso the sticky reads as a continuation
of the surrounding background). Kills scrolled-content
bleed-through.3c9f06blandscape touch band tighten 96 → 88 px.
Single-row cluster needs only.t-jump's 68 px + 12 px bottom
margin = 80 px → 88 px leaves a comfortable 8 px top margin
while recovering 8 px of usable game canvas.
Operator decisions baked into this arc: mobile arcade MUST be
playable (overrides Phase 3 brief §8 "desktop-only" intent);
mobile main page stays editorial (no touch controls are wired in
website/index.html and the path forward is responsively-polished
editorial, NOT a touch overlay); no per-room boundaries on mobile;
GET STARTED CTAs full-width same-size; top hero hook = NPM INSTALL
- GITHUB only on mobile.
14 tracked mobile-specific capture tapes added (4 arcade + 10
main-page + narrow variants). Multimodal-verified across portrait
380×820, landscape 820×380, narrow 320×700, iPhone SE landscape
568×320, desktop 1280×720.
Added — admin Invite UX
GET /api/org/members(admin-only, samlSession-secured) returns
the active SCIM-provisioned org users sorted by email. Powers a
<select>dropdown on the dashboard's/invitepage and the
Settings → Enrolment tokens section, replacing the
paste-the-UUID free-text input that v1.8.0 shipped. Non-admin
callers get 403 and the UI falls back to the free-text input so
the page stays usable.- New
rollup.Member+rollup.MembersResulttypes pin the wire
shape via x-go-type;rollup.ListActiveMembersis the seam.
Handler ininternal/orgserver/dashboard/api.go.
Added — distribution README DRY mechanism
npm/observer/README.mdandpypi/observer/README.mdshared
~780 byte-identical lines that silently drifted when one channel
was updated without the other. The shared body now lives in
docs/distribution/README-body.md; each channel's
README.template.mdcarries the channel-specific shell and
includes the body via a single<!-- @@INCLUDE:... -->marker.
make sync-distribution-readmesregenerates;make verify-distribution-readmesis a CI drift gate that builds into
temp files and diffs against committed (never mutates the working
tree). Zero content drift introduced by this commit — both
rendered READMEs are byte-identical to the prior committed state.
Added — release-pipeline hardening
npm-release.ymlgains a top-levelconcurrency:block
(group: npm-release-${{ github.ref }},cancel-in-progress: false). Defends against re-pushed tags racing on artifact
uploads /npm publish/vsce publishper
[[feedback-npm-release-workflow-double-fire]]. The serialised
run waits instead of cancelling — killing a publish mid-stream
risks half-published registry state.- New
vscode-preflightjob queries the Marketplace viavsce show superbased.superbased-observer --jsonBEFORE the
vscode-packagematrix runs. Fails fast (~30s) with the
remediation hint if the tag's version is already listed,
instead of after ~25 min of matrix builds +vsce publish
errors.vscode-package'sneeds:is now[build, vscode-preflight]. With v1.8.1's G8 stamp fix, the v1.8.0
failure mode now has three defence layers.
Fixed — Teams test regression (2026-06-03 second run)
Six follow-ups closing the residual findings in
docs/teams-test-regression-2026-06-03.md. Issues 1–4, 6 (most),
and 7 from the original 2026-06-02 set remain fixed; the new arc
closes the boot regression and the 5b dashboard-403 root cause that
landed in v1.8.0.
- deploy/observer-org IdP boots again (N1). The v1.8.0
attempt to pin baseurlpath viaidp-config-override.phpdid
require '/var/simplesamlphp/config/config.php.dist', but
kristophjunge/test-saml-idpships SimpleSAMLphp at
/var/www/simplesamlphp/and has no.dist— the require
fatal'd, the IdP served the fatal as metadata, and the org
server'sNewSAMLcouldn't parse<br>as
<EntityDescriptor>. Fix: remove the override.php entirely;
replace with a compose-level entrypoint thatseds the pin
in-place against the image's own completeconfig.php, then
exec apache2-foreground. Idempotent across restarts. - IdP healthcheck no longer reads PHP fatals as Healthy (N3).
SimpleSAMLphp returns HTTP 200 even on a PHP fatal-error
body, so the priorcurl -fsScheck passed while the body
was malformed. New check pipes the response throughgrep -q EntityDescriptor, so an unparseable metadata body fails
compose's healthcheck and N1-style regressions surface in
compose psinstead of hiding. - SAML resolver detaches from r.Context() (5b). Issue 5b's
ACS 403 + infinite SSO loop traced tosamlSession.CreateSession
passingr.Context()straight toResolveSAMLUser— a
browser disconnect or write-timeout firing mid-ACS canceled
the DB query, surfaced asapi.store.memberByEmail: context canceled, and crewjam translated the failure to 403. Same
shape as the v1.7.3 proxy-insert detach
([[feedback-proxy-detached-insert-context]]). Fix: derive a
boundedcontext.WithTimeout(context.Background(), 10s)for
the resolver call. Regression test seeded in
saml_test.go::TestCreateSessionDetachesContext. - Dashboard renders data again (5b dashboard half). Even
after the resolver detach, every/api/org/*endpoint kept
returning 403 becauserequireAdminwalks
OrgConfig.AdminEmailsand the devconfig.tomlhad no
[org]section at all. Fix: dev config now shipsadmin_emails = ["user1@example.com", "admin@example.com"]so both the
kristophjunge default user and the quickstart-provisioned
admin can see whole-org rollups. observer-org quickstartsurvives colddocker compose build(N2). The whole flow ran under a 120s budget; a cold
Go-image build trivially exceeds that and got SIGKILL'd. Fix:
runComposeUpruns undercmd.Context()directly (no internal
timeout — operator is watching the build), and only the
post-up readiness + SCIM + mint steps live under the 120s
budget.observer enrollactually wiresANTHROPIC_BASE_URL(N4).
The v1.8.0 auto-wire claim covered hooks + MCP + (codex)
proxy-route, but Claude Code'sANTHROPIC_BASE_URLwas a
print-only hint. The single biggest remaining onboarding gap
per the regression doc. New(*proxyroute.Registrar).RegisterClaudeCode
writes"env": { "ANTHROPIC_BASE_URL": "http://127.0.0.1:<port>" }
into~/.claude/settings.json, preserving every other
top-level key (hooks, mcpServers, permissions, ...) and every
otherenvkey. Idempotent; refuses non-loopback existing
values without--force; treats another local-observer
port-9999-style entry as AlreadySet rather than clobbering.org status"Last push" resets on re-enroll (N5). Prior
behaviour left a stale prior-run timestamp after re-enrol
becauseEnrollcleared the bearer + cursor but not
schema_meta.org_last_push_payload/org_push_log. New
Store.ClearLastPushState(called inline fromEnroll)
drops both atomically.- Server-side
actions.source_fileambiguity documented
(N5). Migration files are immutable once shipped, so the
column rename is not in scope; ingest.go now carries a
comment explaining that in metadata-only mode (v1.8.0+) the
column holds the sha256 hex of the path rather than the path
itself, and how to disambiguate by length / sibling
source_file_hashcolumn.
Fixed — v1.8.2 re-test follow-ups (2026-06-04)
Three concerns surfaced by the v1.8.2 re-test
(docs/teams-test-regression-v1.8.2-2026-06-04.md). N1/N3/N4/N5 from
the 2026-06-03 regression doc are confirmed fixed; these close the
two new blockers the v1.8.2 first cut introduced plus the N4
operational caveat.
- Issue 5b is finally fixed (the SSO loop). v1.8.2's resolver
detach removed the403half, but post-ACS the browser bounced
between/saml/sso → IdP → /saml/acs → /saml/ssoat ~10
round-trips/sec until the tab crashed. Root cause:
requireSAMLWebredirects unauthenticated/to/saml/sso, so
crewjam records/saml/ssoas the RelayState entry URL, and the
post-ACS redirect lands the (now-authed) user back on/saml/sso
— which re-initiates SSO unconditionally. Fix:
internal/orgserver/auth/saml.go::SAML.SSOnow checks
sessions.UserID(r)first and 302s to/when the session is
valid, skipping crewjam'sHandleStartAuthFlow. Regression
test:auth/saml_test.go::TestSSOShortCircuitsWhenAuthenticated. - N6 — dev
admin_emailsactually loads now. v1.8.2 added the
allow-list under[org]indeploy/observer-org/config.toml, but
the config struct reads from[dashboard](the section header
didn't exist in the file). TOML silently dropped it →
cfg.Dashboard.AdminEmailsempty → admin endpoints 403, aggregate
endpoints render zeros. Fix: rename the section header to
[dashboard]. Server now also emits a startupWARNwhen the
allow-list is empty so a future misplaced key surfaces as a
boot-time signal, not a silent dashboard-zeros mystery. New
config-load testTestLoadDevComposeConfigwould have caught the
misplacement. - N4 caveat — proxy-down warning + symmetric unenroll cleanup.
v1.8.2'sRegisterClaudeCodewritesANTHROPIC_BASE_URLinto
the shared~/.claude/settings.json, so every Claude Code
session on the host immediately routes through the proxy. If
the proxy isn't running (e.g. operator forgotobserver start),
every Claude Code instance breaks with connection-refused — the
v1.8.2 re-test caught this when the tester's own driving
session dropped. Two-part fix:- Enroll now does a 200ms TCP-dial probe of the proxy port
after the settings.json write and emits a loudWARNING: observer proxy is not runningblock with the remediation
command. - New
(*proxyroute.Registrar).UnregisterClaudeCodesymmetric
to RegisterClaudeCode: dropsANTHROPIC_BASE_URLwhen it
points at any loopback (any observer install), preserves a
deliberate third-party proxy entry, drops the entireenv
block when it becomes empty.observer unenrollcalls it
best-effort afterc.Unenroll(ctx).
- Enroll now does a 200ms TCP-dial probe of the proxy port
- D1 — Projects rollup now works under default privacy posture.
v1.8.0 stripped rawproject_rootserver-side in metadata-only
mode, but the rollup queries kept filtering
WHERE project_root != ''— every project-dimension aggregate
(project_count,top_projects,/api/org/projects,
/api/org/teams/{id}.top_projects) was permanently empty. D1 in
docs/teams-test-open-issues-2026-06-04.md. Fix is server-side
only:internal/orgserver/rollup/cost.go::spendCTEnow reads
project_root_hash(the column the privacy fix preserves)
withLEFT JOIN sessions s ON s.id = t.session_id AND s.user_id = t.user_idso proxy-fedapi_turnswhose own
project_root_hashis empty (theirproject_idwasNULL
on the agent → no hash from the agent-sideLEFT JOIN projects)
still inherit the session's hash viasession_id.overview.go,projects.go,teams.go,budgets.goall
switched to aggregate / filter onproject_root_hash.- New
ProjectIDFromHashhelper — the URL{id}is now
derived from the hash's first 16 chars (the hash already IS
sha256(rawRoot)). - Wire shape unchanged:
project_rootJSON field still ships,
carrying the hash hex in metadata-only mode. Full-content
mode also populatesproject_root_hash(via the agent's
hashOrComputedpath), so aggregation works for both modes
without forking the queries. - Regression test
rollup_test.go::TestProjects_MetadataOnlyMode
seeds the production-reality fixture (raw column empty, only
the hash + one proxy-fed turn with NO hash but a valid
session reference) and proves the JOIN-fallback path.
Changed — docs reorg Plan C (2026-06-04)
b89faec. Moved 13 tracked audits →docs/audits/and 16 tracked
plans →docs/plans/. ~200 path-ref rewrites across ~40 docs.
docs/README.mdAudits/Plans/Subdirs sections rewritten. After
Plan C, only two transient docs remain atdocs/root:
adapter-audit-playbook.md(reusable methodology) and
handoff-2026-05-16-design-parity.md(legacy naming, kept for
historical continuity). Pairs with the Plan A categorized index +
the Plan B handovers move from earlier in the v1.8.2 chain.
Added — Cloudflare-Pages website pipeline + Phase 2/3/3.1 redesign (2026-06-04 / 2026-06-05)
The marmutapp/superbased-observer-private repo now owns publishing
the marketing site at https://superbased.app. The public mirror
stays focused on the binary + package distribution surface — the
site source is excluded from the orphan via release.sh.
-
Phase 1 takeover (
e6a6ab4, 2026-06-04). Mirrored the prior
screenshot-app~/superbased/website/(48 files, 5.0M) verbatim
into./website/plus the.github/workflows/website-deploy.yml
workflow that fires Cloudflare Pages on everywebsite/**push to
main. Account8907a11bce2894c499edf7e34f4691f6, project
superbased-website, secretsCLOUDFLARE_API_TOKEN+
CLOUDFLARE_ACCOUNT_IDon the private repo. -
Phase 2 redesign (
a763244, 2026-06-05). Replaced the
screenshot-app pages with a side-scrolling NES-skinned slide deck
(10 stages + Konami bonus, support pages re-skinned to the same
palette). Operator rejected mid-iteration as "skin on a slide
deck, not a real game"; superseded by Phase 3. -
Phase 3 real playable platformer (
918319f, 2026-06-05). Real
HTML5 Canvas side-scrolling platformer with characterObs(the
S logo with eyes), 10 buildings → NES dialog rooms (HOOK / PAIN /
FIX / PAYOFF / INTEGRATIONS / INSTALL / DASHBOARD / MCP / TRUST /
GET STARTED), Konami bonus Stage 11, NES contact-modal end-gate.
Mobile vertical card fallback. Simple-view editorial layout
toggle. Built by Claude Design from
docs/plans/website-phase-3-real-game-brief-2026-06-05.md.
Separate/arcade(arcade.html+arcade.js) is a full
enemy-stomping platformer with power-ups + coin shop + lives. -
Phase 3.1 iteration (
78f668c, 2026-06-05). Light/dark
theme system (PAL.dark/PAL.light palette swap,body.lightCSS
overrides, theme-toggle button,localStorage.sb_theme
persistence, logo auto-swap via.js-logoclass). Contact modal
title★ CONTACT ★→★ GET IN TOUCH ★. Arcade grew 3 → 5
levels (COLD START/RATE LIMIT/CONTEXT WINDOW/
TOKEN STORM/THE AUDIT). Splash hint upsized to
clamp(17px,2vw,22px)Space Grotesk for prominence. -
Phase 3.1 follow-up fixes (
697a54c/12168b9/24e0a6b/
602bb5b/2f357e7). "3 AGENTS" stat-card wrap (force-fit 26px
nowrap). Arcade theme accents stuck on dark because
LEVELS[].accent: COLOR.tealwas a value copy at IIFE load time;
switched to string keys +COLOR[lvl.accent]resolution at
render time. Top-left expanded#topnavpanel with all 8 site
destinations (HOME / ARCADE / SECURITY / PRIVACY / TERMS / EULA
/ GITHUB / NPM + PYPI + VS CODE). Support pages
(security/privacy/terms/legal/eula) get the same theme system +
proper brand-logo image (auto-swaps logo.png/logo-dark.png) +
theme toggle. Cache-proof inline-style/width/height attributes
on the support-page brand image so a stale cached site.css can't
render the 920×240 wordmark at native size. -
Contact-modal cleanup (
22ef9b5). Replaced the three founder
rows (legal@superbased.app + santosh@ + sanjay@) with a single
contact@marmut.approw + inline X/LinkedIn/YouTube/GitHub
socials. Personal founder emails removed (kept private).
ENTERPRISE plan CTA mailto also swapped tocontact@marmut.app. -
Release-pipeline website-private invariant (
b7dde46).
website/+design/website/added to
scripts/release.sh::PRIVATE_ONLY_PATHS(sogit rm --cached
drops them from the public orphan), to the.gitignoreheredoc
appended to the orphan tree (so any future drop-in clone of the
public repo classifies them correctly), and to a new
site_leakspost-stage sanity-check grep so a regression that
silently lets either tree through into the public push fails
the release. -
New tracked plan docs:
docs/plans/website-phase-2-redesign-2026-06-05.md(the
superseded slide-deck plan; kept for traceability of the
rejected approach) and
docs/plans/website-phase-3-real-game-brief-2026-06-05.md(the
brief the operator handed to Claude Design — palette/fonts/game
mechanic/level layout/verbatim content/acceptance criteria;
remains the canonical hand-off if Phase 3 needs to be
re-derived). Both indexed indocs/README.mdPlans section. -
Live verification corner cases captured in memory:
feedback_cloudflare_pages_html_strip.md(Pages auto-308 from
/foo.htmlto/fooclean URL — don't read as a misconfig).
feedback_cloudflare_email_obfuscation.md(Pages rewrites every
mailto:to/cdn-cgi/l/email-protection#hexso a live curl
grep forcontact@marmut.appreturns 0 even when correct —
decode the XOR hex to verify).
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.8.2-linux-x64.tar.gz |
| Linux arm64 | observer-v1.8.2-linux-arm64.tar.gz |
| macOS x86_64 (Intel) | observer-v1.8.2-darwin-x64.tar.gz |
| macOS arm64 (Apple Silicon) | observer-v1.8.2-darwin-arm64.tar.gz |
| Windows x86_64 | observer-v1.8.2-win32-x64.zip |
Verify with sha256sum -c SHA256SUMS (or shasum -a 256 -c SHA256SUMS on macOS) from the directory containing the downloads.
Also available via npm: npm install -g @superbased/observer@1.8.2
Org server (Docker)
The self-hosted org server ships as a Docker image and as per-platform observer-org-v1.8.2-* archives (attached below).
docker pull ghcr.io/marmutapp/observer-org:v1.8.2The image is keyless-signed with cosign. Verify it:
cosign verify ghcr.io/marmutapp/observer-org:v1.8.2 \
--certificate-identity-regexp 'https://github.com/marmutapp/superbased-observer-private/.*' \
--certificate-oidc-issuer https://token.actions.githubusercontent.comSupply chain
CycloneDX SBOMs are attached: observer.cdx.json and observer-org.cdx.json.
SLSA Level 3 build provenance for the binaries is attached below as a *.intoto.jsonl attestation. The build runs on the private origin repo, so pass that as the source when verifying an extracted binary with slsa-verifier v2.7.0 or newer (older versions fail with unexpected tlog entry type: expected intoto:0.0.2, got dsse:0.0.1):
slsa-verifier verify-artifact ./observer \
--provenance-path *.intoto.jsonl \
--source-uri github.com/marmutapp/superbased-observer-private