Bifrost-binding for the chat client: self-drive + log affect/memory ops #17
Closed
opened 2026-06-15 23:08:16 -07:00 by vh
·
1 comment
No Branch/Tag Specified
main
diag/r30-gap-injection-harness
diag/r30-phi0-step-response
diag/r29-pad-series
graphify-tooling
v0.22.3
v0.22.2
v0.22.1
v0.22.0
v0.21.20
v0.21.19
v0.21.18
v0.21.17
v0.21.16
v0.21.15
v0.21.14
v0.21.13
v0.21.12
v0.21.11
v0.21.10
v0.21.9
v0.21.8
v0.21.7
v0.21.6
v0.21.5
v0.21.4
v0.21.3
v0.21.2
v0.21.1
v0.21.0
v0.20.17
v0.20.16
v0.20.15
v0.20.14
v0.20.13
v0.20.12
v0.20.11
v0.20.10
v0.20.9
v0.20.8
v0.20.7
v0.20.6
v0.20.5
v0.20.4
v0.20.3
v0.20.2
v0.20.1
v0.20.0
v0.19.9
v0.19.8
v0.19.7
v0.19.6
v0.19.5
v0.19.4
v0.19.3
v0.19.2
v0.19.1
v0.19.0
v0.18.11
v0.18.10
v0.18.9
v0.18.8
v0.18.7
v0.18.6
v0.18.5
v0.18.4
v0.18.3
v0.18.2
v0.18.1
v0.18.0
v0.17.17
v0.17.16
v0.17.15
v0.17.14
v0.17.13
v0.17.12
v0.17.11
v0.17.10
v0.17.9
v0.17.8
v0.17.7
v0.17.6
v0.17.5
v0.17.4
v0.17.3
v0.17.2
v0.17.1
v0.17.0
v0.16.1
v0.16.0
v0.15.1
v0.15.0
v0.14.2
v0.14.1
v0.14.0
v0.13.0
v0.12.0
v0.11.0
v0.10.0
v0.9.0
v0.8.2
v0.8.1
v0.8.0
v0.7.1
v0.7.0
v0.6.5
v0.6.4
v0.6.3
v0.6.2
v0.6.1
v0.6.0
v0.5.1
v0.5.0
v0.4.1
v0.4.0
v0.3.0
v0.2.1
v0.2.0
v0.1.0
Labels
Clear labels
blocked-needs-contract
blocked-needs-dependency
bug
cli
documentation
duplicate
enhancement
invalid
needs-architect-decision
needs-info
needs-triage
observability
ready-for-agent
sse-client
task
tui
wontfix
Sleipnir refuses dispatch — issue-scoped contract missing
Sleipnir holds dispatch — INV-029 dependency-aware gate
Something is not working
Command-line surface (--send, --new, --session, etc.)
Docs / contract / spec work
Duplicate of another issue
New feature or improvement
Not a real issue
Escalated for a design call
More info required from reporter
Newly filed, not yet sorted
Log-pane / debug-surface work (persona, admin events, Bifrost, tools)
Gates AFK dispatch via Sleipnir (applied by /sleipnir-preflight)
SSE consumer module (src/ratatoskr/sse_client.py)
Implementation task
Textual app shell + presenters
Accepted as not-fixing
Milestone
No items
No Milestone
Projects
Clear projects
No projects
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: vh/ratatoskr#17
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Context
Ratatoskr now wears two hats: the conversation-API canary client (TUI/web/CLI that runs turns against Worldtree and observes the SSE flow) and, since 2026-06-14, a Bifrost Tier-3 provider — the durable affect store (shipped v0.17.2, live-proven) and memory store (shipped v0.17.3, #195-parity green).
But the canary client can't drive its own provider.
create_sessionsends only{agent_id, end_user_id}(src/ratatoskr/sessions.py:196) — it never sets the session's Bifrostendpoint_url. Supplying Bifrost endpoints from the client was an explicit negative clause in the original design-brief (§6: "Bifrost-binding consumer support — not a Ratatoskr concern"). That decision predates the provider identity — so ratatoskr now owns both ends of the Bifrost round-trip but can't connect them itself. The affect + memory smokes both had to be driven externally (infra-ops/worldtree-dev crafting the binding).This issue closes that gap: §6 is stale against the provider identity; reverse it.
Goal
Make ratatoskr a complete, self-contained chat client that drives AND observes the full Bifrost round-trip against its own provider — for troubleshooting latent bugs across the affect/memory planes. Two parts:
bifrostfield so a turn dispatches affect/memory to our provider (:8390affect,:8391memory).handshake/upsert_many/search/emit/get/delete) in the debug surface + logs, correlated with the turn that triggered it. Because ratatoskr owns both ends, it can show exactly which memory writes/recalls a given turn produced — the lens for latent-bug hunting.Feasibility anchor
The conversation API already supports client-set binding:
POST /sessionstakes an optionalbifrostfield (issue #160 "MCP-in-reverse"); Worldtree runs the handshake synchronously before 201 (502 on failure, no session created). So the binding is settable from the client in principle — no Worldtree change needed to bind.Open questions (resolve before/during contract)
The authoritative recipe is in flight via infra-ops ↔ worldtree-dev (althing thread
01KV7D82MJYB…, the memory-smoke wiring) — it doubles as this feature's feasibility answer. Loop the result in here.bifrostfield bind affect/memory dispatch, or only #160 tools? affect/memory are separate planes (#204 / #294).memory.agent_self_enabled: false; binding the endpoint may not be enough — may need a memory-enabled agent or session-level promotion-on-bind.endpoint_urlbe HTTPS; our provider is HTTP. Dev-mode relaxation?affect_updateexists; memory equivalent?); admin Bifrost inspection (GET /admin/sessions/{id}/bifrost). Self-loop correlation is the most powerful.Dependencies / risk
Out of scope / supersedes
Pointers
src/ratatoskr/sessions.py(create_session)src/ratatoskr/provider/{affect_store,memory_store,serve,serve_memory}.pydocs/conversation-api-spec.md§"Optional Bifrost binding (issue #160)" (~L977),GET /admin/sessions/{id}/bifrost(~L685)01KV7D82MJYB…Closing — shipped end-to-end and now empirically proven from a real Worldtree-driven turn.
Shipped: self-drive Bifrost binding + dispatch-layer op-feed of affect/memory ops, slices 1–3c (
v0.17.8–v0.17.13) plus the op-feed handshake field-name fix (v0.17.17,d60b77d). The composite both-plane extension (one session binds BOTH planes) landed under #18 (v0.18.0).Final live proof (2026-06-20, personal Worldtree v0.36.0 → composite provider
:8392): one bound session (b83a66b6) dispatched the full both-plane lifecycle through one endpoint, every op correlated to the boundsession_idby the op-feed:handshake→caps_granted=[memory, affect]affect.fetch+memory.search(reads)affect.emit→stored:true— PAD persisted toaffect_snapshotsmemory.upsert_many→upserted:1— promotion chunk persisted tomemory_chunksBoth writes verified directly in our SQLite stores, not just dispatch-ok. This is the thesis realized: ratatoskr, owning both ends of the round-trip, sees exactly which memory/affect ops a turn produced — from the provider side, correlated to the turn that triggered them.