Skip to content

v1.8.2

Choose a tag to compare

@marmutapp marmutapp released this 06 Jun 15:48
· 16 commits to main since this release

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 legacy kilocode.kilo-code IDE extension
    (Cline + Roo Code fork). Persistence is byte-identical to Cline:
    <vsCodeGlobalStorage>/kilocode.kilo-code/tasks/<taskId>/api_conversation_history.json.
    The new kilocode.LegacyAdapter wraps the existing
    internal/adapter/cline.Adapter and re-tags every emitted event
    with Tool = "kilo-code" so dashboard rollups don't blur Kilo
    activity into Cline.
  • kilo-code-cli — the current @kilocode/cli (npm package,
    binary kilo), a fork of sst/opencode. The all-new IDE extension
    is rebuilt on this CLI runtime. SQLite store at
    ~/.local/share/kilo/kilo.dbsame 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 new kilocode.CLIAdapter is a structural
    transposition of internal/adapter/opencode/, including the
    stageMirrorIfForeign cross-mount pattern (SQLite returns
    SQLITE_IOERR_SHORT_READ on 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 via ctx.register_hook("post_tool_call", …) /
    "post_api_request" / "on_session_start" / "on_session_end" /
    "subagent_stop" and fires observer hook hermes <event> as a
    fire-and-forget subprocess (0.5s timeout, exceptions swallowed).
  • The watcher walks ~/.hermes/state.db (or
    %LOCALAPPDATA%\hermes\state.db on Windows native, plus
    cross-mount candidates on WSL2) and emits ToolEvents + TokenEvents
    via modernc.org/sqlite read-only access. Filters
    messages.active = 1 to 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_high integer.
  • 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-splitphase-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_EMBLEMS /
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.

  • d79a71d arcade mobile playable. Flipped simpleMode
    default to false; dropped @media (max-width:920px)
    game-element display:none !important rules; prefixed editorial
    show-rules with body.simple so they're opt-in only. Copy:
    "PLAY ON DESKTOP" → "PLAY GAME". shoot.mjs gained --touch
    flag (Playwright hasTouch + isMobile) so headless captures
    actually trigger input.js's touch-overlay DOM append.
  • 422d0d3 touch-band redesign. Dedicated 200 px band above
    the HUD on portrait (88 px in landscape after 3c9f06b)
    reserves space for the touch cluster — buttons never overlap
    the canvas. Two-row portrait cluster: X E upper / ◀ ▶ ... 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).
  • 275c558 main-page mobile editorial. Killed the duplicate
    .mtopbar (and its meaningless hardcoded ★ 10/10 chip);
    #simpleNav is the single sticky header; #simpleHeader +
    #simpleFooter force-shown on mobile; .grid-3 → 1 column to
    kill the orphan-card layout; shoot.mjs gained --no-debug-wait
    so non-arcade pages can be captured without the __OBS_DEBUG
    global timeout.
  • 28dc1f6 round-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
    via minmax(0, 1fr) + 480-break collapse; CONTACT US ↔ PLAY
    THE FULL GAME size parity with full-width stacked CTAs.
  • c9b7064 #simpleNav opaque. Four selectors bumped from
    0.93-0.95 α to fully opaque hex (#0D0D12 dark / #DCE7EE
    light — same as --base so the sticky reads as a continuation
    of the surrounding background). Kills scrolled-content
    bleed-through.
  • 3c9f06b landscape 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 /invite page 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.MembersResult types pin the wire
    shape via x-go-type; rollup.ListActiveMembers is the seam.
    Handler in internal/orgserver/dashboard/api.go.

