# 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.