tapstateDocs
Developers and AICLI and APIs

CLI reference

Use tapstate offline workspace commands, connected sessions, and one-shot commands

The CLI is an optional interface for developers, scripts, and AI agents. Start with the web Quickstart for interactive use. The CLI has three operating forms:

  • Offline commands read or create local workspace files. They do not require a running server.
  • Connected sessions retain the selected workspace, server, and login in an interactive REPL.
  • Connected one-shot commands use launch options to connect, authenticate, run one command, and exit.

Run this command to see the command set included with your installed version:

tapstate --help

Use tapstate help <command> or tapstate <command> --help to inspect a command without connecting to a server.

Launch and help options

OptionPurpose
-w, --workdir <dir>Select the workspace for an interactive session. For an offline one-shot command, place this option after the command. The default is tap-work, or $TAPSTATE_WORKDIR when set.
-c, --connect <url>Connect to a server before opening a session or running a one-shot command.
--context <name>Select a saved server context for connected commands. Use tapstate context or :ctx to create and manage contexts.
-u, --user <name>Log in as this user during launch when -c is also supplied. Without -c, the CLI stays in an offline session.
-p, --password <password>Supply the password inline. Prefer TAPSTATE_PASSWORD or the prompt because command-line values are visible in shell history and process listings.
--versionPrint only the installed CLI version and exit. Use tapstate version to report both the CLI and server versions.
--helpPrint top-level help and exit.

Report CLI and server versions

The CLI and server are installed separately and can run different builds. Use tapstate version when you need the complete version pair for troubleshooting or compatibility checks:

$ tapstate version
cli    <cli-version>
server not connected

The command works without a server. After you connect, run version in the same session to read the server's current self-description:

tapstate(127.0.0.1:8080)> version
cli    0.7.0
server 0.7.0 (127.0.0.1:8080)
dsl    tapstate/v1
data   12

When connected, version reports the CLI version, server version, the list of accepted authoring grammars (dsl), and the internal store schema version (data). If the server accepts no grammars, dsl reports none. If the server omits a field entirely, it reports not reported. Offline sessions omit dsl and data because only a running server can report them.

tapstate --version is different: it reports only the local executable and does not contact a server.

When connect finds different CLI and server versions, it reports cli.version-mismatch but keeps the connection open. Install the CLI version that matches the server, or connect to a server on the CLI version. If their contracts differ, the server decides which operations it accepts. A server that does not expose its version is reported as not reported; the CLI does not assume that the versions match.

Running tapstate without a subcommand starts the REPL. A global work directory can be supplied before the session starts:

tapstate -w work

Offline workspace commands

demo

Create a complete three-file order-state workspace:

tapstate demo [-w DIR] [--print-steps] [--force] [-o text|json|yaml]

The command writes:

source/orders_db.tap.yml
source/fulfillment_db.tap.yml
pipeline/order_pipeline.tap.yml

It generates local files only. It does not start Docker, connect to a server, test either database, or run the pipeline. Use --print-steps to print the commands that apply and run the workspace after you configure its connection values.

By default, demo refuses to overwrite an existing demo workspace and returns cli.demo-workspace-exists. Use a new directory, or review the files before running with --force. If the directory cannot be written, the command returns cli.workspace-not-writable with path and reason, restores files it replaced, and removes files it created. Empty directories created during the attempt can remain.

validate

Validate resource structure, field values, modes, and references:

tapstate validate [-w DIR] [-o text|json|yaml] [path]

When path is omitted, the command validates the selected workspace.

add

Scaffold a source, pipeline, transform, view, or serve resource into the workspace:

tapstate add source \
  --connector mysql \
  --id orders_source \
  --mode snapshot \
  --set host=localhost \
  --set port=3306 \
  --workdir work

Options:

OptionPurpose
<kind>Positional argument selecting the resource kind: source, pipeline, transform, view, or serve.
--connector <id>, -cSet the connector for a source resource.
--id <id>Set the resource ID.
--type <type>Set a transform type: filter, map, js, union, nest, or join. Use with add transform.
--mode <mode>, -mSet a source read mode.
--set key=valueSet a connector configuration field; repeat for multiple fields.
--source <id>Set a pipeline's source reference.
--sync-to <id>Add a pipeline target; repeat for multiple targets.
--non-interactive, -yRefuse missing required answers instead of prompting.
--dry-runPrint the generated resource without writing it.
--forceReplace an existing generated target.
--out <dir>Write the generated artifact flat into this directory instead of the workspace's kind directory.
-w, --workdir <dir>Set the workspace directory.

