Skip to Content

Kalam CLI Command Reference

The Kalam CLI (kalam) is the SQL-first terminal client for KalamDB. This guide documents every CLI flag and interactive command currently implemented in ../KalamDB/cli, including live subscriptions, topic consumers, credential workflows, and schema watch automation.

Install and verify

Choose one of these installation options:

bash snippetBASH
curl -fsSL https://kalamdb.org/install.sh | bash

Option 2: GitHub release binaries

Use prebuilt binaries from releases if you do not want a Rust toolchain:

Option 3: Build from source

bash snippetBASH
cd clicargo build --release./target/release/kalam --help

After installation, verify your CLI:

bash snippetBASH
kalam --helpkalam --version

Execution modes and precedence

kalam supports four execution modes:

  1. --watch-schema: poll system.tables and run a local command when schema metadata changes.
  2. --subscribe / --list-subscriptions: subscription management flow.
  3. --consume --topic ...: topic consumer mode.
  4. SQL execution mode:
    • --file <path> executes file and exits
    • --command <sql> executes one statement and exits
    • no --file/--command starts interactive shell

Important behavior:

  • --watch-schema is a standalone mode and requires --run.
  • --consume takes precedence over --file and --command.
  • --file and --command together are invalid.

Connection and authentication options

OptionDescription
-u, --url <URL>Full server URL or bare host. Bare loopback inputs default to http://; other bare hosts default to https://.
-H, --host <HOST>Host-only alternative to --url; combines with --port.
-p, --port <PORT>Port used with --host (default 3000).
--token <JWT>JWT auth token.
--user <USER>User/password login identifier.
--password [PASS]Basic auth password. If passed with no value in interactive mode, CLI prompts.
--instance <NAME>Credential profile name (default local).

URL defaults and resolution:

  • If --url is set, that value is normalized and used. Bare hosts are accepted.
  • If --host is set, URL becomes http://<host>:<port>.
  • Otherwise CLI uses stored credentials URL for the selected --instance when present.
  • Final fallback is http://localhost:2900.
  • Bare --url inputs like localhost:2900, 127.0.0.1:2900, and [::1]:2900 default to http://...; other bare hosts like kalam.masky.app default to https://....
  • --url rejects embedded credentials, query parameters, and fragments.

Query execution and output options

OptionDescription
-c, --command <SQL>Execute a single SQL statement and exit.
-f, --file <PATH>Execute SQL from file and exit.
--format <table|json|csv>Output format (default table).
--jsonShorthand for --format json.
--csvShorthand for --format csv.
--no-colorDisable ANSI colors.
--no-spinnerDisable spinner animations.
--loading-threshold-ms <MS>Spinner threshold in milliseconds.

Examples:

bash snippetBASH
kalam --command "SELECT * FROM system.tables LIMIT 5;"kalam --command "SELECT * FROM system.tables LIMIT 5;" --jsonkalam --file ./setup.sql --csvkalam --url kalam.masky.app --command "SELECT 1;"

Running SQL from the CLI

The CLI is SQL-first: if a statement works through /v1/api/sql, you can send it unchanged through kalam --command, kalam --file, or the interactive shell.

Common patterns:

bash snippetBASH
# Read system metadatakalam -c "SELECT * FROM system.tables ORDER BY namespace_id, table_name LIMIT 20;" # DDL / DMLkalam -c "CREATE NAMESPACE chat;"kalam -c "CREATE TABLE chat.messages (id BIGINT PRIMARY KEY, body TEXT) WITH (TYPE='USER');"kalam -c "INSERT INTO chat.messages (id, body) VALUES (1, 'hello');" # Run a whole SQL filekalam -f ./migrations/001-init.sql

Namespace state in interactive mode

Namespace switching is a SQL statement, not a backslash command:

sql snippetSQL
USE NAMESPACE chat;SELECT * FROM messages ORDER BY id DESC LIMIT 20;\flush table messages

After a successful USE NAMESPACE chat, SET NAMESPACE chat, or USE chat, the CLI stores chat locally and sends it as namespace_id on later requests. That means later unqualified table names resolve to chat.<table> until you switch again. The prompt also shows the active namespace as ns:<name>.

When output format is table, query results end with row count and footer metadata:

