dw
The Doubleword Batch Inference CLI. Upload JSONL files, run batches, stream results, and send real-time inference requests — all from the terminal.
Features
- Batch processing — upload files, create batches, watch progress, download results
- Streaming —
dw streamgoes from JSONL file to piped results in one command - Real-time inference — one-shot streaming requests via
dw realtime - Local file tools — validate, prepare, stats, sample, merge, split, and diff JSONL files without uploading
- Project scaffolding —
dw project initcreates ready-to-run project templates - Multi-account — manage multiple accounts and organizations, switch between them like kubectl contexts
- Output formats — table for interactive use, JSON for scripts, auto-detected from TTY
- Shell completions — bash, zsh, and fish
- Self-update —
dw updatedownloads the latest release
Quick Example
# Authenticate
dw login
# See available models
dw models list
# Run a batch and stream results (prints "Batch: <id>" to stderr)
dw stream batch.jsonl > results.jsonl
# One-shot inference
dw realtime Qwen/Qwen3-VL-30B-A3B-Instruct-FP8 "Explain batch inference"
# Check what the batch cost (use the batch ID from dw stream output)
dw batches analytics <batch-id>
Installation
Install Script (recommended)
curl -fsSL https://raw.githubusercontent.com/doublewordai/dw/main/install.sh | sh
This downloads the latest release binary for your platform and installs it to ~/.local/bin/. The script detects your OS (Linux, macOS) and architecture (x86_64, arm64) automatically.
From Source
git clone https://github.com/doublewordai/dw.git
cd dw
cargo build --release
cp target/release/dw ~/.local/bin/
Requires Rust 2024 edition (1.85+).
Verify
dw --version
Shell Completions
Generate shell completions for your shell:
# Bash
dw completions bash > ~/.local/share/bash-completion/completions/dw
# Zsh
dw completions zsh > ~/.zfunc/_dw
# Fish
dw completions fish > ~/.config/fish/completions/dw.fish
Updating
dw update
This downloads the latest release from GitHub, verifies the checksum, and replaces the binary in place.
Authentication
Browser Login (recommended)
dw login
Opens your browser to the Doubleword SSO page. After authenticating, the CLI receives API keys for both the inference and admin APIs. Credentials are stored in ~/.dw/credentials.toml with 0600 permissions.
Logging into an Organization
dw login --org my-org
When you log in with --org, the CLI creates credentials scoped to that organization. Batches, files, and usage are billed to the org.
Custom Account Name
dw login --as work
By default the account is named after your email or org. Use --as to set a custom name.
API Key Login (headless)
For SSH sessions, containers, and CI:
dw login --api-key <YOUR_INFERENCE_KEY>
API key login stores only the inference key. Commands that use the admin API will not be available, including dw whoami, dw usage, dw requests, dw keys, and dw webhooks. For full functionality, use browser login (with port forwarding for remote sessions).
Credentials Storage
Credentials are stored in ~/.dw/credentials.toml:
~/.dw/
├── config.toml # Active account, server URLs
└── credentials.toml # API keys (0600 permissions)
Logging Out
# Log out of the active account
dw logout
# Log out of a specific account
dw logout work
# Log out of all accounts
dw logout --all
Checking Your Identity
dw whoami
Shows the authenticated user and active organization (if any).
Quickstart
This guide walks through a complete batch workflow: prepare a file, submit it, and get results.
1. Log In
dw login
2. See Available Models
dw models list
3. Create a Batch File
A batch file is JSONL where each line is an API request:
{"custom_id": "q1", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "Qwen/Qwen3-VL-30B-A3B-Instruct-FP8", "messages": [{"role": "user", "content": "What is batch inference?"}], "max_tokens": 256}}
{"custom_id": "q2", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "Qwen/Qwen3-VL-30B-A3B-Instruct-FP8", "messages": [{"role": "user", "content": "Explain transformers in 2 sentences."}], "max_tokens": 256}}
Save this as batch.jsonl.
4. Validate and Inspect
dw files validate batch.jsonl
dw files stats batch.jsonl
5. Submit and Stream Results
The fastest path from file to results:
dw stream batch.jsonl > results.jsonl
This uploads the file, creates a batch, watches progress, and pipes results to stdout as they complete.
6. Check Cost
For a single input file, dw stream prints Batch: <id> to stderr when the batch is created. When streaming a directory of multiple JSONL files, batch IDs are printed after streaming completes. Use a printed batch ID to see the cost breakdown:
dw batches analytics <batch-id>
Alternative: Step-by-Step
If you prefer manual control over each step:
# Upload
dw files upload batch.jsonl
# Create batch from the uploaded file
dw batches create --file <file-id>
# Watch progress
dw batches watch <batch-id>
# Download results
dw batches results <batch-id> -o results.jsonl
Real-Time Inference
For one-off requests without a batch file:
dw realtime Qwen/Qwen3-VL-30B-A3B-Instruct-FP8 "What is batch inference?"
Next Steps
- Batch Processing — full batch workflow details
- Local File Operations — validate, prepare, merge, split JSONL
- Project System — scaffold and run multi-step projects
- Examples — real-world use-case examples
Batch Processing
Batch processing lets you submit thousands of API requests in a single JSONL file and process them asynchronously at reduced cost.
Creating a Batch
One-Step: dw batches run
Upload a file and create a batch in one command:
dw batches run batch.jsonl
With progress watching:
dw batches run batch.jsonl --watch
Override the model for all requests:
dw batches run batch.jsonl --model Qwen/Qwen3-VL-235B-A22B-Instruct-FP8 --watch
Process an entire directory of JSONL files:
dw batches run output/ --watch
Step-by-Step
# Upload the file
dw files upload batch.jsonl
# Create a batch from the uploaded file
dw batches create --file file-abc123
# Optionally set a 1-hour completion window (default: 24h)
dw batches create --file file-abc123 --completion-window 1h
# Add metadata
dw batches create --file file-abc123 --metadata project=evals --metadata run=1
Monitoring
Watch Progress
Watch one batch:
dw batches watch batch-abc123
Watch multiple batches with parallel progress bars:
dw batches watch batch-abc123 batch-def456 batch-ghi789
Check Status
dw batches get batch-abc123
List Batches
# Recent batches
dw batches list
# Active batches first
dw batches list --active-first
# All batches (auto-paginate)
dw batches list --all
Results
Download Results
dw batches results batch-abc123 -o results.jsonl
Without -o, results are printed to stdout.
Batch Analytics
dw batches analytics batch-abc123
Shows token usage, latency breakdown, and cost for a completed batch.
Cancellation and Retry
Cancel a Batch
dw batches cancel batch-abc123
Prompts for confirmation. Use --yes to skip:
dw batches cancel batch-abc123 --yes
Retry Failed Requests
dw batches retry batch-abc123
Creates a new batch containing only the failed requests from the original batch.
Completion Windows
The completion window determines the SLA for batch processing:
| Window | Description |
|---|---|
24h | Default. Standard batch pricing. |
1h | Priority processing. Results in ~1 hour. |
dw batches run batch.jsonl --completion-window 1h
Cost Estimates
Before submitting, check the estimated cost:
dw files upload batch.jsonl
dw files cost-estimate <file-id>
dw files cost-estimate <file-id> --completion-window 1h
Saving Batch IDs
When running multiple files, save batch IDs for later reference:
dw batches run output/ --output-id batch-ids.txt
This writes one batch ID per line to the specified file.
Streaming Results
dw stream is the fastest path from a JSONL file to results. It uploads the file, creates a batch, watches progress, and streams results to stdout as they complete.
Basic Usage
dw stream batch.jsonl > results.jsonl
Progress is printed to stderr, results to stdout. This means you can pipe results while still seeing progress.
Streaming a Directory
When given a directory, dw stream processes all .jsonl files in it:
dw stream output/ > results.jsonl
Each file becomes a separate batch. Progress bars for all batches are shown in parallel.
Model Override
Set the model for all requests without modifying the file:
dw stream batch.jsonl --model Qwen/Qwen3-VL-235B-A22B-Instruct-FP8 > results.jsonl
Completion Window
dw stream batch.jsonl --completion-window 1h > results.jsonl
How It Works
- If
--modelis specified, the file is transformed to a temp file with the model set - The file is uploaded via
POST /v1/files - A batch is created from the uploaded file
- The CLI polls the batch status, showing a progress bar
- As results become available, they're fetched via the file content endpoint and written to stdout
- Polling continues until the batch completes
Results are streamed incrementally — you don't have to wait for the entire batch to finish before seeing output.
When to Use Stream vs Batches Run
| Use Case | Command |
|---|---|
| Quick one-off, pipe to file | dw stream batch.jsonl > results.jsonl |
| Fire and forget, check later | dw batches run batch.jsonl |
| Multiple files, watch progress | dw batches run output/ --watch |
| CI pipeline, save batch ID | dw batches run batch.jsonl --output-id batch.txt |
dw stream is a convenience wrapper. For more control (metadata, retries, ID tracking), use dw batches run and dw batches results separately.
Real-Time Inference
dw realtime sends a single inference request and streams the response. Useful for quick tests, prototyping prompts, and interactive use.
Basic Usage
dw realtime Qwen/Qwen3-VL-30B-A3B-Instruct-FP8 "Explain batch inference in one paragraph"
The response streams token-by-token to stdout.
System Message
dw realtime Qwen/Qwen3-VL-30B-A3B-Instruct-FP8 "Summarize this text" \
--system "You are a concise technical writer."
Reading from Stdin
When no prompt is given, dw realtime reads from stdin:
echo "What is 2+2?" | dw realtime Qwen/Qwen3-VL-30B-A3B-Instruct-FP8
cat document.txt | dw realtime Qwen/Qwen3-VL-30B-A3B-Instruct-FP8 --system "Summarize this"
Options
| Flag | Description |
|---|---|
--system <MSG> | Set the system message |
--max-tokens <N> | Maximum tokens to generate |
--temperature <T> | Sampling temperature (0.0-2.0) |
--no-stream | Wait for full response instead of streaming |
-o, --output-file <FILE> | Write response to a file |
--usage | Print token usage summary after completion |
Non-Streaming Mode
dw realtime Qwen/Qwen3-VL-30B-A3B-Instruct-FP8 "Hello" --no-stream
Waits for the complete response before printing. Useful when you need the full text at once (e.g., for piping to jq).
Token Usage
dw realtime Qwen/Qwen3-VL-30B-A3B-Instruct-FP8 "Hello" --usage
Prints input/output token counts to stderr after the response completes.
Output to File
dw realtime Qwen/Qwen3-VL-30B-A3B-Instruct-FP8 "Write a poem" -o poem.txt
JSONL Format
Doubleword uses the OpenAI-compatible batch JSONL format. Each line is a JSON object representing one API request.
Chat Completions
{
"custom_id": "request-001",
"method": "POST",
"url": "/v1/chat/completions",
"body": {
"model": "Qwen/Qwen3-VL-30B-A3B-Instruct-FP8",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is batch inference?"}
],
"max_tokens": 512,
"temperature": 0
}
}
Embeddings
{
"custom_id": "emb-001",
"method": "POST",
"url": "/v1/embeddings",
"body": {
"model": "Qwen/Qwen3-Embedding-8B",
"input": "The quick brown fox"
}
}
Vision (Multimodal)
{
"custom_id": "img-001",
"method": "POST",
"url": "/v1/chat/completions",
"body": {
"model": "Qwen/Qwen3-VL-30B-A3B-Instruct-FP8",
"messages": [
{
"role": "user",
"content": [
{"type": "text", "text": "Describe this image."},
{"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,/9j/4AA..."}}
]
}
]
}
}
Required Fields
| Field | Description |
|---|---|
custom_id | Unique identifier for the request. Used to match results. |
method | HTTP method. Always "POST". |
url | API endpoint. /v1/chat/completions or /v1/embeddings. |
body | The request body, matching the OpenAI API format. |
Model Field
The model field in the body can be:
- Set in the JSONL file directly
- Omitted and set later with
dw files prepare --model <name> - Overridden at upload/run time with
--model
The recommended pattern for reusable batch files is to omit the model and set it with dw files prepare:
dw files prepare batch.jsonl --model Qwen/Qwen3-VL-30B-A3B-Instruct-FP8
Result Format
Results are also JSONL, one line per completed request:
{
"id": "req-abc123",
"custom_id": "request-001",
"response_body": {
"id": "chatcmpl-xyz",
"object": "chat.completion",
"model": "Qwen/Qwen3-VL-30B-A3B-Instruct-FP8",
"choices": [
{
"index": 0,
"message": {"role": "assistant", "content": "Batch inference is..."},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 42,
"completion_tokens": 128,
"total_tokens": 170
}
}
}
Match results to requests using the custom_id field.
Local File Operations
The CLI includes local JSONL tools that run without uploading or authenticating. These are useful for preparing, inspecting, and manipulating batch files before submission.
Validate
Check a JSONL file for format errors:
dw files validate batch.jsonl
Validates that each line is valid JSON with the required fields (custom_id, method, url, body).
Stats
Show statistics for a JSONL file:
dw files stats batch.jsonl
Output includes line count, models used, and estimated token counts.
Prepare
Transform a JSONL file in place (or to a new file):
# Set the model on every line
dw files prepare batch.jsonl --model Qwen/Qwen3-VL-30B-A3B-Instruct-FP8
# Set model and temperature
dw files prepare batch.jsonl --model Qwen/Qwen3-VL-30B-A3B-Instruct-FP8 --temperature 0
# Write to a new file instead of modifying in place
dw files prepare batch.jsonl --model Qwen/Qwen3-VL-30B-A3B-Instruct-FP8 -o batch-30b.jsonl
# Prepare all files in a directory
dw files prepare output/ --model Qwen/Qwen3-VL-30B-A3B-Instruct-FP8
Setting Arbitrary Fields
Use --set for any field in the request body:
dw files prepare batch.jsonl --set body.stream=false --set body.top_p=0.9
Encoding Images
Convert local image paths and URLs to base64 data URIs:
dw files prepare batch.jsonl --encode-images
Adding and Removing Lines
# Append a new request line
dw files prepare batch.jsonl --add-line '{"custom_id":"extra","method":"POST","url":"/v1/chat/completions","body":{"messages":[{"role":"user","content":"test"}]}}'
# Remove lines matching a pattern
dw files prepare batch.jsonl --remove-lines "test-*"
Sample
Extract a random sample from a JSONL file:
dw files sample batch.jsonl -n 10 -o sample.jsonl
Uses reservoir sampling for bounded memory on large files.
Merge
Combine multiple JSONL files into one:
dw files merge file1.jsonl file2.jsonl file3.jsonl -o merged.jsonl
Split
Split a JSONL file into chunks:
dw files split large.jsonl --chunk-size 1000
Creates large_001.jsonl, large_002.jsonl, etc. in the same directory. Use -o for a different output directory:
dw files split large.jsonl --chunk-size 1000 -o chunks/
Diff
Compare two JSONL result files by custom_id:
dw files diff results-30b.jsonl results-235b.jsonl
Shows which custom_ids are present in one file but not the other, and a content hash comparison for matching IDs.
Project System
The project system lets you define multi-step workflows in a dw.toml manifest file and run them with dw project commands.
Creating a Project
From a Template
dw project init my-project
Interactive prompts let you choose a template:
| Template | Description |
|---|---|
single-batch | Prepare, submit, and analyze a single batch |
pipeline | Multi-stage pipeline (prepare -> run stages -> analyze) |
shell | Shell-script steps instead of Python |
minimal | Just a dw.toml with no scaffolding |
Or specify directly:
dw project init my-project --template pipeline
From an Example
dw examples clone model-evals
cd model-evals
Manually
Create a dw.toml in your project directory.
The dw.toml Manifest
[project]
name = "my-project"
setup = "uv sync"
workflow = [
"dw project setup",
"dw project run prepare -- -n 100",
"dw files stats batches/batch.jsonl",
"dw files prepare batches/batch.jsonl --model Qwen/Qwen3-VL-30B-A3B-Instruct-FP8",
"dw batches run batches/batch.jsonl --watch --output-id .batch-id",
"dw batches results $(cat .batch-id) -o results.jsonl",
"dw project run analyze -- -r results.jsonl",
"dw batches analytics $(cat .batch-id)",
]
[steps.prepare]
description = "Download dataset and generate batch JSONL"
run = "uv run my-project prepare"
[steps.analyze]
description = "Score results against ground truth"
run = "uv run my-project score"
Fields
| Field | Description |
|---|---|
project.name | Project name |
project.setup | Command to run on dw project setup (e.g., uv sync) |
project.workflow | Ordered list of commands for dw project run-all and dw project info |
steps.<name>.run | Shell command to execute for this step |
steps.<name>.description | Human-readable description shown in dw project info |
Running Steps
Setup
Install dependencies:
dw project setup
Runs the project.setup command from dw.toml.
Individual Steps
dw project run prepare
Pass extra arguments after --:
dw project run prepare -- -n 100 --output custom.jsonl
Full Workflow
Run all workflow steps sequentially:
dw project run-all
This executes every command in the workflow array, skipping dw project setup (run it separately first).
Resume After Failure
If a step fails, fix the issue and continue from where you left off:
dw project run-all --continue
Or start from a specific step:
dw project run-all --from 3
Inspecting State
Project Info
dw project info
Shows available steps, descriptions, and the full workflow.
Run Status
dw project status
Shows the current run state: which steps have completed, which failed, and where the run left off.
Cleanup
dw project clean
Removes batches/, results/, and the run state file (.dw-run.json).
Workflow Comments
Lines in the workflow starting with # are comments. They are displayed in dw project info but skipped during dw project run-all and excluded from step numbering for --from:
workflow = [
"dw project setup",
"# Download the dataset from: https://example.com/data",
"dw project run prepare",
]
Examples
Doubleword provides a set of real-world use-case examples that demonstrate different batch inference patterns.
Listing Examples
dw examples list
Cloning an Example
dw examples clone model-evals
cd model-evals
dw project setup
dw project info
Each example includes a dw.toml manifest, Python code, and a README with full instructions.
Available Examples
Model Evals
Evaluate LLM accuracy at batch pricing. Runs the full GSM8K test set and scores model answers against ground truth.
dw examples clone model-evals
Embeddings
Batch embeddings for semantic search. Downloads Wikipedia abstracts, generates embeddings, and builds a searchable HNSW index.
dw examples clone embeddings
Synthetic Data Generation
Generate training data at scale. Three-stage pipeline: scenario generation, conversation generation, and quality filtering.
dw examples clone synthetic-data-generation
Data Processing Pipelines
Clean and enrich company records. Normalize names, deduplicate, and classify industries using real SEC EDGAR data.
dw examples clone data-processing-pipelines
Image Summarization
Vision-language batch inference. Fetches images from Unsplash, encodes them, and generates social media-style summaries.
dw examples clone image-summarization
Structured Extraction
Extract fields from scanned documents. Receipt data extraction with ensemble voting on the SROIE dataset.
dw examples clone structured-extraction
Bug Detection Ensemble
Classify security vulnerabilities. CWE classification on the CVEfixes dataset with calibration via running twice.
dw examples clone bug-detection-ensemble
Dataset Compilation
Compile exhaustive datasets with LLM + search. Recursive query expansion, web search, extraction, and filtering.
dw examples clone dataset-compilation
Async Agents
Deep research with recursive multi-agent orchestration. A root agent spawns sub-agents that independently search the web and synthesize findings.
dw examples clone async-agents
Running an Example
Every example follows the same pattern:
dw examples clone <name>
cd <name>
dw project setup # Install dependencies
dw project info # See the workflow
dw project run-all # Run everything
Or run steps individually — see dw project info for the full workflow.
Command Reference
Full reference for all dw commands. Run dw <command> --help for details on any command.
Auth
| Command | Description |
|---|---|
dw login | Authenticate via browser or API key |
dw login --api-key <KEY> | Headless authentication |
dw login --org <ORG> | Login within an organization |
dw login --as <NAME> | Set a custom account name |
dw logout | Remove active account credentials |
dw logout --all | Remove all stored credentials |
dw whoami | Show authenticated user |
Accounts
| Command | Description |
|---|---|
dw account list | List all stored accounts |
dw account current | Show the active account |
dw account switch <NAME> | Switch the active account |
dw account rename <OLD> <NEW> | Rename an account |
dw account remove <NAME> | Remove a stored account |
Models
| Command | Description |
|---|---|
dw models list | List available models |
dw models list --type chat | Filter by type (chat, embeddings, reranker) |
dw models get <MODEL> | Get model details |
Files
Remote (requires auth)
| Command | Description |
|---|---|
dw files upload <PATH> | Upload a JSONL file |
dw files list | List uploaded files |
dw files list --all | List all files (auto-paginate) |
dw files list --purpose all | Include output and error files |
dw files get <ID> | Get file metadata |
dw files delete <ID> | Delete a file |
dw files content <ID> | Download file content |
dw files cost-estimate <ID> | Get processing cost estimate |
Local (no auth needed)
| Command | Description |
|---|---|
dw files validate <PATH> | Validate JSONL format |
dw files prepare <PATH> | Transform JSONL (model, params, images) |
dw files stats <PATH> | Show line count, models, token estimates |
dw files sample <PATH> -n <N> | Random sample from JSONL |
dw files merge <FILES...> | Merge multiple JSONL files |
dw files split <PATH> | Split JSONL into chunks |
dw files diff <A> <B> | Compare two result files |
Batches
| Command | Description |
|---|---|
dw batches run <PATH> | Upload + create batch (one step) |
dw batches run <PATH> --watch | Upload + create + watch progress |
dw batches create --file <ID> | Create batch from uploaded file |
dw batches list | List batches |
dw batches get <ID> | Get batch details |
dw batches cancel <ID> | Cancel a running batch |
dw batches retry <ID> | Retry failed requests |
dw batches results <ID> | Download results |
dw batches watch <IDS...> | Watch batch progress |
dw batches analytics <ID> | Show batch analytics |
Stream
| Command | Description |
|---|---|
dw stream <PATH> | Upload, batch, watch, and pipe results |
Realtime
| Command | Description |
|---|---|
dw realtime <MODEL> <PROMPT> | One-shot streaming inference |
Usage & Requests
| Command | Description |
|---|---|
dw usage | Show usage summary (tokens, cost, requests) |
dw usage --since 2026-03-01 | Usage from a specific date |
dw usage --since 2026-03-01 --until 2026-03-31 | Usage for a date range |
dw requests | List recent requests |
Keys
| Command | Description |
|---|---|
dw keys create --name <NAME> | Create an API key |
dw keys list | List API keys (secrets masked) |
dw keys delete <ID> | Delete an API key |
Webhooks
| Command | Description |
|---|---|
dw webhooks create --url <URL> | Create a webhook |
dw webhooks list | List webhooks |
dw webhooks delete <ID> | Delete a webhook |
dw webhooks rotate-secret <ID> | Rotate signing secret |
Projects
| Command | Description |
|---|---|
dw project init [NAME] | Create a new project from template |
dw project setup | Run project setup command |
dw project run <STEP> | Run a named step |
dw project run-all | Run full workflow |
dw project run-all --continue | Resume from last completed step |
dw project status | Show run progress |
dw project clean | Remove artifacts |
dw project info | Show steps and workflow |
Examples
| Command | Description |
|---|---|
dw examples list | List available examples |
dw examples clone <NAME> | Clone an example project |
Config
| Command | Description |
|---|---|
dw config show | Show current configuration |
dw config set-url <URL> | Set both API URLs |
dw config set-ai-url <URL> | Set inference API URL |
dw config set-admin-url <URL> | Set admin API URL |
dw config reset-urls | Reset URLs to defaults |
Other
| Command | Description |
|---|---|
dw update | Self-update to latest release |
dw completions <SHELL> | Generate shell completions |
Accounts & Configuration
The CLI supports multiple accounts (personal and org contexts), similar to kubectl contexts.
Accounts
Multiple Accounts
Each dw login creates a new account. You can log in to multiple accounts and switch between them:
# Login to personal account
dw login
# Login to an org
dw login --org my-company --as company
# Login to a self-hosted deployment
dw login --as work --server https://dw.internal.example.com
Switching Accounts
dw account list
dw account switch company
Using a Specific Account for One Command
dw batches list --account company
The --account flag overrides the active account for a single command.
Managing Accounts
# Rename
dw account rename old-name new-name
# Remove
dw account remove old-account
# Show active
dw account current
Configuration
Configuration is stored in ~/.dw/config.toml:
active_account = "you@example.com"
[client]
timeout_secs = 300
connect_timeout_secs = 10
max_retries = 1
poll_interval_secs = 2
Server URLs
For self-hosted or custom deployments:
# Point both APIs to one server
dw config set-url https://dw.example.com
# Or set individually
dw config set-ai-url https://api.example.com
dw config set-admin-url https://app.example.com
# Reset to defaults
dw config reset-urls
Client Settings
Configure in ~/.dw/config.toml under the [client] section:
| Setting | Default | Description |
|---|---|---|
timeout_secs | 300 | HTTP request timeout in seconds |
connect_timeout_secs | 10 | TCP connect timeout in seconds |
max_retries | 1 | Max retries on transient errors (0–10) |
poll_interval_secs | 2 | Seconds between polls for watch and stream (min: 1) |
All fields are optional. Omit individual fields or the entire [client] section to use defaults.
Viewing Configuration
dw config show
Shows active account, default output format, and server URLs.
Output Formats
The CLI auto-detects the best output format:
| Context | Format | Description |
|---|---|---|
| Interactive terminal | table | Human-readable tables |
| Piped to another command | json | One JSON object per line |
Override with the --output flag:
dw batches list --output json
dw models list --output plain
Available formats: table, json, plain.
API Keys & Webhooks
API Keys
Create and manage API keys for programmatic access.
Create a Key
dw keys create --name "ci-pipeline"
dw keys create --name "my-agent" --description "Used by the research agent"
The key secret is shown once at creation time. Store it securely.
List Keys
dw keys list
Secrets are masked in the output. Only metadata (name, ID, creation date) is shown.
Delete a Key
dw keys delete <key-id>
dw keys delete <key-id> --yes # Skip confirmation
Webhooks
Webhooks notify your endpoints when batch events occur.
Create a Webhook
dw webhooks create --url https://example.com/webhook
With specific events:
dw webhooks create --url https://example.com/webhook --events "batch.completed,batch.failed"
With a description:
dw webhooks create --url https://example.com/webhook --description "Notify Slack on batch completion"
The webhook signing secret is shown once at creation time. Use it to verify webhook payloads.
List Webhooks
dw webhooks list
Delete a Webhook
dw webhooks delete <webhook-id>
dw webhooks delete <webhook-id> --yes # Skip confirmation
Rotate Signing Secret
dw webhooks rotate-secret <webhook-id>
Generates a new signing secret. The old secret stops working immediately.
Usage & Analytics
Usage Summary
dw usage
Shows total tokens, requests, and cost broken down by model.
Date Filtering
# Usage since a specific date
dw usage --since 2026-03-01
# Usage for a date range
dw usage --since 2026-03-01 --until 2026-03-31
Dates can be YYYY-MM-DD (date-only) or full RFC 3339 timestamps (2026-03-01T00:00:00Z). Date-only values are treated as midnight UTC.
Recent Requests
dw requests
Lists recent requests with model, status, latency, and token counts.
Note:
dw requestsrequires the RequestViewer role and a platform key (browser login). It is not available withdw login --api-key.
Filtering
dw requests --model Qwen/Qwen3-VL-30B-A3B-Instruct-FP8 --since 2026-03-27
Batch Analytics
For per-batch analytics:
dw batches analytics <batch-id>
Shows token usage (prompt, completion, total), average latency, average TTFB, and cost for a completed batch.
Global Flags
These flags are available on every dw command.
| Flag | Description |
|---|---|
--output <FORMAT> | Output format: table, json, or plain. Auto-detected from TTY by default. |
--account <NAME> | Use a specific account instead of the active one. |
--server <URL> | Override both inference and admin API URLs. |
--server-ai <URL> | Override the inference API URL (default: https://api.doubleword.ai). |
--server-admin <URL> | Override the admin API URL (default: https://app.doubleword.ai). |
--help | Show help for any command. |
--version | Show the CLI version. |
Output Format
The CLI auto-detects the output format based on whether stdout is a TTY:
- TTY (interactive terminal):
table— human-readable tables with headers and alignment - Pipe or redirect:
json— JSON output suitable forjqprocessing (NDJSON for lists, pretty-printed for single items)
Override with --output:
# Force JSON in terminal
dw batches list --output json
# Force table when piping (not common, but possible)
dw batches list --output table | less
# Plain text (tab-separated, no headers)
dw batches list --output plain
Server Overrides
Useful for self-hosted or custom deployments:
# Both APIs on the same server
dw batches list --server https://dw.example.com
# Different URLs for inference and admin
dw stream batch.jsonl --server-ai https://api.example.com --server-admin https://app.example.com
For persistent server overrides, use dw config set-url instead. See Accounts & Configuration.
Account Override
Run a command as a different account without switching:
dw batches list --account my-org
dw models list --account company