AI-friendly CLI facade over Whistle.
- Node.js >= 20
whistleinstalled (npm install -g whistle) sow2is available on PATH
# Install from npm (global)
npm i -g whistle-cli --registry=https://registry.npmjs.org/
# Upgrade
npm i -g whistle-cli@latest --registry=https://registry.npmjs.org/
# This repository (dev mode)
npm install
npm run dev -- --help# Check command surface in dev mode
npm run dev -- --help
# Check Whistle availability
npm run dev -- raw w2 status
# Structured JSON output (default)
npm run dev -- --format json instance status
# Human-readable output
npm run dev -- --format pretty instance statusInstall from the public GitHub repository with a compatible skills installer:
skills add https://github.com/maxjchuang/whistle-cli --skill whistle-cliInstall the repository-distributed skill into the default skills directory:
./scripts/install-skill.shwhistle-cli provides three layers of commands:
| Layer | Purpose | Example |
|---|---|---|
| raw | Escape hatch, passthrough to w2 |
whistle-cli raw w2 status |
| resource | Stable resource operations, preferred for agents | whistle-cli rules patch --preview |
| shortcut | High-frequency intent-driven commands | whistle-cli rule set-header --match ... |
instance— start / stop / restart / status / list / selectrules— rollback / patch / import / export / apply / verify / list / get / enable / disablevalues— rollback / list / get / set / remove / import / exportcaptures— find / get / tail / diff / exportcomposer— replay / composeframes— list / sendruntime— serve the optional__whistle_cli__backend APIcerts— status / install / verify / guideproxy— status / set / off / verifyplugins— list / install / uninstall / enable / disable / inspectdoctor— instance-status / proxy-routing / https-captureraw— w2 passthrough
bootstrap—start/preparerule—set-header/map-localcapture—find/find-errorplugin—install/remove/inspect/invoke(invokeis out of scope in v1)
| Flag | Description |
|---|---|
--format <json|pretty|table|ndjson> |
Output format, default json |
--instance <id> |
Target instance, defaults to current |
--non-interactive |
Fail instead of waiting for user action |
--preview, --apply, --verify, and --rollback are command-level flags on mutating resource commands (not global flags).
Common rollback forms:
rules rollback --action-id <id>values rollback --action-id <id>proxy set --rollback <id>plugins install --rollback <id>
All output is a structured JSON envelope designed for machine parsing:
{
"status": "ok | warning | error | blocked",
"resource": "raw | instance | rules | values | captures | composer | frames | runtime | certs | proxy | plugins | doctor",
"action": "w2 status",
"data": {},
"error": {
"code": "INSTANCE_NOT_RUNNING",
"message": "...",
"reason": "...",
"suggested_fix": "..."
},
"next_actions": [{ "action": "...", "reason": "..." }],
"effective": true
}status— success / failure decisionerror.code— stable machine-readable error classificationnext_actions— suggested next steps (agent doesn't need to guess)effective— whether a mutation is actually live at runtime
| Code | Meaning |
|---|---|
INSTANCE_NOT_RUNNING |
Whistle instance is not running |
INSTANCE_PORT_CONFLICT |
Port already in use |
CERT_NOT_INSTALLED |
CA certificate not installed |
CERT_NOT_TRUSTED |
CA certificate not trusted by system |
PROXY_NOT_ACTIVE |
System proxy not pointing to Whistle |
RULE_CONFLICT |
Conflicting rules detected |
RULE_VERIFY_FAILED |
Rule verification failed |
NO_CAPTURE_MATCH |
No captured traffic matched the query |
CAPTURE_BACKEND_UNAVAILABLE |
Capture backend not accessible |
PLUGIN_NOT_INSTALLED |
Plugin not installed |
PLUGIN_CAPABILITY_UNAVAILABLE |
Plugin capability not available |
PERMISSION_REQUIRED |
Insufficient permissions |
USER_ACTION_REQUIRED |
Manual user action needed |
UNSUPPORTED_OPERATION |
Operation not supported |
1. Environment check
whistle-cli --format json instance status
2. Start instance
whistle-cli --format json instance start
3. Safe mutation (preview -> apply -> verify)
whistle-cli rules patch --id main --file ./patch.txt --format json
whistle-cli rules apply --id main --file ./patch.txt --apply --verify --format json
4. Diagnose issues
whistle-cli --format json captures find --host api.example.com
whistle-cli --format json doctor https-capture
5. Handle blocked/error states
-> Read error.suggested_fix and inform user
-> Read next_actions for next step
whistle-cli includes an optional local runtime backend that serves the __whistle_cli__ API consumed by --backend runtime commands.
# Start a backend in front of a running Whistle Web API
whistle-cli --format json runtime serve \
--target-url http://127.0.0.1:8899 \
--host 127.0.0.1 \
--port 8898
# In another shell, route RuntimeClient calls to it
export WHISTLE_CLI_RUNTIME_URL=http://127.0.0.1:8898
whistle-cli --format json captures find --backend runtime --host example.com
whistle-cli --format ndjson captures tail --backend runtime --host example.com --limit 5
whistle-cli --format json composer compose --method GET --url https://example.com --applyThe runtime backend currently adapts capture data from Whistle's Web API and executes compose/replay with local HTTP requests. Frame routes return UNSUPPORTED_OPERATION until frame-level backend support is implemented.
For browser-driven automation, prefer Whistle Web capture retrieval when the capture was detected with --backend whistle-web:
# Wait for a newly triggered request and keep only a redacted summary in the result
whistle-cli --format json captures assert-request \
--backend whistle-web \
--host app.example.com \
--path /api/ \
--timeout 90s \
--poll-interval 2s \
--fields capture_id,method,status_code,path,referer
# Retrieve the exact capture while it is still in the Whistle Web data window
whistle-cli --format json captures get \
--backend whistle-web \
--id <capture_id>
# Extract one request header from the exact capture
whistle-cli --format json captures get-header \
--backend whistle-web \
--id <capture_id> \
--header cookie
# Export filtered Whistle Web captures as JSON
whistle-cli --format json captures export \
--backend whistle-web \
--host app.example.com \
--path /api/ \
--export-format jsonassert-request remains redacted by default for safe agent-facing reporting. Explicit retrieval commands such as get, export, and get-header return captured request header values requested by the user, so avoid logging their output when headers contain credentials.
If direct Whistle Web API fallback is unavoidable, use dumpCount to widen the returned session window, for example: /cgi-bin/get-data?startTime=0&dumpCount=1000.
result = run("whistle-cli rules patch --apply")
if result.status == "error":
match result.error.code:
case "INSTANCE_NOT_RUNNING":
run("whistle-cli instance start")
# retry
case "CERT_NOT_TRUSTED":
tell_user(result.error.suggested_fix)
case "PROXY_NOT_ACTIVE":
run("whistle-cli proxy set")
case _:
tell_user(result.error.message)
elif result.status == "blocked":
tell_user(result.next_actions)
elif result.status == "warning":
log(result.warnings)# Build
npm run build
# Dev mode (tsx)
npm run dev -- raw w2 status
# Built binary
node dist/cli/index.js --help
# Test
npm run test
# Lint
npm run lint| Command | Status |
|---|---|
raw w2 [args] |
Available |
instance/* |
Available |
rules/* |
Available |
values/* |
Available |
captures/* |
Available |
composer/* |
Available |
frames/* |
Available |
runtime serve |
Available |
certs/* |
Available |
proxy/* |
Available |
plugins/* |
Available |
doctor/* |
Available |
shortcuts/* |
Available |
captures diffexists in command surface but currently returnsUNSUPPORTED_OPERATION.captures tailrequires--format ndjson.- Runtime backend frame routes return
UNSUPPORTED_OPERATION; capture and composer runtime routes are implemented. - Certificate trust and some proxy setup steps may return
blockedorUSER_ACTION_REQUIREDand require manual OS actions.
MIT