text snippetTEXT
(50 rows)As: aliceTook: 2.146 ms
  • As: appears when the server reports the effective user for the statement. This includes EXECUTE AS '<user_id>' and the CLI \as shortcut.
  • Took: is the server-reported execution time in milliseconds.

Interactive meta-commands

In interactive mode, type SQL directly or use backslash meta-commands for CLI-managed operations. --command also accepts these meta-commands, so cluster inspection and administration can stay on the CLI surface instead of requiring backend-rendered strings.

Cluster meta-commands

Core cluster commands:

CommandDescription
\cluster list / \cluster lsRender node overview from system.cluster and system.cluster_groups.
\cluster list groupsRender Raft group details.
\cluster snapshotTrigger cluster snapshots and print per-group results.
\cluster purge --upto <index>Purge Raft logs up to index.
\cluster trigger-electionTrigger elections across groups.
\cluster transfer-leader <node_id>Request leader transfer to a node.
\cluster rebalanceRebalance data-group leaders.
\cluster stepdownRequest leader stepdown across groups.
\cluster clearClear older snapshot files.
\cluster join <node_id> <rpc_addr> <api_addr>Add a node at runtime.

Examples:

bash snippetBASH
kalam --command "\\cluster list"kalam --command "\\cluster list groups"kalam --command "\\cluster rebalance"kalam --command "\\cluster join 2 10.0.0.2:2910 http://10.0.0.2:2900"

How follower writes are forwarded

KalamDB uses Multi-Raft groups, so a client can send a write to any reachable node.

Example:

bash snippetBASH
kalam --url http://node-2:2900 --command "INSERT INTO app.messages (id, body) VALUES (101, 'hello')"

Assume the authenticated or effective user is user-42, and that user hashes to DataUserShard(7).

  1. The request can land on node 2 even if node 2 is only a follower for DataUserShard(7).
  2. KalamDB prepares and classifies the SQL once, then derives the target Raft group from the table type and current user_id.
  3. For user and stream tables, the target group is selected by hashing user_id into one of cluster.user_shards groups.
  4. If the receiving node is not leader for that target group, it forwards the original SQL, params, auth header, and request id over gRPC to the leader of that group.
  5. The leader executes the write, appends it to that group’s Raft log, replicates it to followers, commits it, and returns the result.
  6. The follower returns that leader-built response to the client.

This means the client does not need to discover the right leader first.

Multi-Raft routing today

  • KalamDB runs one metadata Raft group plus multiple user data groups.
  • User and stream data are routed by user_id, so all data for one user is coordinated by the same user-data group leader at a given time instead of scattering that user’s active writes across many leaders.
  • That locality keeps the cluster faster by reducing cross-group coordination and improving write-path locality.
  • Shared tables are not meaningfully sharded yet. Today they route to a single shared data group.
  • Better shared-table partitioning is a work in progress. The planned direction is partition-by-key so each shared table can define how rows are partitioned and where they belong.

Credential and instance management

OptionDescription
--list-instancesList stored credential instances.
--show-credentialsShow stored credentials for --instance.
--update-credentialsLogin and refresh stored JWT/refresh token for --instance.
--delete-credentialsDelete credentials for --instance.
--save-credentialsSave credentials after successful login when using user/password flow.

Examples:

bash snippetBASH
kalam --list-instanceskalam --show-credentials --instance devkalam --update-credentials --instance dev --url http://localhost:2900 --user adminkalam --delete-credentials --instance dev

Live query subscription options

OptionDescription
--subscribe <SQL>Run a live query subscription.
--subscription-timeout <SECONDS>Idle timeout after initial data (0 means no timeout).
--initial-data-timeout <SECONDS>Maximum wait for initial data batch (0 means no timeout).
--list-subscriptionsPrint current subscription model/capabilities.

The CLI live-query surface is \live <SELECT ...> in interactive mode and --subscribe "<SELECT ...>" in non-interactive mode. Both routes send a SELECT plus an optional trailing OPTIONS (...) clause to the WebSocket subscription path.

Supported CLI subscription options today:

ClauseEffect
OPTIONS (batch_size=<n>)Limits each initial snapshot batch to at most n rows. If more rows match, the CLI keeps requesting the next batch until startup loading completes.
OPTIONS (last_rows=<n>)Rewinds the newest n rows as a single startup batch before live changes begin.
OPTIONS (from=<seq_id>)Starts live delivery after a known sequence id. from_seq_id is accepted as an alias.