new --kind <kind> remains supported as a deprecated compatibility alias for add <kind> and prints a migration advisory. Bare tapstate new without arguments launches the guided interactive project initializer.

ls

List resources in the selected workspace:

tapstate ls [-w DIR] [-o text|json|yaml] [source|pipeline|transform|view|serve]

desc

Render one resource by ID:

tapstate desc [-w DIR] [-o text|json|yaml] <id>

explain

Describe the resource grammar or a field path:

tapstate explain [-o text|json|yaml] [field.path]

For example:

tapstate explain source.mode

alias

The installed command is tapstate. A release bundle can also provide the shorter tap alias when that name is available:

tapstate alias install
tapstate alias uninstall

Installing or removing the alias does not replace the canonical tapstate command. The CLI refuses to overwrite an unrelated file named tap. For a non-default installation, set TAPSTATE_INSTALL_DIR to the directory that contains tapstate before running the alias command.

Start a connected session

The local-user and saved-session commands below connect to a self-hosted server. Use managed browser sign-in for Cloud.

Start the REPL, connect to a server, and log in:

tapstate -w work
tapstate> connect http://127.0.0.1:8080
tapstate> login admin
Password:

The password prompt masks its input. connect selects the server; login creates the authenticated session used by later commands.

Save a server context and session

For repeat work against the same server, run tapstate context in an interactive terminal. The context manager can create, choose, edit, bind, unbind, or delete a named context. A context holds its server URL and TLS-verification choice; you can bind it to the current workspace when you create it.

Inside a REPL, run :ctx (or context) to open the same manager. Select a saved context at launch with --context:

tapstate --context local-dev -w work

After auth login <username> succeeds for a saved context, the CLI can resume its cached session when it next uses that context. Run auth status to confirm the signed-in user. Run auth logout to revoke the remote session and remove the local cache, or auth logout --local-only to remove only the local cache. The latter leaves the remote session valid until it expires.

Use a saved context for an interactive user session. A context does not turn a machine token into a saved credential, and a one-shot command that supplies --token remains scoped to that process.

REPL session commands:

CommandPurpose
helpShow REPL help.
connect <host:port>Select a server.
disconnectLeave the current server.
login <username>Authenticate to the selected server.
logoutEnd the authenticated session.
:ctx, contextManage saved server contexts.
auth login <username>Sign in and save a session for the selected context.
auth statusReport whether the selected context has a usable saved session.
auth logout [--local-only]Revoke and remove the saved session, or remove only its local cache.
versionReport the CLI version and the connected server version.
cd <dir>Change the REPL workspace directory.
pwdPrint the current workspace directory.
exit, quitEnd the session.

For a connected one-shot command, seed the connection and user before the verb:

TAPSTATE_PASSWORD="<server-password>" \
  tapstate -c http://127.0.0.1:8080 -u admin status orders_to_operational_state

The process connects, signs in, runs status, and exits. Without -c, a connected verb exits with code 3. connect, login, logout, and cd remain session commands; they are not one-shot verbs.

Read data from a declared source

Use a connected, authenticated session to inspect the data behind a declared source. Each read uses that source's configured connection. You do not provide a database URI or a database query language in the command.

In the current preview, row previews and live reads require a source that uses the mongodb connector. Collection listing and statistics can still be available for other connectors.

Read a collection

SyntaxUse
show collections [<source>]List the collections held by one declared source, or by every declared source when the argument is omitted. This lists the database's collections, not only resources declared in the workspace.
<source>.<collection>.stats()Report the collection metadata the connector provides. A row count is an estimate, and any size value can be unavailable.
<source>.<collection>.find([<filter>])Preview rows from one collection.

For example:

tapstate(admin@127.0.0.1:8080)> show collections warehouse
tapstate(admin@127.0.0.1:8080)> warehouse.orders.stats()
tapstate(admin@127.0.0.1:8080)> warehouse.orders.find({status: 'paid'}).sort({field: 'total', dir: 'desc'}).limit(25)

You can chain sort and limit onto find in either order:

<source>.<collection>.find([<filter>]) [.sort({field: '<field>', dir: 'asc'|'desc'})] [.limit(<rows>)]

