Mosaic one model, many lenses

ADR 0005: The CLI lens is a client, not a twin

  • Status: accepted
  • Date: 2026-09-23

Context

Generators commonly emit an in-process CLI: the binary links the store and handlers directly, so it can run without a server. That is a second deployment of the same state — two binaries to test, two ways for the CLI to disagree with the API, and the "convenience" evaporates the moment the store is anything but trivial.

Decision

The CLI lens generates a typed HTTP client (reqwest) against the running server. mosaic <op> subcommands and the REST API are the same request. State has exactly one home: the process you started with serve. In v0 the store is in-memory, so up (build + serve + run) is the workflow; a persisted store is a later ADR, and the CLI stays a client regardless.

Consequences

  • The CLI cannot drift from the API: both hit the same code path.
  • The generated app is one binary doing two thin jobs (serve, call).
  • The --url flag makes the CLI testable against any instance.

Proof

CI job example, step smoke test (proof of ADR 0005): starts the generated serve process, then drives create/list/custom-op through the generated CLI against that process, asserting the returned total.