Options can be combined in one clause, for example OPTIONS (last_rows=20, batch_size=5, from=1234).

Examples:

bash snippetBASH
kalam --subscribe "SELECT * FROM app.messages WHERE conversation_id = 7 OPTIONS (batch_size=5)"kalam --subscribe "SELECT * FROM app.messages OPTIONS (last_rows=20)" --subscription-timeout 15kalam --subscribe "SELECT * FROM app.messages OPTIONS (last_rows=20, batch_size=5, from=1234)"

Interactive examples:

text snippetTEXT
kalam> \live SELECT * FROM app.messages OPTIONS (batch_size=5);kalam> \subscribe SELECT * FROM app.messages OPTIONS (last_rows=20);kalam> \live SELECT * FROM app.messages OPTIONS (last_rows=20, batch_size=5, from_seq_id=1234);

How to verify batching from the CLI output:

  • The CLI prints a BATCH <n> line for each startup snapshot page.
  • With OPTIONS (batch_size=5) and 20 matching rows, you should see four startup batches of 5 rows each.
  • Startup batches are delivered from oldest to newest in normal batch mode.
  • last_rows is different: it is a single-batch rewind of the newest rows, not paginated history replay.

Example output:

text snippetTEXT
[12:00:00.123] ✓ SUBSCRIBED [sub_...] 0 total rows, batch 1 (loading...), 3 columns[12:00:00.124] BATCH 1 [sub_...] 5 rows (more pending)  {"id":1,"message":"hello 1"}  {"id":2,"message":"hello 2"}[12:00:00.130] BATCH 2 [sub_...] 5 rows (more pending)...[12:00:00.145] BATCH 4 [sub_...] 5 rows (complete)

Topic consumer options (--consume)

Use this mode to consume topic records directly from a terminal.

OptionDescription
--consumeEnable topic consumer mode.
--topic <TOPIC>Topic name (required with --consume).
--group <GROUP_ID>Consumer group (offsets committed when set).
--from <earliest|latest|OFFSET>Start position. Supports numeric offset.
--consume-limit <N>Maximum number of messages before exit.
--consume-timeout <SECONDS>Stop after idle runtime window.

Examples:

bash snippetBASH
# Read newest events and keep runningkalam --consume --topic blog.summarizer --from latest # Replay from earliest with bounded runkalam --consume --topic blog.summarizer --group summarizer-agent --from earliest --consume-limit 50 --consume-timeout 60

Schema watch options (--watch-schema)

Use this mode when your app has a local schema-generation step such as npm run schema:gen and you want the CLI to rerun it after DDL changes.

OptionDescription
--watch-schemaStart schema watch mode.
--namespace <NAME>Limit changes to one or more namespaces. Repeat it to watch multiple namespaces.
--table <namespace.table>Limit changes to one or more specific tables. Repeat it to watch multiple tables.
--run <COMMAND>Shell command to execute after schema changes are detected.
--run-on-startRun the command once immediately before polling.
--interval <DURATION>Poll interval. Default 5s; accepts values like 500ms, 2s, or 1m.

Examples:

bash snippetBASH
# Watch all non-system schemaskalam --watch-schema --run "npm run schema:gen" # Watch one namespacekalam --watch-schema --namespace chat --run "npm run schema:gen" # Watch multiple namespaceskalam --watch-schema --namespace chat --namespace billing --run "npm run schema:gen" # Watch a specific tablekalam --watch-schema --table chat.messages --run "npm run schema:gen" # Run once immediately, then poll every 5skalam --watch-schema --namespace chat --run "npm run schema:gen" --run-on-start # Faster pollingkalam --watch-schema --namespace chat --run "npm run schema:gen" --interval 2s

Internally the CLI polls system.tables and checks for rows whose updated_at is newer than the last observed watch timestamp. Repeated namespaces are combined with OR, and repeated tables are added as extra OR branches.

Timeout and runtime tuning options

