Skip to main content

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:

  1. Bump [project].version in wwai-cli/pyproject.toml (semver).

  2. Commit on main (or merge a PR that does).

  3. 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):

  1. Reserve the project on PyPI by uploading once manually, or pre-register a pending publisher at https://pypi.org/manage/account/publishing/.
  2. Add a GitHub publisher with:
    • Owner: Wood-Wide-AI
    • Repository: wwai-main
    • Workflow: publish-cli.yml
    • Environment: pypi
  3. 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

woodwide_cli-0.1.0.tar.gz (17.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

woodwide_cli-0.1.0-py3-none-any.whl (23.2 kB view details)

Uploaded Python 3

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

Hashes for woodwide_cli-0.1.0.tar.gz
Algorithm Hash digest
SHA256 049ca97eeba1ff2f565670f9aea979f41cd24ac2080e76667f4b1bc289a595f3
MD5 b7df6bbc411b91e289149ea73e2facee
BLAKE2b-256 62beace306083ac4a1f934386138c15e2384f2774384ece0d7deb44c6b967812

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for woodwide_cli-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 62d88ac436af71b60d4c63d45ed2aa6493ebb5b49a92ae25648a560cdc268fd5
MD5 508c08efc024c017e8f16d9abb727e09
BLAKE2b-256 4f4d67836bd575e1050c87d620e0410c1c4019e04f036394b57fe13c8e173560

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page