Added — distribution README DRY mechanism

  • npm/observer/README.md and pypi/observer/README.md shared
    ~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.md carries the channel-specific shell and
    includes the body via a single <!-- @@INCLUDE:... --> marker.
    make sync-distribution-readmes regenerates; make verify-distribution-readmes is 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.yml gains a top-level concurrency: block
    (group: npm-release-${{ github.ref }}, cancel-in-progress: false). Defends against re-pushed tags racing on artifact
    uploads / npm publish / vsce publish per
    [[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-preflight job queries the Marketplace via vsce show superbased.superbased-observer --json BEFORE the
    vscode-package matrix 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's needs: 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 via idp-config-override.php did
    require '/var/simplesamlphp/config/config.php.dist', but
    kristophjunge/test-saml-idp ships SimpleSAMLphp at
    /var/www/simplesamlphp/ and has no .dist — the require
    fatal'd, the IdP served the fatal as metadata, and the org
    server's NewSAML couldn't parse <br> as
    <EntityDescriptor>. Fix: remove the override.php entirely;
    replace with a compose-level entrypoint that seds the pin
    in-place against the image's own complete config.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 prior curl -fsS check passed while the body
    was malformed. New check pipes the response through grep -q EntityDescriptor, so an unparseable metadata body fails
    compose's healthcheck and N1-style regressions surface in
    compose ps instead of hiding.
  • SAML resolver detaches from r.Context() (5b). Issue 5b's
    ACS 403 + infinite SSO loop traced to samlSession.CreateSession
    passing r.Context() straight to ResolveSAMLUser — a
    browser disconnect or write-timeout firing mid-ACS canceled
    the DB query, surfaced as api.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
    bounded context.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 because requireAdmin walks
    OrgConfig.AdminEmails and the dev config.toml had no
    [org] section at all. Fix: dev config now ships admin_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 quickstart survives cold docker compose build (N2). The whole flow ran under a 120s budget; a cold
    Go-image build trivially exceeds that and got SIGKILL'd. Fix:
    runComposeUp runs under cmd.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 enroll actually wires ANTHROPIC_BASE_URL (N4).
    The v1.8.0 auto-wire claim covered hooks + MCP + (codex)
    proxy-route, but Claude Code's ANTHROPIC_BASE_URL was 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
    other env key. 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
    because Enroll cleared the bearer + cursor but not
    schema_meta.org_last_push_payload / org_push_log. New
    Store.ClearLastPushState (called inline from Enroll)
    drops both atomically.
  • Server-side actions.source_file ambiguity 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_hash column.

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 the 403 half, but post-ACS the browser bounced
    between /saml/sso → IdP → /saml/acs → /saml/sso at ~10
    round-trips/sec until the tab crashed. Root cause:
    requireSAMLWeb redirects unauthenticated / to /saml/sso, so
    crewjam records /saml/sso as 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.SSO now checks
    sessions.UserID(r) first and 302s to / when the session is
    valid, skipping crewjam's HandleStartAuthFlow. Regression
    test: auth/saml_test.go::TestSSOShortCircuitsWhenAuthenticated.
  • N6 — dev admin_emails actually loads now. v1.8.2 added the
    allow-list under [org] in deploy/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.AdminEmails empty → admin endpoints 403, aggregate
    endpoints render zeros. Fix: rename the section header to
    [dashboard]. Server now also emits a startup WARN when 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 test TestLoadDevComposeConfig would have caught the
    misplacement.
  • N4 caveat — proxy-down warning + symmetric unenroll cleanup.
    v1.8.2's RegisterClaudeCode writes ANTHROPIC_BASE_URL into
    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 forgot observer 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 loud WARNING: observer proxy is not running block with the remediation
      command.
    • New (*proxyroute.Registrar).UnregisterClaudeCode symmetric
      to RegisterClaudeCode: drops ANTHROPIC_BASE_URL when it
      points at any loopback (any observer install), preserves a
      deliberate third-party proxy entry, drops the entire env
      block when it becomes empty. observer unenroll calls it
      best-effort after c.Unenroll(ctx).
  • D1 — Projects rollup now works under default privacy posture.
    v1.8.0 stripped raw project_root server-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::spendCTE now reads
      project_root_hash (the column the privacy fix preserves)
      with LEFT JOIN sessions s ON s.id = t.session_id AND s.user_id = t.user_id so proxy-fed api_turns whose own
      project_root_hash is empty (their project_id was NULL
      on the agent → no hash from the agent-side LEFT JOIN projects)
      still inherit the session's hash via session_id.
    • overview.go, projects.go, teams.go, budgets.go all
      switched to aggregate / filter on project_root_hash.
    • New ProjectIDFromHash helper — the URL {id} is now
      derived from the hash's first 16 chars (the hash already IS
      sha256(rawRoot)).
    • Wire shape unchanged: project_root JSON field still ships,
      carrying the hash hex in metadata-only mode. Full-content
      mode also populates project_root_hash (via the agent's
      hashOrComputed path), 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.md Audits/Plans/Subdirs sections rewritten. After
    Plan C, only two transient docs remain at docs/ 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 every website/** push to
    main. Account 8907a11bce2894c499edf7e34f4691f6, project
    superbased-website, secrets CLOUDFLARE_API_TOKEN +
    CLOUDFLARE_ACCOUNT_ID on 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 character Obs (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.light CSS
    overrides, theme-toggle button, localStorage.sb_theme
    persistence, logo auto-swap via .js-logo class). 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.teal was a value copy at IIFE load time;
    switched to string keys + COLOR[lvl.accent] resolution at
    render time. Top-left expanded #topnav panel 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.app row + inline X/LinkedIn/YouTube/GitHub
    socials. Personal founder emails removed (kept private).
    ENTERPRISE plan CTA mailto also swapped to contact@marmut.app.

  • Release-pipeline website-private invariant (b7dde46).
    website/ + design/website/ added to
    scripts/release.sh::PRIVATE_ONLY_PATHS (so git rm --cached
    drops them from the public orphan), to the .gitignore heredoc
    appended to the orphan tree (so any future drop-in clone of the
    public repo classifies them correctly), and to a new
    site_leaks post-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 in docs/README.md Plans section.

  • Live verification corner cases captured in memory:
    feedback_cloudflare_pages_html_strip.md (Pages auto-308 from
    /foo.html to /foo clean URL — don't read as a misconfig).
    feedback_cloudflare_email_obfuscation.md (Pages rewrites every
    mailto: to /cdn-cgi/l/email-protection#hex so a live curl
    grep for contact@marmut.app returns 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.2

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

Supply chain

CycloneDX SBOMs are attached: observer.cdx.json and observer-org.cdx.json.

SLSA Level 3 build provenance for the binaries is attached below as a *.intoto.jsonl attestation. The build runs on the private origin repo, so pass that as the source when verifying an extracted binary with slsa-verifier v2.7.0 or newer (older versions fail with unexpected tlog entry type: expected intoto:0.0.2, got dsse:0.0.1):

slsa-verifier verify-artifact ./observer \
  --provenance-path *.intoto.jsonl \
  --source-uri github.com/marmutapp/superbased-observer-private