find is a one-shot preview, not a paginated query. It returns 10 rows by default and accepts from 1 through 200 rows. It has no cursor or next-page token. When more rows remain, the CLI says so in the result footer. Without an explicit sort, the connector's natural order is not stable and is not a newest- first order.

For a connected one-shot command, quote the read expression and pass it to data-browser. Set TAPSTATE_PASSWORD in the environment when you do not want the CLI to prompt for it:

tapstate -c http://127.0.0.1:8080 -u admin data-browser \
  'warehouse.orders.find({status: "paid"}).limit(25)'

Filter rows

The CLI accepts a small, Mongo-shell-shaped filter syntax, then translates it to tapstate's own filter vocabulary. It does not forward a database query to the source.

OperatorMeaning
Bare value or $eqEqual to a value. For example, {status: 'paid'}.
$ne, $gt, $gte, $lt, $lteCompare a field with a value.
$inMatch one of a non-empty list of values.
$existsTest whether a field exists; the value must be true or false.
$containsFind a literal substring in a text field.
$and, $orCombine a non-empty list of conditions. Each $or item must be one condition.

Strings must be quoted. To apply more than one operator to the same field, use separate conditions inside $and.

Do not use {} to read every row; omit the filter instead. $regex, $where, $expr, $function, and $accumulator are not supported. Use $contains for a literal text search. Arbitrary nested Boolean groups are also not supported.

REST and MCP reads use structured field, op, and value objects rather than this CLI syntax. See the REST API preview or MCP integration when you are automating a read.

Address fields that contain dots

A dot normally selects a nested field. Quote and escape a dot that is part of a literal field name:

warehouse.orders.find({"price\.usd": {$gt: 10}})

For REST or MCP JSON, escape the backslash for JSON as well:

{
  "filter": {
    "field": "price\\.usd",
    "op": "gt",
    "value": 10
  }
}

You can filter a literal dotted field, but the read evaluates every row. You cannot sort by one; the server returns data-browser.unorderable-field.

Watch one row or tail collection changes

Use watch for an in-place view of the first matching row, or tail for an append-only stream of collection changes:

CommandBehavior
watch <source>.<collection> [<filter>]Refreshes one row in place about once per second. It requires an interactive terminal.
tail <source>.<collection> [<filter>]Writes inserts, updates, and deletes as they reach the source store. It works in a pipe or redirected output.

For example:

tapstate(admin@127.0.0.1:8080)> watch warehouse.orders {status: 'paid'}
tapstate(admin@127.0.0.1:8080)> tail warehouse.orders {status: 'paid'}

Press Ctrl+C to stop either command. watch returns cli.watch-needs-a-terminal with exit code 3 when its output is not a terminal; use tail for a pipeable stream or find for a one-shot read.

tail shows changes written to the store, so rapid intermediate updates might not appear separately. A follow that has no displayed change for 10 minutes is closed; run tail again to resume watching. A filter limits the events shown by the command. It does not modify the source or pipeline.

MCP integration

Use tapstate mcp when an MCP-compatible host needs to call a running tapstate server. The command starts a local stdio gateway; it does not start the server or open an interactive CLI prompt. See the MCP integration reference for host configuration, authentication, tools, and troubleshooting.

Apply and inspect resources

CommandPurpose
apply [path] [--if-match <hash>]Interpolate local environment variables and create or update one resource or the whole workspace. For a single existing resource, --if-match declares the content hash of the version being edited; it is not a batch-workspace precondition.
delete <id> [--if-match <hash>] [-o text|json|yaml]Permanently remove one stored artifact. When supplied, --if-match must match the artifact's current content hash.
get <id>Read one stored resource.
ls [kind]List stored resources, optionally by kind: source, pipeline, transform, view, or serve.
connectors [-o text|json|yaml]List registered connectors.
register <path|connector-id> [-o text|json|yaml]Download and register an official connector by published ID, upload one connector JAR, or upload all direct *.jar children of a directory. Requires administrator authentication (login admin).

apply reports each resource as created, updated, or unchanged. Connector registration is idempotent for the same artifact. When an official connector ID is passed to register, the CLI resolves and downloads the certified artifact from GitHub releases (or a mirror specified by TAPSTATE_CONNECTORS_URL). If the download fails, the CLI returns cli.connector-download-failed.

