You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Operator request, from running v0.14.0: one command that serves every deployment, a way to move between them in the browser, and both surviving a reboot or a crash.
What exists today
keel serve is one process, one --db/--config pair, one port (DEFAULT_PORT = 8765). modeBadge states the invariant: "one process serves one --db/--config pair". Starting the live console is:
./keel-live serve
The deployment has four of these, not two — keel-live (config.live-sandbox.yaml + keel-live.db), keel-paper (config.paperforward.yaml, default keel.db), keel-paperhourly (config.paper-hourly.yaml + keel-paperhourly.db), and config.paper-equities.yaml. Any design here should assume N, not 2.
launchd plists exist for the agent cycles (com.keel.live, com.keel.paperforward, com.keel.paper-hourly, com.keel.paper-equities) and for nothing else. There is no plist for serve, so the console is manual today and dies with its terminal.
The blocker, which is not the obvious one
Two servers means two ports, and a different port is a different origin. That breaks the switcher in a way a link cannot fix:
new_session_token() mints a token per process, and security.py is explicit that "nothing is persisted on this side of the wire."
The session cookie is per-origin, so :8766 never sees :8765's cookie.
A link from the live console to the paper console therefore arrives unauthenticated and lands on the 403 "refused" view.
So "switch between modes" is not a nav item. It requires one of:
A token the operator can carry — pasting the other server's URL, which is what the refused view already offers. Works, but it is the manual step this request exists to remove.
One process serving several deployments — see below.
Why "one process, several databases" is the tempting answer and the dangerous one
It removes the port and token problem entirely: one origin, one token, a real switcher. It also puts the live database and the paper databases behind one process and one token, and makes "which deployment is this row from" a runtime variable rather than a process-level fact.
The current design leans on that fact hard. modeBadge's tooltip names the pair because the pair is fixed. A rendering bug in a multi-deployment server could show live figures under a paper label — the exact class of false claim _session_banner refuses to make, and on the one surface where the stakes are real money.
Not ruling it out. Recording that it changes the blast radius of a UI bug from "wrong number" to "wrong account", and that it needs the argument made explicitly rather than arrived at because it was convenient.
Auto-start is the separable, easy half
RunAtLoad + KeepAlive in a com.keel.serve.*.plist covers boot and crash restart, and needs none of the above resolved. Notes for whoever builds it:
One plist per deployment, mirroring the existing four, each pinning its own --port.
How does the operator get the URL? Under launchd nobody reads stdout; the token goes to StandardOutPath. So the printed URL — the only way in — becomes a line in a log file. That is workable (grep the log) and it is a genuinely worse experience than today's terminal. It is also the strongest argument for a keel console / keel open command that reads the running server's URL, which does not exist.
Operator request, from running
v0.14.0: one command that serves every deployment, a way to move between them in the browser, and both surviving a reboot or a crash.What exists today
keel serveis one process, one--db/--configpair, one port (DEFAULT_PORT = 8765).modeBadgestates the invariant: "one process serves one--db/--configpair". Starting the live console is:The deployment has four of these, not two —
keel-live(config.live-sandbox.yaml+keel-live.db),keel-paper(config.paperforward.yaml, defaultkeel.db),keel-paperhourly(config.paper-hourly.yaml+keel-paperhourly.db), andconfig.paper-equities.yaml. Any design here should assume N, not 2.launchd plists exist for the agent cycles (
com.keel.live,com.keel.paperforward,com.keel.paper-hourly,com.keel.paper-equities) and for nothing else. There is no plist forserve, so the console is manual today and dies with its terminal.The blocker, which is not the obvious one
Two servers means two ports, and a different port is a different origin. That breaks the switcher in a way a link cannot fix:
new_session_token()mints a token per process, andsecurity.pyis explicit that "nothing is persisted on this side of the wire.":8766never sees:8765's cookie.So "switch between modes" is not a nav item. It requires one of:
Why "one process, several databases" is the tempting answer and the dangerous one
It removes the port and token problem entirely: one origin, one token, a real switcher. It also puts the live database and the paper databases behind one process and one token, and makes "which deployment is this row from" a runtime variable rather than a process-level fact.
The current design leans on that fact hard.
modeBadge's tooltip names the pair because the pair is fixed. A rendering bug in a multi-deployment server could show live figures under a paper label — the exact class of false claim_session_bannerrefuses to make, and on the one surface where the stakes are real money.Not ruling it out. Recording that it changes the blast radius of a UI bug from "wrong number" to "wrong account", and that it needs the argument made explicitly rather than arrived at because it was convenient.
Auto-start is the separable, easy half
RunAtLoad+KeepAlivein acom.keel.serve.*.plistcovers boot and crash restart, and needs none of the above resolved. Notes for whoever builds it:--port.StandardOutPath. So the printed URL — the only way in — becomes a line in a log file. That is workable (grepthe log) and it is a genuinely worse experience than today's terminal. It is also the strongest argument for akeel console/keel opencommand that reads the running server's URL, which does not exist.KeepAlivetherefore makes the An installed PWA cannot authorise itself after a serve restart — start_url carries no token #634 tail routine rather than rare: after any crash-restart, an installed PWA with an evicted worker cache has no way back in. That is Device pairing for the console: a verifier on keel's disk, the secret on the device — blocked on #648 #656's case, andKeepAlivemakes it common enough to matter.Suggested split
Acceptance
modeBadgestill names the exact--db/--configbeing served, per console