# sylphx (CLI)
Production **Rust** operator CLI for the Sylphx Cloud **Management plane**.
**Customer install/update contract (SSOT):**
[`docs/how-to/install-and-update-sylphx-cli.md`](../../docs/how-to/install-and-update-sylphx-cli.md)
**Policy:** [ADR-4437](../../docs/adr/ADR-4437-cli-distribution-and-update-authority.md)
**Site:** [sylphx.com/docs/cli](https://sylphx.com/docs/cli)
## Boundary (ADR-3820)
| Orgs, projects, deploy, env, logs, resources, domains, secrets, tokens, billing | Customer app BaaS runtime (`sk_*` / tenant APIs) |
| Agent/CI automation via `SYLPHX_TOKEN` | Console-only visual builders |
| Device-flow human login | Direct cluster / DB mutation |
Dogfoods `sylphx-sdk-management` (Protobuf wire `sylphx.platform.v1`).
## Install
Pick **one** channel and use the **same** channel to upgrade later.
| **curl (standalone)** | `curl -fsSL https://sylphx.com/install/cli \| bash` |
| **npm** | `npm install -g @sylphx/cli` |
| **Cargo** | `cargo install sylphx-cli --locked` |
| **Homebrew** | `brew install sylphxai/tap/sylphx` |
There is **no** WASM operator CLI. npm only distributes the Rust binary.
## Update
**Update the way you installed.** Silent auto-update is forbidden.
| curl / standalone | `sylphx update` or re-run the install script |
| npm / pnpm / bun | `npm install -g @sylphx/cli@latest` (or pnpm/bun) |
| Cargo | `cargo install sylphx-cli --locked --force` |
| Homebrew | `brew upgrade sylphx` |
```bash
sylphx update --check # status only
sylphx update # explicit upgrade
```
Happy path is short (e.g. `sylphx 0.2.6 is current`). Details: `--check` / `--json`.
## Day-1
```bash
sylphx login # browser device approval (user JWT)
sylphx doctor # auth + API base + context diagnostics
sylphx whoami
sylphx context use --org-id org_… --slug my-org
sylphx projects list
sylphx link --project proj_… --org-id org_…
sylphx candidates publish --work-item wi_… --producer-attempt att_…
sylphx deployments list --project proj_…
sylphx status proj_…
sylphx logs --project proj_… --tail 100
```
Agent / CI:
```bash
export SYLPHX_TOKEN=svc_...
export SYLPHX_API_URL=https://api.sylphx.com/v1 # optional; host-only is auto-healed to /v1
sylphx doctor --json
sylphx projects list --org-id org_… --json
```
## Auth model
| OAuth session (device login) | `sylphx login` | ✅ user + orgs | ✅ (needs org context) |
| Service token `svc_*` | `SYLPHX_TOKEN` / `login --token` | no user profile (expected) | ✅ |
Device login discovers the RFC 8414 authorization server, stores a rotating
access/refresh pair atomically, and refreshes before expiry. `sylphx logout`
revokes both credentials before clearing the local file; `--local-only` is an
explicit offline containment option.
Credentials live at `~/.config/sylphx/credentials.json` (mode 0600 in a mode
0700 directory). Access, refresh, and device credentials are never printed.
Preferred org: `~/.config/sylphx/context.json`.
Directory link: `./.sylphx/project.json` (`sylphx link`).
API base URLs are **always normalized** to include `/v1`. A poisoned
`https://api.sylphx.com` credential is healed on read so `/whoami` never
hits the bare-root 404 again.
## Command surface
See `sylphx version-info --json` → `shippedCommands` for the authoritative list.
Highlights:
- `doctor` / `config` / `context` / `link` / `unlink` / `open` / `update` / `wait` / `catalog` / `init` / `inspect` / `tail`
- `candidates publish` / `candidates get` for the immutable, Work-bound delivery handoff
- `domains` / `secrets` / `tokens` / `billing` / `services` / `webhooks` / `certs` / `releases` / `runners` / `sandbox` / `volumes` / `users`
- `admin get` passthrough for residual Management routes
- `delivery configuration get` to inspect the authoring revision used by Release creation
- `delivery policy get` / `delivery policy patch` for versioned environment policy
- `api METHOD PATH` escape hatch for any Management REST route
## Explicit delivery
`deployments` registers and reads immutable completed builds. `releases` assembles
those deployments for an explicit environment, then requests promotion through
that environment's policy. The source-triggered `deploy --ref/--force/--env`
command is retired.
The CLI resolves the supplied or linked project through the authenticated Project
API before a delivery request, so existing links containing a slug retain their
organization scope and use the returned exact project identity. A failed lookup
stops the command before any delivery mutation.
```bash
sylphx deployments create --project proj_… --service svc_… \
--completed-build bld_… --idempotency-key register-build_…
sylphx deployments get deployment_… --project proj_…
sylphx delivery policy get --project proj_… --environment env_…
sylphx delivery configuration get --project proj_… --environment env_… --service svc_…
sylphx releases create --project proj_… --environment env_… \
--policy-revision policy_… --members release-members.json \
--idempotency-key create-release_…
sylphx releases get release_… --project proj_… --environment env_…
sylphx releases promote release_… --project proj_… --environment env_… \
--expected-selection-generation 7 --expected-policy-revision policy_… \
--idempotency-key promote-release_…
sylphx releases receipts release_… --project proj_… --environment env_…
sylphx releases decisions release_… --project proj_… --environment env_…
```
Use the actual IDs, current policy revision, and observed selection generation
returned by the service. Project and organization selectors default to the linked
context. List commands support `--page-token` and `--page-size`.
`release-members.json` is a JSON array of generated `CreateReleaseMember` inputs
from [the delivery contract](../../api/proto/sylphx/app/v1/delivery.proto). For each
selected service, pass its service and deployment IDs, selection
`RELEASE_MEMBER_SELECTION_SELECTED`, and the exact `authoringRevision` returned
by `delivery configuration get` as `expectedAuthoringRevision`. The server seals
the current configuration, immutable secret versions, migration, and runtime
references. Clients do not submit configuration digests or runtime revision IDs.
A carried member uses `RELEASE_MEMBER_SELECTION_CARRIED`, binds both
`carriedFromReleaseId` and `carriedFromMemberId`, and omits
`expectedAuthoringRevision`. The server preserves that predecessor member's exact
sealed configuration.
`delivery policy patch` takes a typed `DeliveryPolicyPatch` file using `--patch`,
plus `--expected-policy-revision`, `--expected-policy-version`, and
`--idempotency-key`. An omitted field preserves it; explicit `false` or an empty
`requiredProofs` set changes it. `releases promote --plan` evaluates the selection
without applying it.
The CLI composes and installs the protobuf type registry once at startup, using
`register_wire_types` from the SDK core to include well-known and generated Apps
types. This preserves concrete Operation results, including IDs needed by the
next command. SDK transports leave the host application's registry intact.
Mutation output is the returned Operation. Pending acceptance is not deployment
or live verification, and terminal Operation failures exit nonzero. Read the
exact Release and its receipts and decisions to inspect each delivery stage.
`status`, `inspect`, and `wait` show project observations; `wait` does not track a
submitted Release and may return immediately for an already healthy project.
For recovery, inspect the current authoring revisions and create a new Release
selecting trusted existing deployments. Configuration and migration compatibility
remain part of admission. Use `--previous-release` to
bind the predecessor where appropriate, then promote with the current policy and
selection-generation fences. This preserves artifact digests without rebuilding
from source. Recovery remains unverified until the new Release's runtime and
customer evidence satisfy its policy. There is no separate `rollback` or
`recover` RPC.