staqly CLI
Install the staqly command, write your first post and put it on the calendar from a terminal.
The staqly command writes, schedules and publishes posts, connects channels, manages
schedules and watches the queue, all from a terminal or a script. The same binary also runs
Staqly Community Edition, the whole server, with staqly serve.
Pick the CLI for shell scripts, cron jobs and quick checks. Use an SDK inside a TypeScript or Python program, MCP when an AI agent such as Claude Code talks to staqly directly, and the REST API from any other language.
Get started
Install the binary
curl -fsSL https://raw.githubusercontent.com/staqly/staqly/main/scripts/install.sh | shThe script installs the latest release for macOS or Linux (amd64, arm64) to ~/.local/bin/staqly
and checks the download against the release's checksums.txt. Make sure ~/.local/bin is on
your PATH, then confirm it works:
staqly versionStart a server (or point to one)
If staqly isn't running yet, start it on this computer. It needs no Docker and no account:
staqly serveThe API and MCP endpoint listen on http://localhost:3333, the dashboard on
http://localhost:8080. Leave it running and open a second terminal. Every request needs the
access token staqly printed at start; the CLI on this computer reads it from staqly's data
folder by itself.
Already running staqly in Docker or in the cloud? Skip this step. With Docker, save the access
token once: staqly login --key "$(docker exec staqly server token)". For a cloud server, save
its URL and key once with staqly login --url https://app.staqly.ai --key stk_....
Connect a channel and write a post
staqly channels connect custom --name "My publisher" # your own automation; see `staqly channels providers` for the rest
staqly collections create "Product updates"
staqly posts create "Product updates" --content "v1.4 is out." --channel "My publisher" --publish-at "+1h"posts create prints the new post with its ID and status (scheduled here, because of --publish-at).
Watch it go out
staqly schedule # the calendar for the next 7 days
staqly posts get post_oalirbz67y4m4cqxq5dw
staqly jobs list --status failedOpen the dashboard at http://localhost:8080 to see the same on the Schedule page.
Other ways to install
Windows. Download the .zip for your CPU from the
releases page and put staqly.exe on your PATH.
A specific version or folder. The install script reads two environment variables:
| Variable | Default | Meaning |
|---|---|---|
STAQLY_VERSION | latest release | Release tag to install, e.g. v0.2.0 |
STAQLY_INSTALL_DIR | ~/.local/bin | Where to put the binary |
curl -fsSL https://raw.githubusercontent.com/staqly/staqly/main/scripts/install.sh | STAQLY_VERSION=v0.2.0 shFrom a checkout of the repository. Requires Go and Node:
make dashboard # embeds the dashboard for `staqly serve`
cd apps/cli
make build # → apps/cli/bin/staqly
make install # → $GOBIN, or ~/go/binShell completion:
source <(staqly completion bash) # or zsh
staqly completion fish > ~/.config/fish/completions/staqly.fishRun the server
staqly serve runs the API, MCP endpoint, job queue and dashboard in one process.
staqly serve # dashboard on this computer only
staqly serve --expose # dashboard reachable from phones and tablets
staqly serve --data ~/staqly-data --port 4333 --dashboard-port 9090| Flag | Default | Meaning |
|---|---|---|
--data | ~/.local/share/staqly (or STAQLY_DATA_DIR) | Folder for the SQLite database, uploads, secret.key and access_token |
--port | 3333 | API and MCP port, always bound to 127.0.0.1 |
--dashboard-port | 8080 | Dashboard port |
--expose | off | Serve the dashboard on all network interfaces; phones sign in once with a QR code or a link from staqly serve connect-link |
With a subcommand, staqly serve runs an operator task against the same data instead:
token [--rotate], connect-link, backup <file> and storage migrate. See
Run the binary and Operator CLI.
Connect to a server
By default the CLI talks to Staqly Community Edition at http://localhost:3333, which wants its
access token: against staqly serve on this computer the CLI reads it from the data folder
(STAQLY_DATA_DIR, else ~/.local/share/staqly) when no key is set. Started it with --data
somewhere else? Set STAQLY_DATA_DIR to that folder too. Against Docker pass the token as a key. To use another server, pass flags, set environment variables, or save a profile.
| Setting | Flag | Environment | Profile field | Default |
|---|---|---|---|---|
| API base URL | --api-url (alias --url) | STAQLY_API_URL | url | http://localhost:3333 |
| API key | --key | STAQLY_API_KEY | key | for localhost: the access token of staqly serve on this computer, else none |
| Profile | --profile | STAQLY_PROFILE | current | default |
| Config file | none | STAQLY_CONFIG | none | $XDG_CONFIG_HOME/staqly/config.json, else ~/.config/staqly/config.json |
The first one set wins, in this order: flag, environment variable, selected profile, default.
--url means something else for some commands
webhooks create and webhooks update (the receiver URL) and posts result (the published
post's link) use --url for their own field. Set the API address with --api-url or
STAQLY_API_URL there. Schedules take their endpoint as --endpoint-url.
Save servers as profiles
staqly login --key "$(docker exec staqly server token)" # Community Edition in Docker → profile "default"
staqly login --url https://app.staqly.ai --key stk_... --profile work
echo "$KEY" | staqly login --url https://app.staqly.ai --key - --profile ci
staqly profiles # list (keys masked); * marks the current one
staqly profiles use work # switch
staqly status --profile ci # use a profile for one command
staqly logout --profile ci # remove a profilelogin checks the credentials against GET /v1/session before saving (skip with
--no-verify), writes the config file (folder 0700, file 0600) and makes the profile
current. Without --key it uses STAQLY_API_KEY or asks for the key at a hidden prompt.
How keys are protected
- A key stored in a profile is only sent to that profile's own URL. If
--api-urlorSTAQLY_API_URLpoints somewhere else, the CLI sends no key and prints a note. Pass--keyorSTAQLY_API_KEYto authenticate against the other server. - The CLI warns when a key would travel over plain
http://to a host other thanlocalhost. Usehttps://for remote servers. - Channel credentials passed with
--fieldgo straight to the API and are never written to the config file.
Output formats
- Human-readable tables by default. Colors only appear on a terminal;
NO_COLOR=1,TERM=dumbor--no-colorturn them off. --jsonprints the API response unchanged. Streaming commands (events tail --follow) print one JSON object per line (NDJSON).- With
--json, errors go to stderr as{"error":{"code","status","message","fields","details","retry_after_seconds"}}. - Text from the server (post content, channel names, error messages) is treated as untrusted.
Human output strips control characters, ANSI / OSC escape sequences and Unicode bidi overrides
before printing.
--jsonkeeps the data intact but writes C1 controls and bidi overrides as\uXXXXescapes, so it is still safe to view in a terminal.
Exit codes
| Code | Meaning |
|---|---|
0 | Success. With --wait (posts create --wait, posts publish --wait, posts retry --wait): published |
1 | Error: API, network, failed confirmation, or some posts of a multi-post command failed |
2 | With --wait: the post failed on a channel |
3 | With --wait: the wait timed out (still publishing) |
64 | Usage error: unknown command or flag, missing arguments |
130 | Interrupted (Ctrl+C). --follow exits 0 on Ctrl-C |
Error messages
The CLI turns API errors into plain-language hints:
| Status | What it tells you |
|---|---|
401 | Pass --key or run staqly login; for the Community Edition, where to print the access token |
402 | The plan limit you hit, with usage and maximum |
403 (scope) | Which scope the key is missing |
409 | The post or channel changed, or the state is already set |
422 | Each invalid field, including the channel a text is too long for |
429 | How long to wait (Retry-After) |
When the server can't be reached, the error names the URL it tried.