OptionDescription
--timeout <SECONDS>HTTP request timeout (default 30).
--connection-timeout <SECONDS>Connection/TLS handshake timeout (default 10).
--receive-timeout <SECONDS>Receive timeout (default 30).
--auth-timeout <SECONDS>WebSocket auth timeout (default 5).
--fast-timeoutsPreset tuned for local development.
--relaxed-timeoutsPreset tuned for high-latency networks.
--config <PATH>Config file path (default ~/.kalam/config.toml).
-v, --verboseVerbose logging.

Global utility options

OptionDescription
-h, --helpPrint command help.
-V, --versionPrint CLI version, commit, branch, and build timestamp.

Interactive shell commands by category

After launching interactive mode (kalam with no --command/--file), these backslash commands are available.

Core shell and inspection

CommandDescription
\help, \?Show help.
\quit, \qExit CLI.
\info, \sessionShow current CLI session, resolved server, health probe status, server version, cluster, and config details.
\sessionsShow active PostgreSQL gRPC bridge sessions from system.sessions.
\history, \hOpen command history menu.
\healthRun unauthenticated public health probes.
\stats, \metricsQuery system stats metrics.

Session introspection

Use \session (or \info) to inspect the current CLI process and server connection: resolved URL, user, connectivity, health probe status, server version, API version, build date, cluster mode, config file, local history, and build metadata.

\health uses the same public /health and /v1/api/healthcheck endpoints documented in the HTTP reference. It does not fall back to authenticated SQL. On remote deployments those endpoints may be localhost-only; in that case the CLI reports the restriction, while \session can still show version/build details learned from cluster metadata.

Use \sessions when you want server-side observability for PostgreSQL bridge traffic. It executes:

sql snippetSQL
SELECT *FROM system.sessionsORDER BY last_seen_at DESC, session_id;

That view is focused on live pg_kalam gRPC sessions only. To inspect active explicit transactions across both pg_kalam and native /v1/api/sql requests, query:

sql snippetSQL
SELECT transaction_id, owner_id, origin, state, write_countFROM system.transactionsORDER BY origin, transaction_id;

See System Views for the view columns and query patterns.

Namespace, schema, impersonation, and formatting

CommandDescription
\dt, \tablesList tables.
\d <table>, \describe <table>Describe table columns. Accepts <table> or <namespace.table> and ignores a trailing ;.
\as <user_id> <SQL>Run one statement as a convenience wrapper for EXECUTE AS '<user_id>'.
\format table|json|csvChange output format for current session.
\refresh-tables, \refreshRefresh autocomplete table metadata.

Example:

sql snippetSQL
USE NAMESPACE chat;SELECT * FROM messages WHERE conversation_id = 42;\flush table messages\as user_123 SELECT * FROM app.messages WHERE conversation_id = 42;

\flush is a shortcut for STORAGE FLUSH:

  • \flush or \flush all runs STORAGE FLUSH ALL using the current namespace context.
  • \flush table messages runs STORAGE FLUSH TABLE chat.messages when the current namespace is chat.
  • \flush table billing.invoices preserves the explicit namespace you typed.

The CLI rewrites that shortcut to the canonical SQL wrapper:

sql snippetSQL
EXECUTE AS 'user_123' (  SELECT * FROM app.messages WHERE conversation_id = 42)

See Execute As for the delegation rules and role matrix.

Credentials in interactive mode

CommandDescription
\show-credentials, \credentialsShow stored credentials for current instance.
\update-credentials <user> <pass>Update credentials for current instance.
\delete-credentialsDelete credentials for current instance.

Live query commands

CommandDescription
\live <SQL>, \subscribe <SQL>Start live query subscription (\subscribe is an alias).

Topic consumer command (interactive)

CommandDescription
\consume <topic> [--group NAME] [--from earliest|latest|OFFSET] [--limit N] [--timeout SECONDS]Consume topic messages directly from interactive shell.

Example:

sql snippetSQL
\consume blog.summarizer --group summarizer-agent --from earliest --limit 25 --timeout 45

Cluster and ingest control commands

The \cluster meta-command renders cluster operations directly from the CLI surface.

