Woodwide AI CLI -- agent-friendly command-line client to work with the Wood Wide models
Project description
wwai CLI
Agent-friendly command-line client for the Woodwide AI API.
Install
Recommended (isolated install — works anywhere, no virtualenv needed):
uv tool install woodwide-cli
# or
pipx install woodwide-cli
Or as a regular package in an existing environment:
pip install woodwide-cli
Once installed, wwai is on your PATH:
wwai --help
Local development
If you're hacking on the CLI in this monorepo, install it editable from the package directory:
cd wwai-cli
uv pip install -e .
wwai --help
Authentication
Provide your API key via any of these methods (first wins):
# 1. Flag
wwai --api-key sk_live_abc123 datasets list
# 2. Environment variable
export WOODWIDE_API_KEY=sk_live_abc123
wwai datasets list
# 3. Config file
wwai config set --api-key sk_live_abc123
wwai datasets list
Config is stored in ~/.wwai/config.json.
Pointing to a local API
wwai config set --api-key sk_test_... --base-url http://localhost:8080
# or
export WOODWIDE_BASE_URL=http://localhost:8080
Commands
wwai config set Save API key / base URL
wwai config show Print current config (key redacted)
wwai datasets list List datasets (supports --include-archived)
wwai datasets get Get dataset details
wwai datasets create Upload a CSV/Parquet file (multipart)
wwai datasets upload Upload via signed URL (large files)
wwai datasets update Update name/description
wwai datasets delete Soft-delete a dataset
wwai datasets preview Sample rows from the current version
wwai datasets lookup Fetch rows by id column value
wwai datasets models List models trained on this dataset
wwai datasets versions List versions of a dataset
wwai datasets version Get a specific dataset version
wwai models list List models
wwai models get Get model details
wwai models train Train a new model
wwai models retrain Retrain (dispatched via POST /models/train)
wwai models delete Delete a model and all its versions
wwai models versions List versions of a model
wwai models version Get a specific model version
wwai infer sync Synchronous file inference
wwai infer async Async file inference
wwai infer batch Async dataset inference (cached by default; --force-rerun to bypass)
wwai jobs list List jobs
wwai jobs get Get job details
wwai jobs cancel Cancel a job
wwai jobs retry Retry a failed job
wwai jobs results Get job results
wwai jobs wait Poll until completion
wwai jobs dashboard-activity Per-day counts + window aggregates
wwai org get Get organization details
wwai api-keys list List API keys
wwai api-keys get Get API key details
wwai api-keys create Create a new key (supports --scopes, --expires-at)
wwai api-keys update Update name/scopes/expires_at
wwai api-keys revoke Revoke a key (keeps audit trail)
wwai api-keys delete Hard-delete a key (no audit trail)
wwai api-keys rotate Rotate a key
Run wwai <command> --help for full options and examples on any command.
Output format
JSON by default (machine-readable). Use --format table for human-readable output:
wwai --format table datasets list
End-to-end lifecycle
Every ML workflow follows the same three-phase pattern:
1. Upload data --> 2. Train a model --> 3. Run inference to get results
Training and inference are async. They return a job_id which you poll
until the job reaches a terminal status (succeeded or failed). The
--wait flag automates this polling for you.
Phase 1: Upload a dataset
Upload a CSV or Parquet file. This creates a dataset and an ingestion job that processes the file into a queryable format.
wwai datasets create --file train.csv --name "sales-q4"
Output (JSON):
{
"dataset": { "id": "DATASET_ID", "version_id": "VERSION_ID", "version_number": 1 },
"job_id": "INGEST_JOB_ID",
"status": "queued"
}
The dataset is ready once the ingest job succeeds. You can wait for it:
wwai jobs wait INGEST_JOB_ID
Phase 2: Train a model
Train a model on the dataset. You must specify the model type.
prediction models require --label-column; other types do not.
wwai models train \
--dataset DATASET_ID \
--type prediction \
--label-column revenue
Output (JSON):
{
"model": { "id": "MODEL_ID", "version_id": "MV_ID", "version_number": 1 },
"job_id": "TRAIN_JOB_ID",
"status": "queued"
}
Training is async. You must wait for it to finish before running
inference. Use --wait to block until done:
wwai models train \
--dataset DATASET_ID \
--type prediction \
--label-column revenue \
--wait
Or poll separately:
wwai jobs wait TRAIN_JOB_ID --timeout 600
The model is ready for inference once the training job status is succeeded.
Phase 3: Run inference to get results
Once a model is trained (status: ready), run inference to get
predictions on new data. There are three modes:
Sync inference (small files, results returned immediately)
Upload a CSV and get results back in one call. Best for small inputs.
wwai infer sync MODEL_ID --file new_data.csv --output-type json
The response body contains the prediction results directly. No job polling needed.
Async file inference (large files)
Upload a file and get a job_id back immediately. Poll for results.
wwai infer async MODEL_ID --file large_data.csv --wait
Without --wait, you poll manually:
JOB_ID=$(wwai infer async MODEL_ID --file large_data.csv | jq -r '.job_id')
wwai jobs wait "$JOB_ID"
wwai jobs results "$JOB_ID"
jobs results returns a signed download URL for the results file:
{
"job_type": "infer_batch",
"inference_results_uri": "https://storage.googleapis.com/...signed-url..."
}
Batch inference (run on an existing dataset)
Reference a dataset already in the system instead of uploading a file. Best for large inputs that are already stored.
wwai infer batch MODEL_ID --dataset DATASET_ID --wait
Same result format as async -- poll the job, then fetch jobs results
for the download URL.
Complete pipeline example
All three phases chained together:
# 1. Upload dataset and capture IDs
UPLOAD=$(wwai datasets create --file train.csv --name "sales-q4")
DATASET=$(echo "$UPLOAD" | jq -r '.dataset.id')
INGEST_JOB=$(echo "$UPLOAD" | jq -r '.job_id')
# Wait for ingestion to finish
wwai jobs wait "$INGEST_JOB"
# 2. Train model (--wait blocks until training succeeds)
TRAIN=$(wwai models train \
--dataset "$DATASET" \
--type prediction \
--label-column revenue \
--wait)
MODEL=$(echo "$TRAIN" | head -1 | jq -r '.model.id')
# 3. Run inference on new data
wwai infer sync "$MODEL" --file new_data.csv --output-type json
Anomaly detection example
Anomaly models don't need a label column. Inference returns anomalous
row indices by default, or per-row scores with --anomaly-format per_row.
# Train
wwai models train --dataset "$DATASET" --type anomaly --wait
# Infer with per-row scores
wwai infer sync MODEL_ID --file transactions.csv --anomaly-format per_row --output-type json
Retraining a model
Create a new version of an existing model with fresh data. Reuses the original config (type, label column, etc.):
wwai models retrain MODEL_ID --dataset NEW_DATASET_ID --wait
Job exit codes
All --wait flags and wwai jobs wait use these exit codes:
| Code | Meaning |
|---|---|
0 |
Job succeeded |
1 |
Job failed, canceled, or rejected |
2 |
Timeout (job still running) |
Status updates are printed to stderr; final JSON goes to stdout.
This means you can pipe stdout to jq while still seeing progress.
Model types
| Type | Description | Requires --label-column |
|---|---|---|
prediction |
Supervised classification/regression | Yes |
anomaly |
Anomaly detection | No |
embedding |
Vector embeddings | No |
clustering |
Unsupervised clustering | No |
factors |
Interpretable factor analysis | No |
search |
FAISS nearest-neighbor search | No |
Environment variables
| Variable | Description |
|---|---|
WOODWIDE_API_KEY |
API key (sk_...) |
WOODWIDE_BASE_URL |
API base URL (default: https://api.woodwide.ai) |
Releasing
The CLI is published to PyPI as woodwide-cli
by the .github/workflows/publish-cli.yml workflow, which runs on tag pushes
matching cli-v* and uploads via PyPI trusted publishing (OIDC, no API tokens).
To cut a release:
-
Bump
[project].versioninwwai-cli/pyproject.toml(semver). -
Commit on
main(or merge a PR that does). -
Tag the release commit and push:
git tag cli-v0.1.0 git push origin cli-v0.1.0
The workflow checks that the tag (cli-v<VERSION>) matches the pyproject
version, builds sdist + wheel with uv build, validates with twine check,
and publishes via pypa/gh-action-pypi-publish.
One-time PyPI setup
Before the first publish, a maintainer with PyPI access must register the trusted publisher (no token required):
- Reserve the project on PyPI by uploading once manually, or pre-register a pending publisher at https://pypi.org/manage/account/publishing/.
- Add a GitHub publisher with:
- Owner:
Wood-Wide-AI - Repository:
wwai-main - Workflow:
publish-cli.yml - Environment:
pypi
- Owner:
- In this repo, create a GitHub environment named
pypi(Settings → Environments → New environment). No secrets are needed; optionally require reviewers for the publish step.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file woodwide_cli-0.1.0.tar.gz.
File metadata
- Download URL: woodwide_cli-0.1.0.tar.gz
- Upload date:
- Size: 17.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
049ca97eeba1ff2f565670f9aea979f41cd24ac2080e76667f4b1bc289a595f3
|
|
| MD5 |
b7df6bbc411b91e289149ea73e2facee
|
|
| BLAKE2b-256 |
62beace306083ac4a1f934386138c15e2384f2774384ece0d7deb44c6b967812
|
Provenance
The following attestation bundles were made for woodwide_cli-0.1.0.tar.gz:
Publisher:
publish-cli.yml on Wood-Wide-AI/wwai-main
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
woodwide_cli-0.1.0.tar.gz -
Subject digest:
049ca97eeba1ff2f565670f9aea979f41cd24ac2080e76667f4b1bc289a595f3 - Sigstore transparency entry: 1571643935
- Sigstore integration time:
-
Permalink:
Wood-Wide-AI/wwai-main@59af061ee79b1a4fc39f4c718eeb0c910f8654ca -
Branch / Tag:
refs/tags/cli-v0.1.0 - Owner: https://github.com/Wood-Wide-AI
-
Access:
internal
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-cli.yml@59af061ee79b1a4fc39f4c718eeb0c910f8654ca -
Trigger Event:
push
-
Statement type:
File details
Details for the file woodwide_cli-0.1.0-py3-none-any.whl.
File metadata
- Download URL: woodwide_cli-0.1.0-py3-none-any.whl
- Upload date:
- Size: 23.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
62d88ac436af71b60d4c63d45ed2aa6493ebb5b49a92ae25648a560cdc268fd5
|
|
| MD5 |
508c08efc024c017e8f16d9abb727e09
|
|
| BLAKE2b-256 |
4f4d67836bd575e1050c87d620e0410c1c4019e04f036394b57fe13c8e173560
|
Provenance
The following attestation bundles were made for woodwide_cli-0.1.0-py3-none-any.whl:
Publisher:
publish-cli.yml on Wood-Wide-AI/wwai-main
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
woodwide_cli-0.1.0-py3-none-any.whl -
Subject digest:
62d88ac436af71b60d4c63d45ed2aa6493ebb5b49a92ae25648a560cdc268fd5 - Sigstore transparency entry: 1571643998
- Sigstore integration time:
-
Permalink:
Wood-Wide-AI/wwai-main@59af061ee79b1a4fc39f4c718eeb0c910f8654ca -
Branch / Tag:
refs/tags/cli-v0.1.0 - Owner: https://github.com/Wood-Wide-AI
-
Access:
internal
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-cli.yml@59af061ee79b1a4fc39f4c718eeb0c910f8654ca -
Trigger Event:
push
-
Statement type: