When we shipped the first public version of the Stratum CLI, the most common piece of feedback was blunt: it does too much. Developers want tools that do one thing and compose well with the rest of their shell, not a GUI crammed into a terminal. That feedback shaped every subsequent release.
Design principle 1: nouns and verbs, not actions
Most CLI tools are verb-first: deploy, rollback, restart. We started that way too, and ended up with 60 top-level commands that were impossible to discover. The v2 rewrite adopted a noun-first structure: stratum app deploy, stratum app rollback, stratum db connect, stratum logs tail. Every command now has exactly two segments — resource and action — which means tab-completion alone is enough to learn 80 % of the CLI without reading the docs.
Design principle 2: the output is for humans and machines
Every Stratum CLI command supports three output modes:
--format table(default in a TTY): colour-coded, aligned, with status icons — readable in under two seconds.--format json: machine-readable, one object per line (NDJSON) for safe piping intojqor custom scripts.--format quiet: prints only the primary identifier (e.g. the deploy ID) with no decoration — designed for shell scripting where you want to capture and pass on a single value.
The format is detected automatically from whether stdout is a TTY. Scripts that pipe stratum app list into grep always get the quiet format; developers running the command directly get the table. This rule — honour the terminal context — eliminated 90 % of the script-vs-human output complaints.
Design principle 3: errors must be actionable
An error message that says Request failed: 403 is not an error message — it is a bug report waiting to happen. Every Stratum CLI error follows a three-part structure: what went wrong, why it likely happened, and what to do next. Example:
Error: deploy failed — image registry.stratum.io/acme/api:v2.3.1 not found.
Cause: the image tag was pushed to a private registry the service account cannot pull from.
Fix: run stratum registry grant acme/api --service-account deploy-sa to add pull permission, then retry.
Design principle 4: context awareness reduces friction
The CLI reads a .stratum/config.yaml from the project root and infers defaults: the active app, the target environment (staging vs production), and the region. A developer in a repo that has this file can run stratum deploy with no flags at all. Flags are available to override every default, but they are never required for the 80 % case. This is the principle we call sensible defaults, full control.
What we would do differently
- Ship tab-completion on day one. We added it in v1.4, eight months after launch. It is now the most-used feature. Every developer who onboarded before v1.4 had a worse first week than they needed to.
- Invest in interactive mode earlier.
stratum init --interactivenow walks developers through project setup with prompts and sane defaults. It was the most-requested feature for the first year and we kept postponing it for "real" features. - Never break flags silently. We renamed
--envto--environmentin v2.0 without a deprecation warning. The support tickets ran for six months.