CommandDescription
\flush [all|table <table>]Run STORAGE FLUSH using the current namespace context.
\cluster snapshotTrigger cluster snapshot.
\cluster purge --upto <index> or \cluster purge <index>Purge cluster logs up to index.
\cluster trigger-election or \cluster trigger electionTrigger election.
\cluster transfer-leader <node_id> or \cluster transfer leader <node_id>Request leadership transfer to node id; some builds may report it unsupported at runtime.
\cluster rebalanceRebalance leaders across data groups.
\cluster stepdown or \cluster step-downStep down current leader.
\cluster clearClear older snapshot files while keeping recent ones.
\cluster list or \cluster lsShow cluster nodes (system.cluster).
\cluster list groupsShow cluster groups (system.cluster_groups).
\cluster join <node_id> <rpc_addr> <api_addr>Add a node at runtime.

SQL workflows the CLI should cover

The backslash commands are only part of the surface. Many important CLI workflows are plain SQL entered through -c, -f, or the interactive shell.

Impersonation

You can use either the \as shortcut or the raw SQL form:

sql snippetSQL
EXECUTE AS 'user_123' (  SELECT * FROM app.messages ORDER BY id DESC LIMIT 20);

Backup and user export

Run backup and export workflows as normal SQL:

sql snippetSQL
BACKUP DATABASE TO '/tmp/kalamdb-backup.tar.gz';EXPORT USER DATA;SHOW EXPORT;

Live queries

The CLI live-query commands take a normal SELECT and run it over the live subscription channel:

bash snippetBASH
kalam --subscribe "SELECT * FROM app.messages WHERE conversation_id = 7"
sql snippetSQL
\subscribe SELECT * FROM app.messages WHERE conversation_id = 7

There is no separate live-query SQL keyword to learn for the CLI path; use the same SELECT you would run normally.

Export user data

sql snippetSQL
EXPORT USER DATA;SHOW EXPORT;

SHOW EXPORT returns job rows with a download_url URI path such as /v1/exports/<user_id>/<export_id>. Prefix that path with the same server base URL you used for the CLI when downloading the finished ZIP.

Backup and restore

sql snippetSQL
BACKUP DATABASE TO '/var/backups/kalamdb-nightly.tar.gz';RESTORE DATABASE FROM '/var/backups/kalamdb-nightly.tar.gz';

Backup and restore paths are resolved on the server filesystem, not on the machine running the CLI.

  • If BACKUP DATABASE TO ends with .tar.gz or .tgz, KalamDB writes a single archive file.
  • If it does not, KalamDB writes the backup directory layout under that path.
  • RESTORE DATABASE FROM accepts either the directory layout or a .tar.gz / .tgz archive.
  • Backup and restore require a DBA or System role.
  • There is no separate backup download endpoint today; the TO '<path>' value is the server-side artifact location.
  • To track the status of the backup you can query the jobs table: select * from system.jobs where job_id = ‘backupjob’;

Topic pub/sub SQL

Use SQL for topic definition, CDC wiring, and explicit offset control:

sql snippetSQL
CREATE TOPIC app.new_messages PARTITIONS 4;ALTER TOPIC app.new_messages ADD SOURCE app.messages ON INSERT WITH (payload = 'full');CONSUME FROM app.new_messages GROUP 'worker-1' FROM EARLIEST LIMIT 100;ACK app.new_messages GROUP 'worker-1' UPTO OFFSET 99;DROP TOPIC app.new_messages;

The --consume flag and \consume command are convenience shells around topic consumption. Use raw CONSUME FROM and ACK when you want explicit SQL-based control or when you are scripting the workflow.

Quick command map

bash snippetBASH
# Interactive shellkalam # One-shot SQLkalam -c "SELECT * FROM system.tables LIMIT 5;" # File executionkalam -f ./queries.sql # Live subscriptionkalam --subscribe "SELECT * FROM app.messages" # Start in one namespace, then use unqualified table names interactivelykalam# inside the shell:# USE NAMESPACE chat;# SELECT * FROM messages;# \flush table messages # Export user data and inspect download pathskalam -c "EXPORT USER DATA;"kalam -c "SHOW EXPORT;" --json # Server-side backup archivekalam -c "BACKUP DATABASE TO '/var/backups/kalamdb-nightly.tar.gz'" # Restore from a server-side archivekalam -c "RESTORE DATABASE FROM '/var/backups/kalamdb-nightly.tar.gz'" # Topic consumerkalam --consume --topic blog.summarizer --group summarizer-agent --from latest # Regenerate local Drizzle schema on DDL changeskalam --watch-schema --namespace app --run "npm run schema:gen" --run-on-start
Last updated on