The Azure DevOps CLI
shaped like gh, built for agents
ado is a single self-contained binary for macOS, Linux and
Windows that manages Azure DevOps — projects, repositories, work items,
pipelines, pull requests and 19 more service areas — with the command
vocabulary, JSON surface and exit codes that gh taught agents
to expect.
npm install -g @gilbertwong1996/ado --foreground-scripts
Works on macOS, Linux, and Windows. Other install methods →
- Version
- 0.7.0
- Commands
- 150 across 24 service areas
- Binary
- ~5 MiB, no runtime dependency
- Startup
- about 6 ms (measured)
- Platforms
- macOS arm64/x86_64, Linux x86_64/aarch64, Windows x86_64
- License
- Apache-2.0
What it does
One binary covers the Azure DevOps surface a team touches daily, and the
command names are the ones gh uses wherever the concept maps.
24 service areas, 150 commands
Projects, repositories, branches, branch policies, work items and their comments and attachments, pull requests, review comments and reviewers, pipelines, builds, artifacts, variable groups, secure files, releases, packages, wikis, teams, users, areas, iterations, agent pools and queues, service connections, extensions, banners, test results and coverage, search and configuration.
gh's shape, name for name
Singular nouns, gh's verbs, one level deep: ado pr view, ado pr edit, ado work-item list, ado pr-comment add, ado pr merge. The flags transfer too — -R names the repository, -w opens the page, -q and -t format the output, -L caps a list. An agent that knows gh already knows the grammar.
3 auth methods
Personal Access Token, browser OAuth with PKCE, and device code. MSA personal accounts (*.visualstudio.com) are supported, and ado auth token hands the stored credential to git or curl. No az CLI dependency.
Cross-platform
Five native archives — macOS arm64 and x86_64, Linux x86_64 and aarch64 (musl), Windows x86_64 — built on native runners with cargo-dist.
CI/CD friendly
ado ci watch PROJECT BUILD_ID streams build logs in real time and exits 2 when the build is cancelled. Per-run variables, variable groups, PR automation, package publishing.
An escape hatch for the rest
ado api /_apis/anything -X post -f key=value sends one authenticated request to any endpoint, prints the server's body as it arrived, and exits with the server's status.
Why "AI-native"?
Most CLIs are designed for humans and retrofitted for agents with a
--json flag that dumps everything. ado is designed
the other way around: the machine surface is the primary one, and the table
is the convenience.
| Feature | Human-friendly | AI-agent-friendly |
|---|---|---|
| Output | Bordered table on a terminal; tab-separated rows, no header, when piped | Stable JSON envelope on every command |
| Field selection | — | --json=number,title prints only those fields — gh's vocabulary where a catalog maps it, the payload's own keys on every other command |
| Post-processing | Pipe to your own tools | -q/--jq EXPR and -t/--template TPL, compiled in-process |
| Discovery | ado --help at every level |
ado schema --json — the whole tree, 47 groups and 150 leaves, in one round trip |
| Documentation | Embedded help pages | ado skills list / ado skills read NAME --json |
| Errors | One-line [Code] message on stderr |
{ok: false, error: {code, status, message, details}} |
| Exit codes | 0 or 1 | 0 success, 1 failure, 2 cancelled watch, 4 no credential |
| Auth | Browser OAuth (interactive) | PAT, device code, browser — plus ado auth token to hand the credential on |
Field-selected JSON in one command
$ ado pr list Alpha Core --json=number,title
[
{ "number": 137, "title": "Add payment retries" },
{ "number": 138, "title": "Retire the legacy ledger" }
]
$ ado pr list Alpha Core --json -q '.[] | select(.pullRequestId > 137) | .title'
Retire the legacy ledger
Errors that agents can match on
$ ado project view nonexistent --json
{
"ok": false,
"error": {
"code": "not_found",
"message": "Resource not found. Check the project/repo/build ID and your permissions.",
"status": 404,
"details": { "body": "..." }
}
}
Every error carries a stable code from a set of ten:
auth_required, not_logged_in,
not_found, forbidden, conflict,
validation_error, api_error,
network_error, cancelled, unknown.
status and details appear only when the error has
them. An agent matches on error.code and the exit status, never
on English text.
ado vs the official az devops
Both talk to the same REST API. They are built for different things: the
Azure CLI is Microsoft's supported, complete client for every Azure
service; ado is a small, fast, agent-shaped client for Azure
DevOps alone. Neither wins outright.
| Dimension | ado | az devops (official) |
|---|---|---|
| Install | One ~5 MiB binary via npm or a release archive; no runtime | Python plus the Azure CLI package; installed by a system package manager, installer or pip |
| Startup | About 6 ms | Python interpreter start-up, then the CLI's own imports — noticeably longer for a one-off command |
| Command shape | ado <noun> <verb>, one level, gh's vocabulary |
az devops <area> <verb> and siblings such as az boards, az pipelines, az repos |
| Machine output | Envelope on every command, field selection, --jq, --template, TSV when piped |
--output json|table|tsv; no field selection and no in-process jq |
| Discovery for agents | ado schema --json dumps the command tree; embedded skills install into five agent directories |
az find and --help; no machine-readable command tree of this kind |
| Errors | Stable error.code plus exit 4 for "no credential" |
Human-readable messages; scripts parse text |
| Coverage | 150 commands over 24 Azure DevOps areas, plus ado api for anything unmodelled |
Every Azure DevOps API, and every other Azure service besides |
| Sign-in | PAT, browser OAuth, device code | PAT, browser, service principal and managed identity |
| Support | One maintainer, Apache-2.0, community issues | Microsoft-supported, with a support plan and an extension ecosystem |
Choose ado when…
- The caller is a script or an LLM agent: field-selected JSON, in-process
jq, TSV and exit 4 are there without extra glue. - You want a single binary on a CI runner — no Python, no
azinstall step, about 6 ms to first output. - The caller already knows
gh: the verbs and nouns transfer. - You need one endpoint the CLI does not model:
ado apiprints the server's answer verbatim.
Choose az devops when…
- You need service-principal or managed-identity sign-in.
adodoes not offer it. - You need the long tail of Azure DevOps APIs, or any other Azure service in the same script.
- You want a vendor-supported tool with a support contract.
- Your scripts already call
azand work; there is no reason to port them.
Running both is normal: ado never reads or writes
az's credentials, so the two coexist on one machine without
interfering.
For LLM agents
The binary carries three skills — ado-cli,
ado-auth and ado-ci — that teach an agent how to
use it. Install them once and the agent loads them at startup, with no
shell-out to discover the surface.
$ ado skills install
Installing 3 skills to 4 target(s):
- claude: ~/.claude/skills
- codex: ~/.codex/skills
- cursor: ~/.cursor/skills
- pi: ~/.pi/agent/skills
Note: copilot installs per-repo (to <repo>/.github/ado-cli/).
Installed: 12
Skipped: 0
Errors: 0
$ ls ~/.pi/agent/skills
ado-cli/ ado-auth/ ado-ci/
What the skills teach
ado-cli
The command reference for all 24 service areas, plus the output contract: field selection, --jq, Go templates, TSV, exit codes. The big one — load it when the agent first meets ado.
ado-auth
Every sign-in path — PAT, browser OAuth, device code — the resolution order, and what to do with exit 4. No az dependency.
ado-ci
CI/CD patterns: trigger pipelines, manage variable groups, automate PRs, publish packages, and branch on the exit codes a pipeline cares about.
Or — discover dynamically
An agent that installs nothing can still read the whole surface in one call:
$ ado schema --json | jq '.schema.subcommands | length'
47
$ ado schema "pr list" --json | jq -c '.schema.jsonFields[:5]'
["number","id","title","state","author"]
Other install methods
Prefer a single binary over npm? Download the one that matches your platform from the latest release, or build from source.
📥 Download binary
Grab the archive for your platform and put the binary on your $PATH.
curl -L -o ado.tar.gz https://github.com/gilbertwong96/ado_cli/releases/latest/download/ado-aarch64-apple-darwin.tar.gz
tar -xzf ado.tar.gz ado-aarch64-apple-darwin/ado
chmod +x ado-aarch64-apple-darwin/ado && sudo mv ado-aarch64-apple-darwin/ado /usr/local/bin/
Replace ado-aarch64-apple-darwin.tar.gz with the archive for your platform (see the release page).
🔨 Build from source
Requires Rust 1.98+. Use this if you want to hack on ado itself.
git clone https://github.com/gilbertwong96/ado_cli && cd ado_cli
cargo build --release --locked
cp target/release/ado /usr/local/bin/
Quick start
# 1. Authenticate (pick one)
ado auth login # browser OAuth, org auto-detected
ado auth login --method pat --org myorg --pat TOKEN # Personal Access Token
ado auth login --method device # no browser needed
# 2. Set the default organization once
ado config set default_org myorg
# 3. List projects
ado project list
# 4. Machine-readable output for a script or an agent
ado project list --json=name,state
ado pr list myorg myrepo -q '.[].title'
# 5. Create a work item
ado work-item create myproject --type Bug --title "Fix login page"
# 6. Name the repository once, gh-style
ado pr list -R myproject/myrepo
# 7. Search work items, code or wiki pages
ado search code "retry backoff" --project myproject
# 8. Open the page a command is about, instead of printing it
ado pr view -R myproject/myrepo 137 --web
# 9. Watch a pipeline run in real time
ado ci watch myproject 12345
# 10. Anything the CLI does not model
ado api "/myproject/_apis/git/repositories?api-version=7.1" -i
# 11. Install skills to your LLM agent
ado skills install --target pi