Apply can run checks that need discovered source metadata. For example, dsl.upsert-needs-key means a selected source table written with upsert has no primary key in its discovered schema. Discover the source again and select a keyed table, or choose append only for insert-only delivery. See Choose a write mode.

For delete, omitting --if-match makes the CLI read the current artifact and use that version for the removal. Supplying a hash pins a version already held by the caller; a stale hash is refused instead of overwriting a newer version. Deletion is irreversible. The CLI get command prints the artifact content, not its hash; use the REST or MCP representation when you need to supply an explicit hash.

For a Source, get omits connector config from the displayed YAML. The stored content hash still identifies the complete resource. Treat this output as a display view, not a backup or a complete Source definition to reapply.

Manage machine tokens

An authenticated administrator can create, list, and revoke machine tokens from the REPL:

CommandPurpose
token create --scope <read|write|admin> [-o text|json|yaml]Create a machine token. The bearer value is returned once.
token list [-o text|json|yaml]List token IDs, scopes, creation times, and revocation state without bearer values.
token revoke <token-id> [-o text|json|yaml]Revoke a machine token.

Use the narrowest scope required by the integration. Store a newly created bearer value in a secret manager or process environment; it cannot be retrieved later.

Test and discover connections

CommandPurpose
test <connection-id> [-o text|json|yaml]Run a connection test and render its result.
test-result <connection-id> [-o text|json|yaml]Read the latest stored test result without rerunning the test.
discover-schema <connection-id> [-o text|json|yaml]Discover source objects using a stored connection.
schema <connection-id> [table] [-o text|json|yaml]Read the stored discovered schema, optionally for one table.

A successful resource validation does not establish network reachability, authentication, or data movement. Test the connection from the server environment before starting a pipeline.

test and discover-schema wait for the connector without a fixed request deadline. A slow database can keep the command waiting. If the connection is interrupted, inspect test-result or schema before rerunning the operation.

Control and observe a pipeline

CommandPurpose
start <pipeline-id>Start a pipeline.
stop <pipeline-id> [--keep-state] [-y]Stop a pipeline. Clears checkpoint state by default; pass --keep-state to preserve it.
restart <pipeline-id> [--rerun] [-y]Restart a pipeline from its last checkpoint, or rerun from the beginning with --rerun.
pause <pipeline-id>Pause a running pipeline.
resume <pipeline-id>Resume a paused pipeline.
position <pipeline-id> [-f <file>]Read or update checkpoint resume positions for a stopped pipeline.
derived-schema <pipeline-id> [--accept]Compare schema evolution across pipeline steps, or adopt derived columns with --accept.
status <pipeline-id>Read pipeline lifecycle state, available failure details, and observation time when present.
status <pipeline-id> --watchStream lifecycle changes until interrupted.
metrics <pipeline-id>Read current pipeline and per-table metrics or confirmed target positions.
metrics <pipeline-id> --from <time> --to <time> [options]Read bounded output-rate and selected-table lag history.
explain <pipeline-id>In a connected session, explain current pipeline observations.
logs <pipeline-id>Read recent node-local logs, including forwarded connector and PDK runtime warnings and errors.
logs <pipeline-id> --followStream node-local logs and forwarded connector logs until interrupted.
snapshot <pipeline-id>Read the current snapshot view when one is available.

Use Ctrl+C to end status --watch or logs --follow. This ends the local stream, not the pipeline.

Before the first runtime observation, a known pipeline's status can be NEW without an observation time. status --watch waits for runtime observations. Metrics, snapshot, and explain can still return monitor.no-observation. See the status response fields for lifecycle intent and display phases.

History and explanations

For history, supply both --from and --to as RFC3339 timestamps with UTC offsets. The range is half-open and cannot exceed 15 days.

OptionContract
--resolutionauto (default), raw, 5m, 30m, 1h, 3h, or 6h.
--limit1–1000 points per page; default 240.
--tableRepeat for up to 20 tables; omitted table selections return no table lag.
--cursorContinue the same query with its returned nextCursor.

Repeat the original query unchanged when continuing. Cursors expire after 10 minutes. Read gaps, unavailable values, and effective ranges as described in Observe a pipeline.

explain has two meanings: without a server target, it describes a DSL field; with a server target, it interprets one pipeline's observations. A connected NO_MATCH response does not establish healthy delivery.

Stop and restart a pipeline

