@dataworks-technology/cli
v1.6.1
Published
The official command-line interface for the Dataworks Data Engine
Readme
Dataworks — CLI
The official command-line interface for the Dataworks sports data platform. Authenticate with Dataworks, operate the public Data Engine API, ingest metrics, and consume real-time events from a terminal or automation workflow.
Overview
The dw binary turns the public GraphQL contract published by @dataworks-technology/data into discoverable, typed commands. It provides human-readable output for interactive use and stable JSON or NDJSON output for scripts and agents.
Command Surface
| Command | Description |
| --------------------- | ----------------------------------------------------------- |
| dw agents install | Install the Dataworks skill and MCP tools for AI agents |
| dw auth ... | Log in, log out, and inspect the active UAT or Live session |
| dw autocomplete | Install shell completion for commands and flags |
| dw data ... | Run schema-derived queries, mutations, and subscriptions |
| dw ingest | Send athlete metrics to the Data Engine ingest endpoint |
| dw events subscribe | Subscribe to AppSync Events channels |
| dw graphql ... | Run raw GraphQL queries, mutations, and subscriptions |
| dw report-error | Report a datasource error |
| dw tenant ... | List or select the tenant used by subsequent commands |
| dw commands | Print the complete command inventory |
Prerequisites
- Node.js 22 or newer to run the published CLI
- A Dataworks account
- Bun for repository development
- For repository development only: AWS credentials with CodeArtifact read access.
bun installruns apreinstallhook that fetches a token for the private@dataworks/sdkdevDependency, which supplies the metric catalogue. UseAWS_PROFILE=your-profile-name bun installfor a non-default profile, andbun run sdkto refresh an expired token. Installing the published CLI needs none of this.
Quickstart
Install the CLI:
npm install --global @dataworks-technology/cli dw --helpAuthenticate:
dw auth login --environment uat dw auth statusThe CLI opens Dataworks Managed Login in your browser and never receives your password. Sessions are stored in the operating-system credential store, never in the Dataworks config file. If a browser cannot be opened automatically, pass
--no-browserand visit the displayed URL on the same computer. Headless jobs can provide a protectedDW_SESSION_JSONsecret instead.The public UAT and Live Cognito client IDs are built in. Override them with
--client-id,DW_UAT_CLIENT_ID,DW_LIVE_CLIENT_ID, orDW_CLIENT_IDwhen testing a different app client.List and select a tenant. The selection is saved to your local profile and used by subsequent commands.
dw tenant list dw tenant select dw tenant select tenant-123dw tenant listshows the friendly name, ID, and current selection. Agents and scripts should usedw tenant list --json.Discover and run commands:
dw commands dw data athlete list dw data athlete create --name "Ada" --date-of-birth 1992-01-01
Generated command documentation is available in docs/commands.
Enable Dataworks in Codex or Claude Code:
dw agents installThis detects supported clients and installs the complete Dataworks plugin: the metric-query skill plus its read-only
query_metricsMCP server. Start a new Codex thread after installation. In Claude Code, run/reload-pluginsor start a new session. To configure only one client, usedw agents install codexordw agents install claude-code.Until setup is completed, interactive CLI use prints this reminder at most once every 24 hours. It never appears with
--json. Permanently hide it withdw agents reminder disable, restore it withdw agents reminder enable, or setDW_NO_AGENT_REMINDER=1for a single process or automation environment.
Bash autocomplete
Generate the completion cache and print the one-time Bash setup instructions:
dw autocomplete bashGlobal npm installs and upgrades run this command automatically. It prepares the
latest completion cache and prints the setup instruction, but does not edit your
shell startup files. If npm cannot access the shell cache, installation still
succeeds and you can retry with dw autocomplete bash.
After following the displayed instruction and reloading Bash, press Tab to
complete dw command names and flags. Run dw autocomplete --refresh-cache
after installing a release that adds commands.
AI agent metric queries
The package includes a focused, read-only MCP server with three tools:
query_metrics, list_athletes, and list_events. It uses the same OS-backed login session and selected tenant as
dw, resolves an athlete by exact ID or unique name, resolves metric names
against the canonical Dataworks catalogue, polls asynchronous Data Explorer
queries, and returns normalized structured rows. GPS values include decoded
latitude and longitude; heart-rate values use numeric BPM when valid.
Metric wording is matched case-, space-, hyphen- and underscore-insensitively,
so “Heart Rate” resolves to heartrate, alongside aliases such as gps, hr,
and watts. An unrecognized name returns the closest canonical candidates
rather than a bare rejection.
The simplest setup for Codex and Claude Code is:
dw agents installThe command is safe to rerun after upgrades. It installs or updates the complete
Dataworks plugin for each detected client and reports the reload or restart step.
If an old marketplace registration points to a different CLI installation, rerun
with --force.
Keeping the plugin current
Agent clients copy the plugin into a version-pinned directory rather than reading
the installed npm package, so upgrading the CLI does not by itself update the
skill an agent loads. The MCP server does move with the CLI, because it is
launched as dw-mcp from PATH — leaving a new server driven by an older skill
until the plugin is refreshed.
Global installs and upgrades refresh it automatically: the postinstall hook runs
dw agents install --refresh, which updates only clients that already have
Dataworks and configures nothing new. Reload the client afterwards with
/reload-plugins in Claude Code, or a new Codex thread.
When that cannot run — an install with --ignore-scripts, or a CLI reinstalled
under a different Node version — dw prints a reminder at most once a day
telling you the plugin is behind, and naming both steps needed to fix it.
Refresh with dw agents install, adding --force if the marketplace still
points at the previous installation, then reload the client.
Reloading matters either way: a client already running keeps the plugin copy it loaded at start-up, so refreshing alone changes nothing in the current session.
Successful setup automatically disables the periodic CLI reminder. To opt out
without installing an agent integration, run dw agents reminder disable.
Other MCP clients can launch the installed dw-mcp binary directly:
{
"mcpServers": {
"dataworks": {
"command": "dw-mcp",
"args": []
}
}
}The npm package ships a cross-compatible Codex and Claude Code plugin at
plugins/dataworks. Its focused skill turns requests such as “give me the last
30 GPS values for James Haigh” into a query_metrics call. The tool accepts
exactly one of athlete_id or athlete_name, plus metric; optional inputs are
limit, order, from, to, event_id, dataset_datasource_id,
tenant_id, metric_category, and timeout_ms.
A query must be scoped by athlete_id, athlete_name, event_id, or
dataset_datasource_id. Supplying only an event or datasource answers questions
about a whole race — "the latest heart rate values at T100 San Francisco" — and
returns a null athlete with each row still carrying its own athlete_id.
list_athletes and list_events exist so an agent can resolve an ID instead of
guessing one, and can tell "not in this tenant" apart from "misspelled". When
list_events reports unavailable: true the event API returned nothing for that
session, which is a permissions problem rather than an empty tenant.
The server never performs mutations. If name resolution is ambiguous, it
returns candidates and requires an explicit athlete ID rather than guessing.
Every error carries a recovery field naming the command that fixes it.
Output and Safety
- Commands render human-readable tables by default.
- Pass
--jsonfor scripts and agents. Finite results use a stable{data,meta}envelope; subscriptions and other streams emit newline-delimited JSON (NDJSON). - Generated mutations support
--dry-run --jsonto render a request without sending it. - Destructive mutations and all Live mutations require confirmation; non-interactive callers must pass
--yes. - Passwords, tokens, authorization headers, secrets, and API keys are redacted from structured output.
- Missing-argument errors list the required GraphQL types and representative values, then provide a safe copy-paste example and an exact
--helpcommand;--jsonincludes the same guidance as structured details.
# Preview a mutation without sending it
dw data athlete update --public-id athlete-123 --name "Ada L." --dry-run --json
# Explicitly confirm a destructive mutation
dw data athlete delete --public-id athlete-123 --yes
# Use raw GraphQL when no friendly command fits
dw graphql query --document @query.graphql --variables @variables.json --jsonIngest metrics
dw ingest validates and sends athlete metrics to an event and
dataset-datasource. Each metric requires athletePublicId, metric, value,
and a positive integer timestamp. Pass either an inline JSON array, a
{ "metrics": [...] } object, @filename, or - to read JSON from standard
input.
# Inline JSON
dw ingest --event event-123 --dataset-datasource ds-456 --metrics '[{"athletePublicId":"ath-1","metric":"heartrate_calculated","value":172,"timestamp":1700000000}]'
# File input; strict validation rejects the whole batch if any metric is invalid
dw ingest --event event-123 --dataset-datasource ds-456 --metrics @metrics.json
# Send valid metrics, report dropped invalid metrics, and return stable JSON
dw ingest --event event-123 --dataset-datasource ds-456 --metrics @metrics.json --best-effort --jsonSubscribe to realtime events
Realtime metric channels use
dataworks/<dataset-datasource-id>/<event-id>/<metric-or-*>. Use * to watch
every metric for that dataset-datasource/event pair or a metric name to narrow
the stream. A leading / is optional. Human output is tabular; add --json for
NDJSON.
Press Ctrl+C once to close the WebSocket subscription and return to the
shell.
# Watch all metrics for dataset-datasource 1 and event 1
dw events subscribe --channel dataworks/1/1/*
# Watch only heart-rate metrics as NDJSON
dw events subscribe --channel dataworks/1/1/heartrate --jsonQuery Data Explorer
dw data data-explorer execute queries metric storage with an explicit column
list and metric category. Optional fields support Data Explorer filter rules,
aggregation, grouping, ordering, limits, and polling an asynchronous
queryExecutionId. The category must be METRICS_TYPE_A, METRICS_TYPE_B, or
METRICS_TYPE_C; --columns is a JSON array.
# Keep a filtered GPS query in a reusable JSON file
dw data data-explorer execute --input @gps-query.json --json
# Return the latest 30 GPS positions for one athlete
dw data data-explorer execute --columns '["timestamp","athletepublicid","current"]' --metric-category METRICS_TYPE_A --filter-rules '{"combinator":"and","rules":[{"field":"metric","operator":"in","value":"latlong"},{"field":"athletepublicid","operator":"in","value":"athlete-123"}]}' --limit 30 --order-by timestamp --order-direction DESC --jsonThe corresponding gps-query.json contains the same fields without CLI flag
conversion:
{
"columns": ["timestamp", "athletepublicid", "metric", "current"],
"metricCategory": "METRICS_TYPE_A",
"filterRules": "{\"combinator\":\"and\",\"rules\":[{\"field\":\"metric\",\"operator\":\"in\",\"value\":\"latlong\"},{\"field\":\"athletepublicid\",\"operator\":\"in\",\"value\":\"athlete-123\"}]}",
"limit": 30,
"orderBy": "timestamp",
"orderDirection": "DESC"
}filterRules is an AWSJSON string containing a top-level combinator and a
rules array. Each rule has field, operator, and string value; supported
operators include =, !=, >, <, >=, <=, contains, and in.
Multiple values for in are comma-separated. GPS is metric latlong in
METRICS_TYPE_A; the current value is a latitude:longitude string. Run
dw data data-explorer execute --help for the complete flag list and examples.
In --json output, rows is AWSJSON and may need JSON-decoding until it becomes
an array; default table output performs that decoding for humans.
Common Commands
| Command | Description |
| ------------------------------- | ------------------------------------------------------------------- |
| bun install --frozen-lockfile | Install development dependencies |
| bun run sdk | Refresh the CodeArtifact token used to fetch @dataworks/sdk |
| bun run dev --help | Run the TypeScript development CLI |
| bun run generate | Regenerate schema-derived commands and Markdown |
| bun run generate:check | Verify generated files are current |
| bun run test | Run the Vitest unit tests |
| bun run lint | Run the TypeScript checks |
| bun run format | Format files with Prettier |
| bun run build | Generate commands, compile for Node, and build the oclif manifest |
| make verify | Run generation, formatting, typing, tests, and the production build |
SDK and Command Generation
The Data Engine SDK publishes a filtered public GraphQL schema and a versioned contract containing its SDK version, operation counts, and schema hash. This repository pins that SDK version, validates the contract, and generates one oclif command and Markdown page for every public operation.
Files under src/generated/, src/commands/data/, and docs/commands/ are generated. Change schema/operation-overrides.json, scripts/generate-commands.ts, or the upstream public schema instead of editing generated files.
Canonical metric names are generated the same way. scripts/generate-metrics.ts reads metricConfig from the private @dataworks/sdk devDependency and emits src/generated/metrics.ts and the catalogue block in the query-dataworks-metrics skill. To add a metric, change the SDK — not the generated files, and not the alias layer in src/lib/metric-names.ts.
The daily SDK maintenance workflow checks for new @dataworks-technology/data and @dataworks/sdk versions. Deterministic generation runs first; if compatibility work is required, a constrained LiteLLM maintenance agent prepares a draft pull request for human review.
See architecture, contributing, automated SDK maintenance, security, and releasing for details.
CI/CD
| Trigger | Workflow | Description |
| --------------------------------- | -------------- | --------------------------------------------------------------------------------------------------------------------------- |
| Pull request or push to main | ci.yml | Verifies generation, formatting, types, tests, builds, and packaging on the labelled self-hosted runner with Node 22 and 24 |
| Daily schedule or manual dispatch | sdk-sync.yml | Updates the Data SDK and opens or refreshes a draft maintenance PR |
| Manual dispatch | uat-e2e.yml | Authenticates against UAT and reads the public Data manifest |
| Push to main | release.yml | Runs release-please on the self-hosted runner, then publishes with npm provenance from the required GitHub-hosted runner |
Automated SDK update pull requests remain drafts until a human reviews and marks them ready.
Code Style
- Bun for dependency management and repository scripts
- Node.js 22+ compatibility for the published CLI
- Prettier for formatting
- Vitest for unit tests
- Conventional commits enforced by commitlint (
feat:,fix:,chore:,refactor:,test:,docs:) - Explicit risk classification for every generated GraphQL mutation
Cross-Repo Dependencies
- Depends on Dataworks-Data for the public GraphQL schema and
@dataworks-technology/datapackage - Uses the same public contract that generates the Data SDK Docusaurus reference
- Authenticates against the UAT or Live Cognito and Data Engine endpoints at runtime
- New SDK versions are consumed through reviewed automated pull requests rather than manual schema copying
Contributors
License
MIT
