CLI commands
This page lists the main keelson CLI commands and the behavior scripts and agents need to account for. An AI agent typically runs them through an Agent Skill, so you do not need to memorize them all. Use keelson <command> --help for command-specific help.
See the Quickstart to install the CLI. Run keelson upgrade to update it.
In the examples below, <...> is a value to supply and [...] marks optional arguments or flags. Use durations such as 30s or 5m for <duration> and integers for <n>.
Common flags
Section titled “Common flags”These flags are shared by several commands, but support varies. Commands such as login, logout, install-agent, and dev ... accept only some of them. app curl does not accept --json or --quiet.
| Flag | Description |
|---|---|
--app <slug> | Target app; resolved from keelson.yaml in the current directory when omitted. Required for access show, access set, apps tokens create, apps tokens rotate, and feedback |
--workspace <slug|name|id> | Target workspace by slug, name, or ID. Use the slug or ID if names are ambiguous |
--json | Output the result as JSON. Use this from scripts and agents |
--quiet | Suppress explanations and progress; output depends on the command |
--timeout <duration> | API call timeout; default 15 seconds, with exceptions below |
--retry <n> | Retry count for temporary failures; default 0, with exceptions below |
--no-browser | Show a login or approval URL without opening a browser. Supported by login, apps delete, db apply, and snapshots restore |
Workspace selection follows this order: --workspace, workspace in keelson.yaml, then the saved default workspace. If no workspace is selected, the CLI automatically selects your only workspace; if you belong to several, supply --workspace. The exception is apps list, which lists all workspaces when the flag is omitted.
With --quiet, secrets set prints one line per secret name and deploys list prints one line per deployment ID. A successful deploy --check prints nothing.
Timeout and retry exceptions:
apps duplicatedefaults to a 120-second timeout.- The app request made by
app curldefaults to a 130-second timeout. Temporary GET / HEAD failures are retried up to twice; use--retry 0to disable retries. - App creation in
deploy --newretries temporary failures up to three times even with--retry 0. This retry count cannot be set below three. A value above three sets the higher limit.
preview and app curl do not accept --no-browser, even when browser approval is required. In non-interactive execution, they print an approval URL without opening a browser. The same applies to preview --json.
When a command fails with --json, standard output contains an error object. Its code identifies the error, message explains it, and hint describes what to do. If retryable is false, do not retry automatically; follow hint.
Older names such as --tenant and keelson tenants list are still accepted. See Command aliases.
| Command | Description |
|---|---|
keelson login [--no-browser] | Log in through a browser and link this device |
keelson logout [--all-devices] | Delete saved login credentials on this device and invalidate the server-side session. --all-devices logs out every device. Tokens supplied through KEELSON_TOKEN are not revoked |
keelson whoami | Show the signed-in user and currently selected workspace. Use workspaces list --json to reliably obtain a workspace slug |
keelson workspaces list [--query <text>] [--exact] | List or search your workspaces. Pass the slug from --json output to --workspace |
keelson doctor [--fix-path] | Check PATH, login, and Skill status. --fix-path adds PATH to the shell configuration file |
keelson install-agent <claude-code|codex|cursor> [--global] | Install the Skill for an AI agent. With no argument and --yes, update all installed Skills |
keelson upgrade | Update the CLI to the latest version |
keelson version | Show the version |
keelson telemetry status|off|on | Show, disable, or enable CLI usage telemetry |
keelson feedback --app <slug> [--deploy <id>] < feedback.json | Send feedback about the CLI and the Skill as JSON on standard input. See Feedback |
As an alternative to keelson install-agent, install the Skill from the public repository using the Claude Code plugin commands /plugin marketplace add keelsonhq/skills followed by /plugin install keelson@keelson-skills, or use npx skills add keelsonhq/skills for other agents. Use only one installation method; combining them can create two copies of the Skill or cause one installation to overwrite the other. These alternatives install only the Skill, so you must also install the CLI and sign in.
A Skill installed as a Claude Code plugin is not updated by keelson login; it follows Claude Code plugin updates instead. The plugin is outside the location checked by keelson doctor, so you can ignore its “not configured” result and its suggestion to run install-agent for Claude Code.
Deploy
Section titled “Deploy”| Command | Description |
|---|---|
keelson deploy | Deploy the app in the current directory. See below for when it waits for completion |
keelson deploy --new [--region <region>] [--secrets-from-env-file <path>] | Create an app and deploy it for the first time. Register env file values as secrets and exclude that file from the archive |
keelson deploy --check [--json] | Validate configuration and show archive contents, exclusions, and potentially sensitive files without uploading. This local check cannot determine whether you will exceed plan limits |
keelson deploy --ndjson --yes | Stream progress as one JSON object per line for scripts |
keelson status [deploy_id] [--wait] [--max-wait <duration>] | Show the specified deployment’s status, or the app’s latest deployment if no ID is supplied |
keelson diagnose [deploy_id] | Diagnose a failed deploy (with an ID), including stored startup logs when startup failed, or the running app (without an ID) |
keelson deploys list [--limit <n>] [--offset <n>] | Show deployment history |
keelson deploys download <deploy_id> [-o <path>] | Download the source archive used for a deployment, within its retention period |
keelson rollback [deploy_id] [--yes] | Return to the previous successful deployment or a specified successful deployment |
When deploy waits for completion
Section titled “When deploy waits for completion”| Invocation | Behavior |
|---|---|
keelson deploy in an interactive terminal | Waits for completion; default 30 minutes, configurable with --watch-timeout |
keelson deploy --yes in a pipe, CI, or other non-interactive environment | Returns when accepted. Use --yes --watch to wait |
--json | Returns when accepted; cannot be combined with --watch |
--ndjson | Waits for completion; cannot be combined with --no-watch |
--no-watch | Returns when accepted, even in an interactive terminal |
In normal output mode, non-interactive execution requires --yes; omitting it produces confirmation_input_unavailable. --json, --ndjson, and --quiet run without asking for confirmation.
Reaching the watch timeout stops monitoring, but does not stop the server-side deployment. Continue checking with status --wait.
Check completion with status
Section titled “Check completion with status”status --wait waits up to 50 seconds by default. Set a different limit with --max-wait <duration>. At the limit it returns the latest status it retrieved. If status retrieval succeeds, the exit code is 0 even when the deployment is still running.
Scripts must inspect terminal and status in --json output, rather than relying on the exit code alone. terminal: false means the deployment is unfinished. Success requires terminal: true and status: "completed".
A previous successful revision may still be serving even when the latest deployment failed. Use keelson app info to check the app currently serving traffic.
Rollback behavior
Section titled “Rollback behavior”Only successful deployments with a container image can be rollback targets. To revert a static site, redeploy its previous source. Rollback skips the build but runs db.migrate again.
rollback returns when accepted. Pass the returned deployment ID to keelson status <deploy_id> --wait --json and inspect terminal and status. --yes is required with --json or non-interactive execution.
Reading NDJSON
Section titled “Reading NDJSON”NDJSON contains progress lines with fields such as stage and status. During a health check, for example, stage is health_check and status is progress. A progress line’s status does not determine the outcome of the whole deployment.
- If monitoring starts, a final line contains
result, with the valuesuccessorfailed. - If the command fails before monitoring starts, it emits an
errorline without aresultline. Invalid configuration may produce only an error line. Failures after registering secrets or uploading the archive may also have earlier progress lines. - Check the process exit code too. A nonzero code means the CLI operation failed. A monitoring timeout also counts as failure, although deployment may still be running on the server.
Verify
Section titled “Verify”| Command | Description |
|---|---|
keelson app curl <path> [-i] [--method <method>] [--data <body|@file>] [--form <name=value|name=@file>] [--header <name:value>] | Send an authenticated request to the app. See Verify a deploy |
keelson preview [--ttl <duration>] [--allow-writes] [--json] | Issue an expiring token for authenticated access to the app |
keelson app info / start / stop / restart | Show app information, start, suspend, or restart the app. restart waits for completion; use --no-watch to return when accepted |
With app curl --data, also specify --method POST, PUT, PATCH, or DELETE. --form defaults to POST when --method is omitted. Repeat --form or --header for multiple fields or headers.
The response body is written to standard output. -i also writes the HTTP status and response headers to standard error. Temporary GET / HEAD failures are retried up to twice by default; use --retry 0 to disable retries.
If someone other than the person who deployed the currently serving revision runs preview or app curl, browser approval is required even for reads. Approval alone does not issue the token or send the request. Within 30 minutes of approval, rerun the same command with --confirmation <id>. This differs from the approval flow in Operations that require browser approval.
| Command | Description |
|---|---|
keelson logs app <slug> [--mode live|history] [--severity <level>] [--previous] [--limit <n>] [--since <duration>] | (--previous is not supported on the current runtime and returns 422; crashed-instance output is included in the normal stream) Show the app’s standard output and standard error |
keelson logs cron <slug> [--severity <level>] [--limit <n>] [--since <duration>] | Show scheduled job execution logs |
keelson logs access [--limit <n>] [--since <duration>] | Show access logs |
keelson logs deploy [deploy_id] [--limit <n>] [--since <duration>] | Show deployment progress and stored failure details, including startup logs when the app exited during startup. Successful build output is not retained; the command explains when no logs are available |
--since accepts durations such as 1h or 1d12h, from 1 second through 30 days.
--json returns one JSON object containing log arrays and other fields. The log location depends on the command.
| Command | Logs in JSON |
|---|---|
logs app / logs cron | entries: objects containing the timestamp, severity, message, and other fields |
logs access | entries: objects containing the timestamp, HTTP status, path, and other fields |
logs deploy | logs: progress log objects. failure_logs and startup_logs: arrays of strings |
Secrets
Section titled “Secrets”Pass values through standard input or an env file, not as command arguments.
| Command | Description |
|---|---|
keelson secrets list | Show configured names and update times, without values |
echo -n "<value>" | keelson secrets set <KEY> [--apply] | Set one value. --apply also requests redeployment and returns when accepted |
keelson secrets set --from-env-file <path> [--apply] | Set multiple values from an env file. Keys are saved individually; a failure partway through leaves a partial update. The error lists saved keys |
keelson secrets unset <KEY> | Delete a secret |
Secrets take effect on the next deploy, or when you use --apply.
App management
Section titled “App management”| Command | Description |
|---|---|
keelson apps list [--workspace <slug>] [--query <text>] [--exact] | List apps. Omitting --workspace includes all your workspaces. JSON results use an apps array when the flag is supplied and a workspaces array when omitted |
keelson apps duplicate <slug> --name <new> [--copy-secrets] [--enable-schedule] | Duplicate an app; scheduled jobs are disabled by default |
keelson apps rename <new_slug> | Change the slug in the app URL. The old URL returns 410 without an automatic redirect. The change takes time to propagate |
keelson apps delete [slug] | Delete an app. Browser approval is required |
keelson quotas | Show plan limits and usage |
After apps rename, update slug in your local keelson.yaml too.
What a duplicate carries over
Section titled “What a duplicate carries over”A duplicate is created from the source app’s latest successful deploy. The duplicate is a separate app with its own URL and deploy history.
| Item | What happens |
|---|---|
| Application code | Copied from the latest successful deploy |
Configuration (keelson.yaml) | Copied, with the duplicate’s new app identity |
| Scheduled job definitions | Copied, but created disabled after the duplicate’s deploy succeeds. --enable-schedule enables jobs unless their configuration explicitly sets enabled: false |
| App-level secrets | Not copied by default. Use --copy-secrets to copy them |
| Workspace-level secrets | Not copied, but they remain available because workspace-level secrets are provided to every app in the workspace |
| Platform-managed credentials | New credentials are issued for the duplicate |
| Managed database contents | Not copied; the duplicate gets a new, empty database. The CLI has no option to copy database contents |
| Deploy history | Not copied; the duplicate starts with a new deploy based on the source app’s latest successful deploy |
Scheduled Jobs
Section titled “Scheduled Jobs”| Command | Description |
|---|---|
keelson crons list [--include-disabled] | List jobs |
keelson crons trigger <name> [--wait] | Run a job now; --wait waits for its result |
keelson crons enable <name> / disable <name> | Enable or disable a job |
keelson crons runs list [--cron <name>] [--limit <n>] [--offset <n>] | Show execution history |
keelson dev cron run <name> [--file <path>] [--dir <path>] | Run a scheduled job from keelson.yaml once locally |
keelson dev task run <name> [--payload <JSON> | --payload -] [--file <path>] [--dir <path>] [--json] | Run a background task from keelson.yaml once locally, synchronously, with no retry. --payload is the task’s payload as JSON (- reads it from standard input; omitted means null). With --json, standard output carries one result object. The SDK uses this command when enqueue runs locally. See Background tasks |
Local development
Section titled “Local development”| Command | Description |
|---|---|
keelson dev serve [--port <n>] [--users <file>] [--as <id>] -- <command...> | Start your app’s server with <command> and relay requests to it, adding the same user information headers as Keelson. Switch users with the switch page (/__keelson/dev) or the X-Keelson-Dev-As header. --port is the port to listen on (default 5173), --users is the user list file (default ./.keelson/dev-users.json, or four built-in users if absent), and --as is the user at startup. The app receives a free port in PORT, and {port} in <command> is replaced with it. Does not start in a deployed environment. See Run your app locally |
keelson dev serve --check | Exit with code 0 without starting anything. Use it to check whether this CLI supports dev serve |
Database
Section titled “Database”| Command | Description |
|---|---|
keelson db apply [file.sql] | Run SQL against Managed SQLite; omit the file or use - for standard input. Browser approval is required if the DB already contains schema objects. A first-time DB with no tables, indexes, views, or triggers needs no approval |
keelson snapshots list | List restore points and running or recent exports, including successful and failed exports |
keelson snapshots create | Create a manual snapshot |
keelson snapshots download <id> [-o <file>] | Download a backup. Without -o, only prints a download URL and writes no file |
keelson snapshots export --at <RFC3339> | Create a point-in-time export (PITR), then retrieve it with download after completion |
keelson snapshots restore <id> | Restore a snapshot. Browser approval is required. The restore can be undone within 72 hours |
keelson snapshots restore-status | Check the progress and result of the latest restore |
keelson db revoke-tokens [app] [--yes] | Revoke DB authentication tokens (destructive). Prompts in the terminal; non-interactive use requires --yes. The DB is temporarily unavailable until the new revision takes over |
keelson db recover [app] / credential-status [app] | Recover credentials and show their status |
Access control
Section titled “Access control”| Command | Description |
|---|---|
keelson groups list | List groups |
keelson groups create <key> [--name <text>] [--description <text>] [--if-not-exists] | Create a custom group |
keelson groups members list <key> | List group members |
keelson groups members add|remove <key> <email>... | Change group membership for existing members; does not send invitations |
keelson access show --app <slug> | Show the app’s view and manage groups |
keelson access set --app <slug> [--view <key>]... [--manage <key>]... [--allow-self-lockout] | Set groups with view and manage permissions |
access set replaces all bindings for each permission type you specify. Supplying only --view leaves manage permissions unchanged. Use --view none to clear view groups. Manage groups cannot be empty.
Repeat the flag for multiple groups. For example, to replace view groups with sales and engineering:
keelson access set --app my-app --view sales --view engineeringA change that removes your own manage permission requires --allow-self-lockout.
External integrations
Section titled “External integrations”| Command | Description |
|---|---|
keelson apps tokens create --app <slug> --name <name> --scope <scope> [--scope <scope>]... [--allowed-ip <cidr>]... | Issue an app token, shown only once. --app is required |
keelson apps tokens list | List token metadata only |
keelson apps tokens rotate --app <slug> --token-id <id> | Rotate a token; the old token expires after a grace period |
keelson apps tokens delete <token_id> | Revoke a token |
keelson apps directory enable | Issue a Directory API token and register it as KEELSON_DIRECTORY_TOKEN (redeploy required) |
keelson domains list | List custom domains and their status |
keelson domains add|verify|remove <hostname> [--yes] | Add, verify, or remove a custom domain (Team). Non-interactive remove requires --yes |
Allowed --scope values are listed below. Inbound and Directory scopes cannot be combined in one token.
| Scope | Purpose |
|---|---|
api | Call the app’s /api/external/... endpoints from external systems |
webhook | Receive webhooks from external services |
directory:members:read / directory:identity:read / directory:groups:read / directory:group-members:read | Call the Directory API from the app; normally granted by apps directory enable |
Feedback
Section titled “Feedback”keelson feedback --app <slug> [--deploy <id>] < feedback.json sends feedback about the CLI and the Skill. The payload is one JSON object on standard input. Unknown fields are rejected.
| Field | Description |
|---|---|
verdict (required) | Object with required score (integer 1–10) and summary (1–1,000 characters) |
friction | Up to 20 objects with step, command, output_quote, expected, lost_minutes, and recovered |
yaml_confusions / error_message_reviews / wanted_commands / kept_good | Up to 20 strings each |
skill_gaps / verification_method | Strings |
Each friction entry requires all six fields:
| Field | Type and meaning |
|---|---|
step | String describing the task stage or situation where friction occurred |
command | String containing the command run |
output_quote | String quoting the message displayed |
expected | String describing the expected behavior |
lost_minutes | Integer from 0 to 1,440: minutes spent resolving the problem |
recovered | Boolean: true if resolved, false if unresolved |
For example, save the following as feedback.json and submit it. Replace the content with your actual experience.
{ "verdict": { "score": 8, "summary": "Deployment succeeded, but confirmation in non-interactive execution was unclear." }, "friction": [ { "step": "Deploying from CI", "command": "keelson deploy", "output_quote": "The confirmation response could not be read from standard input.", "expected": "I wanted to know the required flags for non-interactive execution in advance.", "lost_minutes": 3, "recovered": true } ]}Command aliases
Section titled “Command aliases”These older names still work and no removal date is set. Prefer the canonical form; the alias is not shown in --help output as a separate command.
| Alias | Canonical form |
|---|---|
keelson backups list / trigger / download / restore | keelson snapshots list / create / download / restore |
keelson tokens list / delete | keelson apps tokens list / delete |
keelson skill install [--global] [--codex] [--yes] | keelson install-agent <claude-code|codex|cursor> [--global] [--yes] |
keelson tenants list | keelson workspaces list |
keelson db rotate-credentials | keelson db revoke-tokens |
--tenant | --workspace |
Operations that require browser approval
Section titled “Operations that require browser approval”Deleting an app, running SQL against a database with existing schema objects, and restoring a snapshot require browser approval. The command displays an approval URL (confirmation_required). Approving in the browser executes the operation on the server; do not rerun the command. Approval expires after 15 minutes.
Behavior after the URL is displayed depends on execution mode:
- Interactive terminal: waits for approval and execution by default. Use
--wait=falseto return without waiting. --jsonor a non-interactive terminal: returns without waiting by default. Use--waitto wait.
preview and app curl use the separate rerun flow described under Verify. rollback, db revoke-tokens, and domains remove require terminal confirmation rather than browser approval; non-interactive execution needs --yes.
Environment variables
Section titled “Environment variables”| Variable | Description |
|---|---|
KEELSON_TOKEN | Token used instead of login, for example in CI. Takes precedence over saved credentials. Setting it to an empty string causes an error |
KEELSON_NO_UPDATE_CHECK=1 / KEELSON_NO_SKILL_SYNC=1 | Disable update checks / automatic Skill updates. Any nonempty KEELSON_NO_SKILL_SYNC value, including 0, disables sync |
KEELSON_NO_TELEMETRY=1 | Disable CLI usage telemetry |
KEELSON_CONFIG_DIR | Directory containing credentials.json and config.json |
KEELSON_API_BASE_URL / APP_DOMAIN_BASE | Override the API endpoint and app domain; normally unnecessary |