Define the dev-facing CLI contract: `harmony <scope> <verb>` grammar, mandatory explicit context (no default), declarative/operational verb split, three config homes, per-env profile tag, and the machine/agent contract. Add the living CLI use-case & command guide and register it in the mdbook nav. Mark ADR-012 superseded by 025. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
8.5 KiB
Harmony Application CLI — Use Cases & Commands
Status: design target (proposed). Today
harmony_cliruns Scores via flags; none of the verbs below are implemented yet. This is the living reference we are building toward. The decisions and rationale live in ADR-025 — read that for the "why"; this doc is the "what" and "how".
Mental model
Four ideas carry the whole CLI:
harmony <scope> <verb>. A small fixed set of scope nouns —app(developer lifecycle),tenant(tenant-admin),cluster(cluster-admin),context(everyone). What you can run is decided server-side by your context's identity, not by the command existing.- Implicit app, explicit context. The app is this project's app
(inferred — you never name it). The target is always explicit:
--context <name>orHARMONY_CONTEXT. There is no default context; omitting it is a hard error. Even local k3d is--context local. - Declarative vs operational. Verbs that change desired state go through the project's typed Scores and re-converge. Verbs that only read or are ephemeral talk to the cluster directly and never mutate desired state. You never imperatively edit live state — you edit a Score and redeploy.
- Config has three homes, none of them a config file. Behavior → typed Scores (in git). Target + credentials → the context. Secrets → OpenBao.
Contexts & profiles
A context is { cluster (endpoint + CA), tenant, credential source / identity, profile }. It carries no role — authorization is enforced
server-side from the identity's token (Zitadel → OpenBao → RBAC), never a
client-side setting. Contexts are defined out-of-band (user/CI config),
not in the project.
harmony context list # what can I target?
harmony context show myapp-prod # cluster, tenant, profile, identity (+ role, derived from token)
The profile (local | staging | prod) is a structured field the
context carries — not its name. A Score branches on ctx.profile() to
compute per-environment values (prod → 3 replicas + managed Postgres;
local → 1 replica + sqlite), and never parses the context name. The
name (myapp-prod) is a free human handle for picking --context; the
profile field is the authoritative value, so two differently-named contexts
can share profile = Prod (and myapp-prod vs otherapp-prod are two
different contexts at the same profile). See ADR-025 §7.
Credentials ride on the context and degrade: local uses the ambient k3d/kubeconfig; remote mints a short-lived, namespace-scoped token via Zitadel→OpenBao. The CLI holds nothing standing (ADR-025 §10).
app — the developer lifecycle
The verbs, by class:
| Verb | Class | Context? | What it does |
|---|---|---|---|
check |
declarative | no | Compile + type-check the Scores. The only pre-deploy validation today (no live diff yet). |
build |
declarative | no | Build a digest-pinned OCI image; prints the digest. Environment-agnostic. |
publish |
declarative | yes | Push the image to the registry (remote) or k3d image import (local). Topology-specific. |
deploy |
declarative | yes | Converge the Scores against the context, pinned to --image <digest>. Does not build. Returns only after smoke-test. |
ship |
declarative | yes | build + publish + deploy, threading the digest. The everyday verb. |
run |
declarative | yes | Run a one-off Score-driven Job (migration, task). |
logs |
operational | yes | Stream/tail logs. Deep search lives in the observability tool. |
status |
operational | yes | Health, replicas, last deploy, recent events. |
exec |
operational | yes | Shell/exec into a running container. |
forward |
operational | yes | Port-forward a service to localhost. |
restart |
operational | yes | Rollout-restart a workload (pods return identical; no state change). |
describe |
operational | yes | Resource detail + events for diagnosis. |
history |
operational | yes | Deploy history — what shipped, when, which digest. |
Develop (inner loop)
| I want to… | Command |
|---|---|
| Check my Scores compile/type-check | harmony app check |
| Build the image to test it builds | harmony app build |
| Deploy to local k3d and test | harmony app ship --context local |
| See it running locally | harmony app status --context local · harmony app logs --context local -f |
Ship to production
| I want to… | Command |
|---|---|
| Build + publish + deploy to prod | harmony app ship --context myapp-prod |
| Deploy an already-built image | harmony app deploy --context myapp-prod --image <digest> |
| Roll forward to a prior good build (recovery) | harmony app deploy --context myapp-prod --image <prior-digest> |
| Build / publish as separate CI stages | harmony app build → harmony app publish --context myapp-prod → harmony app deploy … |
There is no rollback and no staging (the roll-forward-only model): you roll forward by deploying a known-good digest.
Operate (day-2)
| I want to… | Command |
|---|---|
| Tail logs | harmony app logs --context myapp-prod -f |
| Check health / what's deployed | harmony app status --context myapp-prod |
| Shell into the app | harmony app exec --context myapp-prod -- /bin/sh |
| Reach a service locally | harmony app forward --context myapp-prod 8080:80 |
| Restart the app | harmony app restart --context myapp-prod |
| Run a DB migration | harmony app run --context myapp-prod -- migrate |
| Change replicas / env / resources | edit the Score, then harmony app ship --context myapp-prod |
Changing replicas/env/config is not an imperative command — it's a Score edit + redeploy. An out-of-band
kubectl scalesurvives only until the next deploy, then is reconciled away (ADR-025 §5, §8).
Debug / diagnose
| I want to… | Command |
|---|---|
| Understand why a deploy failed | read the deploy output (convergence errors, rustc-style) |
| See why a workload is unhealthy | harmony app describe --context myapp-prod · harmony app logs … |
| See what shipped recently | harmony app history --context myapp-prod |
| Deep log search / traces / metrics | open the observability tool (HyperDX/SigNoz/Grafana) — the CLI deep-links |
tenant — tenant administration (tenant-admin)
Mostly manual today (ADR-025 Out of scope: step-0 provisioning). Listed as the target surface; authorization is by the context's role.
| I want to… | Command (planned) |
|---|---|
| List apps / environments in my tenant | harmony tenant list --context my-tenant |
| Create an environment (namespace — billed) | harmony tenant env create <name> --context my-tenant |
| Add / remove a developer | harmony tenant member add <user> --context my-tenant |
| See usage vs quota | harmony tenant usage --context my-tenant (or the dashboard) |
| Rotate an app's deploy key | harmony tenant key rotate <app> --context my-tenant |
cluster — cluster administration (platform operator)
Future / manual today. Same noun-by-scope, authorization by role (only a cluster-admin context may run these).
| I want to… | Command (planned) |
|---|---|
| Provision a tenant | harmony tenant create <name> --context <cluster-admin-ctx> |
| Cluster-wide status | harmony cluster status --context <cluster-admin-ctx> |
| Manage platform operators | harmony cluster operator … |
Machine & agent usage
Every verb is built for CI and autonomous agents — the same surface, strict mode (ADR-025 §9):
--json→ a frozen, versioned schema on stdout; logs/progress on stderr.- Non-interactive when stdin isn't a TTY — no hidden prompts.
- Idempotent verbs;
Outcome(SUCCESS/NOOP/FAILURE/RUNNING/BLOCKED) mapped to exit codes so CI/agents branch without scraping text. - A future agent skill / MCP surface is derived from this reference, not authored separately.
Example CI release (digest pinned end-to-end):
DIGEST=$(harmony app publish --context myapp-prod --json | jq -r .image)
harmony app deploy --context myapp-prod --image "$DIGEST" --json
Status legend
Nothing here is implemented yet. As verbs land, tag them:
[impl] implemented · [wip] in progress · [planned] ·
[future] out of v1 scope (per ADR-025). Until the first verbs
ship, treat the whole document as [planned].