Windrunner CLI
The Windrunner CLI provides a scriptable interface to the versioned REST API. It is useful for local workflows, automation, and agents that need to read or update project work without writing HTTP requests directly.
Install
The public npm package is @shzlwio/windrunner-cli.
It requires Node.js 20 or newer.
npm install -g @shzlwio/windrunner-cli
windrunner --help
The npm package name is scoped, but the installed command is windrunner.
Configure authentication
Create an API key from the Account page, then export the server URL and key in your shell. Do not pass the API key as a command-line argument, because command arguments may be stored in shell history or exposed to other local processes.
export WINDRUNNER_URL=http://localhost:8066
export WINDRUNNER_API_KEY=wr_k_...
WINDRUNNER_URL defaults to http://localhost:8080 when it is not set. For
the Docker Compose installation, use port 8066 as shown above.
The CLI uses the same Bearer API-key authentication and project-level access rules as the REST API. The key must have the scope required by the command:
| Command | Required scope |
|---|---|
projects list, projects get | projects:read |
projects create, projects update, projects delete | projects:write |
projects members list, projects teams list | project_access:read |
projects members add/remove, projects teams add/remove | project_access:write |
projects reorder | work_items:write and entries:write |
work-items list, work-items get | work_items:read |
work-items create | work_items:write |
work-items update | work_items:read and work_items:write |
work-items move, work-items delete | work_items:write |
entries list, entries get | entries:read |
entries create | entries:write |
entries update, entries delete | entries:write |
relationships list | relationships:read |
relationships create, relationships update-reason, relationships delete | relationships:write |
teams list, teams get, teams members list | teams:read or team_members:read |
teams create/update/delete, teams members add/remove | teams:write or team_members:write |
teams projects | team_projects:read |
users get | users:read |
audit-logs list, audit-logs project | audit_logs:read |
search | work_items:read, entries:read, and relationships:read |
The update command reads the current work item before sending the update so fields that were not specified are preserved. That is why it needs both read and write scopes.
Commands
Projects
windrunner projects list --json
windrunner projects get PROJECT_ID --json
windrunner projects create \
--name "Platform work" \
--owner-user USER_ID
windrunner projects update PROJECT_ID --name "Updated project"
windrunner projects delete PROJECT_ID --yes
windrunner projects members list PROJECT_ID --json
windrunner projects members add PROJECT_ID --user-id USER_ID --role EDITOR
windrunner projects teams add PROJECT_ID --team-id TEAM_ID --role VIEWER
windrunner projects reorder PROJECT_ID \
--item WORK_ITEM:item-1 --item ENTRY:entry-1
Project creation requires at least one --owner-user or --owner-team. Repeat
either option to provide multiple owners. Repeat --item for reordering in
the desired order; use --parent-id to target a child work-item stream.
Work items
windrunner work-items list PROJECT_ID --status OPEN --json
windrunner work-items create PROJECT_ID \
--title "Fix login" \
--type TASK \
--status OPEN
windrunner work-items update WORK_ITEM_ID \
--title "Fix login and add regression coverage" \
--status IN_PROGRESS
windrunner work-items move WORK_ITEM_ID --parent-id PARENT_ID --before ENTRY:entry-1
windrunner work-items delete WORK_ITEM_ID --yes
Use --assignee USER:<id> or --assignee TEAM:<id> to assign work. Repeat
--assignee to provide multiple assignments:
windrunner work-items create PROJECT_ID \
--title "Prepare release" \
--assignee USER:user-1 \
--assignee TEAM:team-1
Entries
windrunner entries list WORK_ITEM_ID --json
windrunner entries create WORK_ITEM_ID --body "Deployment completed"
windrunner entries get ENTRY_ID --json
windrunner entries update ENTRY_ID --body "Updated context" --type EVIDENCE
windrunner entries delete ENTRY_ID --yes
Relationships
windrunner relationships list PROJECT_ID --type BLOCKED_BY --json
windrunner relationships create PROJECT_ID \
--from WORK_ITEM:item-1 \
--to WORK_ITEM:item-2 \
--type BLOCKED_BY \
--reason "Waiting on the database migration"
windrunner relationships update-reason RELATIONSHIP_ID --reason "Resolved"
windrunner relationships delete RELATIONSHIP_ID --yes
Teams and users
windrunner teams list --json
windrunner teams create --name "Platform" --owner-user USER_ID
windrunner teams update TEAM_ID --name "Platform engineering" --description "Owns platform services"
windrunner teams members list TEAM_ID --json
windrunner teams members add TEAM_ID --user-id USER_ID --role TEAM_MEMBER
windrunner teams projects TEAM_ID --json
windrunner users get USER_ID --json
Audit logs
windrunner audit-logs list --json
windrunner audit-logs project PROJECT_ID --json
Search
windrunner search PROJECT_ID "login failure" --limit 20 --json
Search returns matching work items, entries, and relationships from the project.
Global options
| Option | Description |
|---|---|
--url <url> | Override WINDRUNNER_URL |
--json | Print compact machine-readable JSON |
--dry-run | Preview a mutation without sending it |
-y, --yes | Skip destructive-operation confirmation prompts |
Normal output is pretty JSON. Use --json when another script or agent will
parse the result.
Use --dry-run before creating, updating, or deleting data:
windrunner work-items create PROJECT_ID \
--title "Review release notes" \
--dry-run --json
Dry runs do not send mutation requests and do not require an API key. Deletes
require confirmation in an interactive terminal; use --yes only when the
delete was explicitly intended. A work-item delete also removes its
descendants, entries, and relationships.
Run windrunner <command> --help for command-specific options and examples.
Run CLI E2E tests
The repository includes Playwright tests that execute the built CLI against an
already-running Windrunner server. Start the server first, then configure
e2e/.env.local with either E2E_API_KEY or E2E_LOGIN and
E2E_PASSWORD.
cd e2e
npm install
npm run test:cli
Set WINDRUNNER_BASE_URL in .env.local when the server is not running at
http://localhost:8066. The test command builds the CLI before running the
tests and does not start or reset the server database.