stop clears checkpoint positions and internal operator state by default. When run in an interactive terminal, the CLI prints an inventory of state to be removed and prompts for confirmation (Clear <id>? Type yes to go ahead). To automate stopping and clearing in scripts, pass -y (or --non-interactive). To stop a pipeline while keeping its resume positions intact so a subsequent start resumes where it left off, pass --keep-state:

tapstate stop orders_pipeline --keep-state

restart manages the lifecycle sequence directly:

  • Default restart: Safely cycles the pipeline without losing state. It pauses the running pipeline, waits until the engine confirms PAUSED, and resumes execution. If the pipeline is already stopped, it starts it.
  • Rerun from the beginning (--rerun): Stops the pipeline, clears this pipeline's checkpoint position and operator state (prompting for confirmation unless -y is passed), and starts a fresh run. On a dedicated source, the next run reads from the source beginning; on a shared mining chain where other pipelines are still running, the physical chain and its initial-load records are preserved:
tapstate restart orders_pipeline --rerun -y

Inspect and adjust checkpoint positions

position <pipeline-id> reports the resume token and recording timestamp for each physical mining chain feeding the pipeline:

  • Positions belong to mining chains, not tables: A single mining chain streams CDC events for all tables selected on a database connection. Offsets are tracked per chain rather than per individual table.
  • Chains can be shared across pipelines: Multiple pipelines reading from the same physical database share the same mining chain. Changing a chain's position affects every pipeline reading through that chain; the CLI reports any other pipelines sharing the chain when a write-back occurs.

To adjust or rewind a resume position:

  1. Read the current position payload:
    tapstate position orders_pipeline > position.json
  2. Replace resumeFrom.token only with a valid token for that connector and position. Do not invent a binlog/LSN string or substitute a displayed fingerprint.
  3. Apply the updated position while the pipeline is stopped:
    tapstate position orders_pipeline -f position.json

Modifying position while a pipeline or any pipeline sharing its mining chains is active is refused with position.write-back-while-live.

Serialized positions in metrics appear as opaque fingerprints. A position write-back summary also hides opaque coordinates. These displays do not expose an exact source LSN or binlog location; the JSON returned by a position read remains the editable payload.

Synchronize schema changes with derived-schema

Tapstate locks each pipeline run to a frozen copy of discovered source schemas so upstream DDL changes cannot unexpectedly disrupt an in-flight job.

Run derived-schema <pipeline-id> to inspect schema drift. It displays a three-way comparison for each pipeline step:

  • recorded: The schema previously recorded for that step (omitted for uninferrable steps such as custom scripts).
  • derived: The schema calculated now by applying pipeline transforms and joins to current stored discovery models.
  • target: The column layout declared on the destination table.

When upstream database schemas change and the target is ready to accept the new structure:

  1. Re-discover the source database so tapstate updates stored discovery models:
    tapstate discover-schema <source-id>
  2. Stop the pipeline and inspect the drift:
    tapstate derived-schema orders_pipeline
  3. Synchronize the pipeline definition:
    tapstate derived-schema orders_pipeline --accept

--accept copies the updated models from discovery storage into the pipeline definition, recomputes derived columns, and locks future pipeline starts to the updated schema. Running --accept while a pipeline is running is refused with actuation.schema-sync-while-running.

Structured output

The offline commands validate, new, ls, desc, and explain support:

-o text
-o json
-o yaml

In a connected session, structured output is available for delete, token, test, test-result, discover-schema, schema, register, and connectors. Calling position without -f outputs structured JSON directly. Lifecycle, status, metrics, logs, and apply commands use their command-specific text output.

Successful command output is written to standard output. Text-mode usage and diagnostic messages are written to standard error. When -o json or -o yaml is selected, the structured result, including validation diagnostics, is written to standard output so automation can parse one stream and use the exit code for success or failure.

Exit codes

CodeMeaning
0The command completed successfully.
1A coded domain diagnostic was returned or the operation was refused.
2The command line or operand usage is invalid.
3The operation is unavailable in the current context, not connected, or not implemented.

Automation should check the exit code instead of matching human-readable output. For multi-command scripted REPL sessions, the process exits with the exit code of the first rejected command rather than the final command executed.

Commands not implemented in the current preview

The top-level help lists run, export, diff, and edit as reserved verbs. They return exit code 3. Do not build a workflow that depends on them.

On this page