14 KiB
Fresh Workspace Handoff
This is the re-entry packet for this repo (path: whatever the checkout is; it has moved drives before).
It is intentionally short. Historical proof belongs in git history and the
distilled state/evidence.jsonl ledger; the shared architecture belongs in
docs/architecture.md; the forward build order belongs in
docs/implementation-plan.md.
Rehydrate
From the repo root:
python .\tools\heimdall_state.py status
Get-Content '.\state\map.yaml'
Get-Content '.\notes\fresh-workspace-handoff.md'
Get-Content '.\docs\architecture.md'
Get-Content '.\docs\implementation-plan.md'
git status --short --branch
git log --oneline -5
Get-Content '.\state\evidence.jsonl' -Tail 8
Do not trust this file for the exact live HEAD. Always check git.
Active Work
Joystick H1 is merged and live (PR GameCult/Heimdall#1; campaign
joystick:campaign:self). Next: joystick:follow_up:h1-joystick-consent-round-trip, then
StreamPixels S0/S1 (other sessions). Open Heimdall follow-ups, by id:
joystick:follow_up:cross-process-failed-refresh-marker,
joystick:follow_up:connect-start-needs-app-auth,
joystick:follow_up:heimdall-idunn-onboarding,
joystick:follow_up:joystick-viewer-signin-public-bot. The Ghostlight KLTST
canaries below stay open, behind them.
Current Orientation
Yggdrasil runs Heimdall d51fa6b, hand-deployed 2026-10-19 15:51Z;
gamecult-ops 210a1af records backup, rollback and provenance. Facts below
about Odin, Ghostlight and CultLib pins were verified at 1086aee (2026-08-22)
and are not re-verified at d51fa6b.
-
At
1086aee01169bf60e8a492b2740db1c6f3e8cabfHeimdall ran with CultLib5cefa0db0079a8e3ee22f29d7b9e6e5aa60912a9 -
Heimdall publishes four redacted access records to Odin under unique keys:
eve:provider:heimdall,heimdall:command-boundary,eve:plugin:gamecult.heimdall.access, andheimdall:transport-profile -
Odin
b4f9a2e95f0b41cebdeddc49223781d1d3c7b42apersists and returns all four; it does not proxy private commands or receive claims -
Ghostlight
b515ca90c25573005a616244143803b37f2d06ecresolves the boundary through Odin and accepted a live canonical anonymousheimdall.auth.begin; its unit has no direct Heimdall endpoint -
gamecult.heimdall.accessnow has a manifest, advertisement, schemas, fixtures, executabledescribe/validate/projectABI, and browser reference adapter -
Heimdall persists OAuth attempts and serves authenticated
heimdall.auth.begin/heimdall.auth.complete/heimdall.auth.refresh/heimdall.auth.logoutthrough loopback CultNet/RUDP on port4101 -
private commands are source-runtime, app-secret, expiry, nonce, and idempotency bound; their MessagePack payloads and completion claims are AES-256-GCM wrapped
-
the Ghostlight app profile now requires its caller-owned Discord role policy; Heimdall evaluates it and Ghostlight remains owner of local sessions, memberships, and campaigns
-
refresh verifies the exact persisted session revision before reissuing a claim; logout expires that session and advances its revision, so a stale or racing refresh cannot resurrect revoked custody
-
this repo now has a first stateful Heimdall service slice
-
the canonical shared architecture lives in
docs/architecture.md -
the concrete HTTP/JWKS contract lives in
docs/service-contract.md -
app profiles live under
docs/app-profiles/ -
the key boundary is explicit:
- Heimdall owns OAuth, linking, managed provider credential custody, grants, entitlement refresh, and signed claim issuance
- app-domain data stays app-owned by default
- host apps verify signed claims locally for routine auth instead of calling Heimdall on every request
-
the landed service now exposes:
/.well-known/jwks.json/.well-known/heimdall-configuration/v1/oauth/{provider}/start/v1/oauth/{provider}/callback/v1/apps/{appSlug}/auth-completions/redeem/v1/apps/{appSlug}/sessions/refresh/v1/apps/{appSlug}/managed-credentials/resolve
-
the Discord callback path now performs real code exchange, identity resolution, auth persistence, entitlement evaluation, audit logging, and claim issuance for the Repixelizer slice
-
browser-style auth handoff now uses a one-time completion code posted back to the opener, with backend redemption instead of fragment-token handoff
-
same-host or Yggdrasil-reachable app integrations can now ask Heimdall to deliver the auth result directly to an app backend callback endpoint, leaving the browser with only status/attempt signaling
-
signing keys can now load from a persisted file path and bootstrap that file on first boot when explicitly enabled
-
managed provider tokens are now sealed at rest with AES-256-GCM instead of being dumped into "encrypted" columns raw like an insult
-
src/verifier.tsnow provides a small local JWT verifier seam for app backends -
Repixelizer has consumed the backend-callback flow in its hosted web layer: it creates local auth attempts, asks Heimdall to start OAuth, receives the direct backend callback, verifies Heimdall Ed25519 access tokens locally, and adopts httpOnly local sessions
-
Heimdall is now deployed on Yggdrasil at
https://heimdall.gamecult.orgbehind nginx/TLS with Postgres storage, file-backed signing-key bootstrap, configured token custody, and public health/discovery/JWKS checks passing -
Repixelizer is now deployed on Yggdrasil at
https://repixelizer.gamecult.orgwith Heimdall mode enabled, Discord and Patreon as public providers, required access enabled, and queue protection enabled -
Repixelizer public auth-start returns Discord and Patreon authorization URLs using the Heimdall callback and Repixelizer backend handoff
-
Repixelizer auth now has a refresh path: Heimdall issues signed refresh tokens with access claims,
/v1/apps/{appSlug}/sessions/refreshreissues short-lived access claims, and Discord/Patreon provider tokens refresh inside Heimdall before entitlement re-evaluation -
Twitch and YouTube now have generic OAuth exchange and identity runtimes
-
GitHub is still catalogued, but its callback runtime is not implemented
-
StreamPixels now delegates viewer and creator Twitch/YouTube OAuth to Heimdall, redeems Heimdall completion codes server-side, writes its own viewer sessions and connector bindings, and resolves current provider access tokens from Heimdall without storing refresh tokens locally
-
Spotiverse now delegates Spotify OAuth to Heimdall. Heimdall has a
spotiverseapp profile andspotifyprovider runtime; Spotiverse stores a local Heimdall account binding and resolves current Spotify access through/v1/apps/spotiverse/managed-credentials/resolvewithout storing provider refresh tokens. -
Bifrost now has a
bifrostapp profile for Discord/Patreon member access. Bifrost sends caller-owned KTLST Discord role and Patreon tier policies through trusted backend-callback OAuth starts; Heimdall owns provider OAuth/token custody and configured backend callback allowlisting. -
Bifrost patron support sync now reuses Heimdall's existing linked Patreon identity and membership reader.
POST /v1/apps/bifrost/patron-support/syncis app-authenticated, refreshes the stored Patreon credential if needed, reads active paid Patreon tier evidence, and emits a signedRecurringSupportSnapshotto Bifrost's/heimdall/patron-support/eventsintake. -
Public Yggdrasil Heimdall has been deployed with the Spotiverse/Spotify code path, Spotify provider credentials, a Spotiverse shared secret, and an allowlisted loopback portal callback at
http://127.0.0.1:18796/auth/heimdall/callback. -
Heimdall and StreamPixels are deployed on Yggdrasil for the StreamPixels migration slice; Twitch callback handling has been patched so provider token
scopecan be either a space-delimited string or an array -
live StreamPixels Twitch sign-in through Heimdall has succeeded on Yggdrasil and Heimdall audit showed callback success, completion creation, and completion redemption
-
the ignored local
secrets/heimdall-service.envartifact now hasGC_ACCESS_PROVIDER_TWITCH_*andGC_ACCESS_PROVIDER_YOUTUBE_*populated for the StreamPixels migration slice -
the intended first deployment shape is a Heimdall service on Yggdrasil behind nginx, not an embedded cross-runtime shared library fantasy
-
Heimdall now writes a daemon-owned boundary witness store at
GC_ACCESS_CULTCACHE_PATHcontaining provider advertisement, command boundary, transport profile, and daemon-health summary state -
Heimdall can now publish
heimdall.cultnet-rudp-provider-healthto Idunn overcultnet.transport.rudp.v0whenGC_ACCESS_IDUNN_RUDP_HEALTHis configured; HTTP/healthz, JWKS, discovery, systemd, and nginx routing remain compatibility witnesses -
Since
1086aeeHeimdall persists its private provider-health identity at/srv/heimdall/keys/provider-health-identity.ccand publishes canonical signed health independently of the slower Verse snapshot cadence. Idunn owns the exact root trust binding, authenticated admission, lifecycle decision, and redacted public.ccprojection. -
Odin commit
b4f9a2e95f0b41cebdeddc49223781d1d3c7b42aretains the RUDP health reliability cut and registers Heimdall's command-boundary, plugin, and transport schemas so the typed catalog can persist rather than silently drop them. Live proof returned all four exact Heimdall records.
Critical Doctrine
- Persistent state is the agent's mind.
- Cut stale architecture notes as ruthlessly as stale code.
- Do not mistake "shared auth" for "shared database."
- Do not mistake "shared auth service" for "every guarded route must call the mothership."
- If compaction hits before boundary findings are persisted, that work is gone. Re-gather it instead of pretending continuity happened.
Next Real Move
The Active Work follow-ups first. Everything below is the standing queue.
Do not continue implementation automatically from a rehydrate-only request.
The Idunn/swarm health transport cut is live. Do not regress Heimdall to
unsigned idunn.daemon_health, merge its private key into Idunn, or make HTTP
health an authority. The next product work is the Bifrost and remaining browser
verification listed below.
The active Ghostlight deployment cut is complete. The next Ghostlight work is a
real separate-account KLTST completion/refresh/logout canary, followed by the
eight-account Session Zero privacy and actor-binding smoke. Keep port 4101
loopback-only and treat any claim, token, completion, app secret, or account
state in Odin/CultMesh/browser output as a release-blocking fault.
If the user asks to continue on Spotiverse, the current next move is the real
browser /auth/login flow through public Heimdall. The Yggdrasil SSH tunnel
must include reverse forward
spotiverse-callback:18796:127.0.0.1:8796, and local Spotiverse must point at
https://heimdall.gamecult.org with the matching HEIMDALL_APP_SECRET. Verify
managed credential resolution after login. Spotiverse should not regain local
Spotify OAuth token storage.
If the user asks to continue on StreamPixels, the current next move is real browser verification:
- verify viewer claim/link through
https://streampixels.gamecult.org/auth/connect - Twitch viewer sign-in has already passed once; continue with YouTube and connector attachment verification
- verify creator connector attach from an admin creator session
- confirm StreamPixels persists local profile/connector binding state while Heimdall retains provider token custody
- if a provider callback fails, inspect Heimdall audit events and StreamPixels service logs before touching app/domain boundaries
Repixelizer still needs its real browser OAuth verification:
- open
https://repixelizer.gamecult.org/app/ - start Discord sign-in with an account that has the
KLTSTor Patreon-syncedInner Sanctumrole, or Patreon sign-in with a currently entitled tier titledInner Sanctum - confirm Repixelizer sends its app-owned provider policy in the backend-callback OAuth start
- confirm Heimdall receives the provider callback and evaluates entitlement
- confirm Repixelizer receives the backend callback, verifies the Heimdall token, adopts a local httpOnly session, and gates hosted/queue routes
- confirm the Discord authorization URL requests only
identify guilds.members.read
Launch policy is role-gated on purpose: the GameCult Discord can remain public,
but Repixelizer access is limited to members with either KLTST or the
Patreon-synced Inner Sanctum role. Repixelizer owns that role policy through
its own runtime env and sends it to Heimdall during backend-callback OAuth
start; Heimdall owns provider OAuth mechanics and claim issuance, not the
per-app role list.
Patreon access is title-gated on the currently entitled tier title
Inner Sanctum; do not use currency amount as the durable policy because
currencies are weird little traps.
Bifrost needs browser verification after deployment:
- configure Heimdall with
GC_ACCESS_APP_BIFROST_BACKEND_CALLBACK_URLS=https://bifrost.gamecult.org/auth/heimdall/callback - configure Heimdall with
GC_ACCESS_APP_BIFROST_SHARED_SECRET_FILE,GC_ACCESS_BIFROST_PATRON_SUPPORT_ENDPOINT=https://bifrost.gamecult.org/heimdall/patron-support/events, andGC_ACCESS_BIFROST_PATRON_SUPPORT_SECRET_FILE, each naming a credential file - configure Bifrost with
Heimdall__DiscordGuildId,Heimdall__DiscordAllowedRoleIds__0=<KTLST-role-id>, andHeimdall__PatreonTierTitle=Inner Sanctum - configure Bifrost with the matching
Heimdall__PatronSupportIntakeSecret - start Discord sign-in from
https://bifrost.gamecult.org/with a user that has the KTLST cult-member role - start Patreon sign-in with a user that has the configured active tier
- confirm Bifrost creates/updates a local account and active standard membership while Heimdall keeps provider token custody
- trigger
/v1/apps/bifrost/patron-support/syncfor that linked Heimdall account and confirm Bifrost records a Patreon recurring-support snapshot without owning Patreon webhook or token custody
Immediate Re-entry Instruction
After compaction, first rehydrate and reorient from the listed files and git state. Wait for the user's next instruction unless they explicitly say to continue.