Overview
stalwart-cli is a small, schema-driven command line tool for administering a Stalwart Mail and Collaboration server. It speaks exclusively to the JMAP API and operates on the management/configuration objects (those whose JMAP type names are prefixed with x:) exposed via the urn:stalwart:jmap capability.
The tool is schema-driven: on first use it downloads (and caches) a JSON schema from the server that describes every object, its fields, the forms used to render it, and the lists used to render queries. All command behaviour, validation, and human-readable output is derived from that schema, so the same binary works against any compatible Stalwart deployment without recompilation.
Capabilities at a glance
Section titled “Capabilities at a glance”| Task | Command | Title |
|---|---|---|
| Inspect what objects and enums the server exposes | describe | Exploring the schema |
| Read a single object by id (or a singleton) | get | Fetching a single object |
| List or filter objects of a given type | query | Searching and listing |
| Create one or more objects | create | Creating objects |
| Modify an existing object (or singleton) | update | Updating objects |
| Destroy one or more objects | delete | Removing objects |
| Apply a bulk plan from a JSON file | apply | Declarative bulk operations |
| Export live server state as an apply plan | snapshot | Exporting server state |
Installation
Section titled “Installation”Pre-built binaries are produced for macOS (Intel and Apple Silicon), Linux (x86_64 and aarch64, glibc and musl), and Windows (x86_64 and aarch64). Pick the installer that matches the platform.
macOS / Linux (shell installer)
Section titled “macOS / Linux (shell installer)”curl --proto '=https' --tlsv1.2 -LsSf \ https://github.com/stalwartlabs/cli/releases/latest/download/stalwart-cli-installer.sh | shWindows (PowerShell installer)
Section titled “Windows (PowerShell installer)”powershell -ExecutionPolicy Bypass -c "irm https://github.com/stalwartlabs/cli/releases/latest/download/stalwart-cli-installer.ps1 | iex"Homebrew (macOS / Linux)
Section titled “Homebrew (macOS / Linux)”brew install stalwartlabs/tap/stalwart-clinpm (Node.js, all platforms)
Section titled “npm (Node.js, all platforms)”npm install -g @stalwartlabs/cliWindows MSI
Section titled “Windows MSI”A signed .msi installer is published with each release at
https://github.com/stalwartlabs/cli/releases/latest. Download and run it for a standard Windows install.
Building from source
Section titled “Building from source”With a recent Rust toolchain (edition 2024):
git clone https://github.com/stalwartlabs/cli.gitcd clicargo install --path .Verify the install with:
stalwart-cli --versionConnecting to a server
Section titled “Connecting to a server”Every invocation needs a server URL and a credential. The same flags are global and may appear before or after the subcommand.
| Flag | Environment variable | Purpose |
|---|---|---|
--url <URL> | STALWART_URL | The Stalwart server endpoint (required). |
--user <USER> | STALWART_USER | Basic-auth username. |
--password <PASS> | STALWART_PASSWORD | Basic-auth password. Prompted interactively if absent and stdin is a TTY. |
--api-key <TOKEN> | STALWART_TOKEN | Bearer token. Mutually exclusive with --user. |
--insecure / -k | (none) | Skip TLS certificate verification (matches curl -k). |
--no-color | (none) | Disable ANSI color output. The NO_COLOR environment variable also disables colors. |
A typical invocation against a local development server:
stalwart-cli --url http://localhost:8080 --user admin --password admin describeEquivalent with environment variables (recommended for scripts and CI):
export STALWART_URL=https://mail.example.comexport STALWART_USER=adminexport STALWART_PASSWORD='changeme'stalwart-cli describeFor unattended use, prefer an API token:
export STALWART_URL=https://mail.example.comexport STALWART_TOKEN='eyJhbGciOi...'stalwart-cli describeObject naming
Section titled “Object naming”The CLI accepts object names with or without the x: prefix and is case-insensitive. The following are all equivalent:
stalwart-cli get Domain abc123stalwart-cli get domain abc123stalwart-cli get x:Domain abc123stalwart-cli get X:DOMAIN abc123Internally, names are normalised to the canonical form before any JMAP request leaves the client. In all human-readable output, the x: prefix is stripped (so x:Domain is shown as Domain).
Singletons
Section titled “Singletons”Some configuration objects are singletons: there is exactly one instance per server. Singletons accept (or default to) the literal id singleton. For example, the JMAP limits singleton can be fetched with either of these:
stalwart-cli get jmapstalwart-cli get jmap singletonSingletons cannot be created or destroyed, only updated. The Updating objects and Fetching a single object pages cover the specifics.
Multi-variant objects
Section titled “Multi-variant objects”Some objects (for example Account) have multiple variants discriminated by an @type field (User, Group, etc.). When creating such an object, two equivalent forms are accepted:
- The shorthand
Object/Variantsyntax (stalwart-cli create account/user ...), which auto-injects@type. - Passing
@typeexplicitly via--fieldor as part of a--jsonpayload.
For get, query, update, and delete, only the bare object name is accepted (the slash form is rejected).
Output formats
Section titled “Output formats”Read commands support --json for machine-readable output. Each output record is a single compact JSON line. Commands that produce a single record (get --json) emit one line. Commands that produce a stream (query --json, apply --json, snapshot) emit NDJSON (newline-delimited JSON): one complete record per line, no enclosing array. This format streams (constant memory regardless of result-set size) and pipes naturally into jq, mlr, awk, and similar tools. To consume an NDJSON stream as a single JSON array, pipe through jq -s '.'.
Without --json, the CLI renders a human-friendly view driven by the schema’s form definitions, with ANSI color when stdout is a TTY.
Color is automatically disabled when:
- stdout is not a TTY (for example, when piping to
head,less, or a file). - The
NO_COLORenvironment variable is set. --no-coloris passed explicitly.
Schema cache
Section titled “Schema cache”The schema is fetched from /api/schema and cached locally under the standard XDG cache directory:
- Linux:
~/.cache/stalwart-cli/<server-hash>/ - macOS:
~/Library/Caches/stalwart-cli/<server-hash>/ - Windows:
%LOCALAPPDATA%\stalwart-cli\<server-hash>\
<server-hash> is a URL-safe base64 of the SHA-256 of the normalised server URL, so multiple Stalwart deployments coexist in the cache without collision. The cache is consulted before each command. If the server hash hasn’t changed, no schema download is issued. If the network is unreachable but a cached copy exists, the CLI emits a warning and proceeds with the cached schema.
Errors
Section titled “Errors”All errors are written to stderr in the form error: <message> and the process exits with a non-zero status. JMAP-level errors are surfaced with their type and description. Per-object set errors (validation failures, primary key violations, dependent-object protection, etc.) include the affected properties and any linked-object information returned by the server.
Piping output to a short-lived consumer such as head or less is handled cleanly: a broken pipe is treated as a normal end of output, not as an error.
Getting help
Section titled “Getting help”Standard help is available for every subcommand:
stalwart-cli --helpstalwart-cli get --helpstalwart-cli apply --helpFor schema-driven help (descriptions of objects, fields, enums, filters, and sort options), use the describe command.