1ctl v1 Contract
This page is the product and engineering contract for 1ctl v1. It complements 1ctl --help: help output lists commands and flags, while this page explains the expected behavior, current implementation status, and gaps that should be closed before the CLI feels reliable for day-to-day deployment work.
Status labels used in this page:
| Label | Meaning |
|---|---|
| Implemented | Present in the current CLI/backend path and verified in normal use. |
| Partially implemented | Usable, but behavior or cleanup is incomplete. |
| Known gap | Current behavior can mislead users, leave drift, or lacks an expected operational command. |
| V1 target | Recommended behavior for a robust version 1, based on common PaaS CLI patterns such as flyctl, railway, and render. |
Core promise
Section titled “Core promise”1ctl should let a developer deploy, inspect, debug, scale, and destroy an app without knowing Kubernetes. It can expose Kubernetes concepts when they help explain behavior, but its primary contract is user-facing:
1ctl deploycreates or updates an application.1ctl deploy --waittells the truth about what became ready.1ctl deploy get/statusshow the current source of truth.1ctl logsand1ctl logs streammake debugging possible immediately.1ctl deploy destroyremoves what the platform created, or clearly says what remains.
Current command surface
Section titled “Current command surface”The current 1ctl --help command surface includes:
| Command | Status | Purpose |
|---|---|---|
auth | Implemented | Login, logout, and auth status. |
profile | Implemented | Named API endpoints and credentials. |
org / organization | Implemented | Organization selection and listing. |
init | Implemented | Create satusky.toml. |
launch | Implemented | Interactive project detection and config creation. |
deploy | Implemented | Build and deploy apps; manage releases, rollback, restart, scale, destroy. |
secret | Implemented | Manage encrypted deployment secrets. |
env / environment | Implemented | Manage non-sensitive environment variables. |
domains / domain | Partially implemented | Attach, list, remove, and check domains. Route reconciliation needs hardening. |
machine | Implemented | List owned machines, available machines, and usage records. |
logs | Implemented | Fetch recent logs and stream live pod logs. |
credits / billing | Implemented | Credit balance and billing state. |
notifications / notif | Implemented | Notification history and preferences. |
user | Implemented | User account details. |
token / api-token | Implemented | API token lifecycle. |
marketplace / market / apps | Implemented | Browse and deploy marketplace apps. |
audit | Implemented | Audit log queries. |
pricing / price | Implemented | Machine pricing information. |
cluster | Implemented | Cluster and zone information. |
completion | Implemented | Shell completions. |
Docs may contain older platform or admin-oriented pages for services, ingress, issuers, object storage, Talos, or admin operations. Treat those as platform/internal or legacy unless they appear in your installed 1ctl --help.
| Page / command | Label | Current guidance |
|---|---|---|
cli/service / 1ctl service | Legacy/manual | Services are created by 1ctl deploy; do not rely on direct service commands unless your CLI exposes them. Tracked in satu-docs#1. |
cli/ingress / 1ctl ingress | Legacy/manual | Default deploys use Gateway API HTTPRoute; use 1ctl domains for domain work. Tracked in satu-docs#1. |
cli/issuer / 1ctl issuer | Legacy/manual | TLS should be managed by the platform route/domain flow. Tracked in satu-docs#1. |
cli/storage / 1ctl storage | Legacy/not current help | This page describes old S3 object storage commands. Persistent app data uses deploy volumes. Tracked in satu-docs#1, 1ctl#44, and 1ctl#47 for the malformed unknown-command error. |
cli/talos / 1ctl talos | Internal | Platform-operator node management, not app deployment. Tracked in satu-docs#1. |
cli/admin / 1ctl admin | Internal | Super-admin/platform operations, not regular user workflows. Tracked in satu-docs#1. |
Deploy readiness contract
Section titled “Deploy readiness contract”Implemented. 1ctl deploy --wait waits for pods to become healthy. A verified deployment can return:
Status: RunningMessage: Deployment is running normallyProgress: 100%Known gap. Pod readiness and public URL readiness are not the same thing. A deployment can have healthy pods while its generated URL is not resolvable or not attached to the live route.
Tracked in:
- 1ctl#41 for CLI
deploy --waitreadiness reporting. - satusky-core_backend#337 for backend route/domain drift after destroy/redeploy.
Observed failure mode:
- Backend recorded
happygiraffe-3u7lttk.satusky.com. - Kubernetes
HTTPRoutestill containedsilentgiraffe-6z2enyu.satusky.com. 1ctl deploy --waittimed out waiting for DNS, then still reported deployment success.- The old hostname remained live and routed to the new pod.
V1 target. 1ctl deploy --wait should report readiness in separate dimensions:
Deployment: healthyPods: RunningPublic URL: not readyReason: DNS unresolved / route mismatchURL: https://happygiraffe-3u7lttk.satusky.comIf --wait means “wait until the app is publicly reachable”, URL failure should produce a non-zero exit. If --wait means “wait until pods are ready”, the CLI should say so and avoid implying the URL is live.
Domain and route reconciliation
Section titled “Domain and route reconciliation”Implemented. The CLI can list, add, remove, and check domains:
1ctl domains list1ctl domains add api.example.com --app my-api --custom-dns1ctl domains remove api.example.com --app my-api1ctl domains check api.example.comKnown gap. Backend domain metadata can drift from Kubernetes routing state. The platform must treat the database and Kubernetes route as a single reconciled unit.
Tracked in:
- satusky-core_backend#337 for deploy/destroy route drift.
- satusky-core_backend#338 for domain status API fields.
- 1ctl#43 for
domains checkdiagnostic output.
V1 target.
deployshould create or update theHTTPRoutehostname that matches the domain returned bydeploy get.destroyshould remove all owned public route resources or state exactly what remains.domains checkshould show DB ownership, Kubernetes route attachment, DNS records, and TLS state separately.- Stale domains should return a real not-found or detached status, not an empty object with invalid timestamps.
Persistent storage contract
Section titled “Persistent storage contract”Implemented. A deployment can request a persistent volume through flags:
1ctl deploy --volume-size 1Gi --volume-mount /app/dataThe equivalent satusky.toml shape is:
[volume]size = "1Gi"mount = "/app/data"Partially implemented. Volume creation is wired through deploy, but volume lifecycle commands are not yet as complete as mature CLIs. The CLI code currently registers volumes for cleanup visibility, while full backend delete support for deploy-created PVCs is still a gap.
Tracked in:
- 1ctl#44 for first-class volume lifecycle commands.
- satusky-core_backend#339 for backend PVC lifecycle and destroy reconciliation.
V1 target. Storage should have an explicit lifecycle comparable to fly volumes:
1ctl volumes list1ctl volumes create --name data --size 1Gi1ctl volumes attach --deployment-id <id> --mount /app/data1ctl volumes detach --deployment-id <id>1ctl volumes destroy <volume-id>Until then, docs and CLI output must be careful: deploy destroy should not promise PVC deletion unless the backend has actually deleted the PVC.
Logs contract
Section titled “Logs contract”Implemented.
1ctl logs --deployment-id <id> --tail 201ctl logs stream --deployment-id <id> --batch-size 51ctl logs supports --tail. 1ctl logs stream does not support --tail; it supports --batch-size.
V1 target. Both commands should make target resolution explicit: whether they used --deployment-id, satusky.toml, namespace/app flags, or current profile.
Tracked in 1ctl#45.
Output and scripting contract
Section titled “Output and scripting contract”Implemented. JSON output is a global flag:
1ctl -o json deploy listKnown gap. Some users naturally try 1ctl deploy list -o json, but global flags are not consistently accepted after subcommands.
Tracked in 1ctl#42.
V1 target. Either support global flags in both positions or document the strict form everywhere:
1ctl -o json <command> <subcommand>For CI, commands should return structured fields for:
- deployment ID
- image
- pod status
- public URL
- public URL readiness
- route hostname
- DNS state
- TLS state
Destroy contract
Section titled “Destroy contract”Implemented. 1ctl deploy destroy deletes the deployment record and associated app resources for normal cases.
Known gap. A verified case showed a previous HTTPRoute hostname surviving destroy and routing traffic to a later deployment with the same app name.
Tracked in:
- 1ctl#46 for per-resource destroy reporting.
- satusky-core_backend#337 for route cleanup/reconciliation.
- satusky-core_backend#339 for PVC lifecycle behavior.
V1 target. Destroy should be idempotent and auditable. It should report each resource class:
Deployment: deletedService: deletedHTTPRoute: deletedDNS record: deleted or not ownedTLS certificate: deleted or retainedPVC: retained or deletedFor destructive resources such as PVCs, the CLI should make retention/deletion explicit instead of hiding it in a generic confirmation prompt.
Local development and private APIs
Section titled “Local development and private APIs”For local backend testing, point the CLI at the local API route:
export SATUSKY_API_URL=http://localhost:8080/v1/cliProfiles can persist the same endpoint:
1ctl profile create --url http://localhost:8080/v1/cli local1ctl profile use localThe API URL resolution order is:
--api-urlSATUSKY_API_URL--profile/ active profile- production default
Good v1 acceptance checklist
Section titled “Good v1 acceptance checklist”A release should be considered a good v1 when these checks pass consistently:
- First deploy from
satusky.tomlbuilds, creates the deployment, creates the service, creates a route, and returns a usable URL. See 1ctl#41 and satusky-core_backend#337. - Redeploy updates the same deployment without duplicate routes or stale DNS. See satusky-core_backend#337.
deploy --waitdistinguishes pod readiness from URL readiness. See 1ctl#41.deploy get/statusagree with Kubernetes state. See satusky-core_backend#337 and satusky-core_backend#338.logsandlogs streamwork with deployment ID and config-based resolution. See 1ctl#45.domains checkreports DB, route, DNS, and TLS state. See 1ctl#43 and satusky-core_backend#338.- Volume-backed apps can prove a PVC is mounted at the requested path. See 1ctl#44 and satusky-core_backend#339.
- Destroy removes or clearly reports every created resource. See 1ctl#46, satusky-core_backend#337, and satusky-core_backend#339.
- JSON output is stable enough for CI scripts. See 1ctl#42.