crabidy/architecture/cbd-bundle.md

106 lines
4.4 KiB
Markdown

# cbd: bundled server + client binary
## Context and problem statement
`crabidy-server` and `cbd-tui` are separate binaries: the normal setup
runs a long-lived server and attaches TUIs to it. The user wants a
single binary **`cbd`** for the one-machine case: starting it starts the
server and connects the TUI to it. Everything else works exactly the
same — same config *format*, same gRPC wire, same features. (`cbd` reads
its own `cbd.toml`, not `cbd-tui.toml`; see the resolved note under
Risks.)
## Assumptions (confirmed)
- `cbd-tui`'s config (`cbd-tui.toml`) already carries the server
address; the server listens on a constant (`0.0.0.0:50051`).
- Both mains are thin shells over module code: the server's `main.rs`
holds the command/message enums and the startup sequence; the TUI's
holds tracing setup and two loops (`orchestrate`, `run_ui`).
- The gRPC boundary stays: the bundled TUI talks to the in-process
server over localhost exactly like a remote one ("works the same
completely"). No in-process transport special-casing.
## Decisions
### D1 — Both binaries become libraries with thin mains
- **crabidy-server**: `playback`, `provider`, `rpc` move from bin
modules to lib modules; the command/message enums and the startup
sequence move into the lib (`serve(addr)` builds orchestrator, queue
store, playback, rpc service and serves tonic on `addr`). `main.rs`
keeps only stderr tracing setup + `serve(LISTEN_ADDR)`.
- **cbd-tui**: gains `src/lib.rs` exposing `run(config)` (the two loops
and their channels); `main.rs` keeps file-based tracing setup +
config init + `run`.
- Behavior-preserving: no logic changes, only module moves and
`crabidy_server::``crate::` path rewrites. All existing tests move
along unchanged.
Not chosen: `cbd` spawning `crabidy-server` as a subprocess — that
needs the second binary installed, which is exactly what "a single
binary" is for.
### D2 — `cbd` = start (or adopt) the server, then run the TUI
New tiny binary crate `cbd`:
1. Tracing goes to the TUI's log file for **both** halves — the
terminal belongs to the TUI, so the server's stderr logging would
corrupt it.
2. Spawn `crabidy_server::serve(LISTEN_ADDR)` on a background task.
If the port is already taken (`AddrInUse` — a standalone server is
running), log and carry on: the TUI simply connects to the existing
server. Any other server error before readiness is fatal.
3. Wait for readiness by polling a TCP connect against the configured
server address (bounded retries with delay, then a clear error).
4. Run the TUI exactly as `cbd-tui` would, with the same
`cbd-tui.toml`.
Quitting the TUI ends the process — and with it the in-process server.
That is inherent to bundling and fine: the current queue is persisted
continuously, so the next start restores it (the ≤200 ms persist
debounce window is the same loss window as killing the standalone
server).
### D3 — Out of scope (explicitly)
- An in-process (channel) transport instead of localhost gRPC.
- Daemonizing: `cbd` never outlives its TUI. Users who want a
persistent server keep running `crabidy-server`.
- CLI subcommands (`cbd server`, `cbd attach`, …) — later if wanted.
## Structure
```d2
direction: right
cbd: "cbd (one binary)" {
boot: "main: file tracing,\nspawn server, wait, run TUI"
srv: "crabidy-server lib\nserve(addr)"
tui: "cbd-tui lib\nrun(config)"
boot -> srv: "tokio::spawn\n(AddrInUse → adopt)"
boot -> tui: "after TCP readiness"
tui -> srv: "localhost gRPC\n(unchanged wire)"
}
standalone: "crabidy-server bin\n(unchanged)"
remote: "cbd-tui bin\n(unchanged)"
remote -> standalone: "gRPC (remote setup\nkeeps working)"
```
## Risks and open questions
- **Separate client configs (resolved 2026-07-21)**: originally `cbd`
and `cbd-tui` both read `cbd-tui.toml`, so pointing that file at a
remote server (the standalone `cbd-tui`'s job) also dragged `cbd`'s
own TUI to the remote while it started an unused local server. `cbd`
now reads its own `cbd.toml` (same option set, defaulting to
localhost — matching its in-process server), so the self-contained
`cbd` and a remote-pointed `cbd-tui` coexist on one machine. See
`architecture/client-configs.md`.
- **Two log producers, one file**: server and TUI layers share the
bundled tracing subscriber; targets distinguish them.
- Open (future): a `--no-server` flag; graceful server shutdown (flush
the persister) on TUI exit.