About ado-axi
ado-axi is an agent-oriented CLI for Azure DevOps, with profiles for organization, project, and authentication settings. It covers work items, pull requests, pipelines, tests, repositories, and a raw REST API bridge.
Key features
- 01Multiple organization profiles
- 02Work item and pull request management
- 03Pipeline runs, logs, and monitoring
- 04Test results and repository operations
- 05Raw Azure DevOps REST API bridge
Use cases
- 01Review and update work items safely
- 02Inspect PR discussions and checks
- 03Run or diagnose build pipelines
- 04Access Azure DevOps REST endpoints without a dedicated command
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ jeffreyhaen/ ado-axi --skill ado-axiAfter installing, type/ado-axiin Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
.nvmrc.gitignoreLICENSEBENCHMARK.mdREADME.mdCHANGELOG.mdpnpm-workspace.yamlpackage.jsonpnpm-lock.yaml.github/workflows/ci.ymlrelease.ymlbenchmark/scenarios.mjstargets.example.jsontool-surface.jsonscripts/release-notes.mjsscripts/benchmark/tokens.mjscapture.mjsbench.mjscapture-surface.mjsfetch-hook.mjsscrub.mjssrc/bin/ado-axi.tssrc/commands/doctor.tshome.tsconfig.tsapi.tsrepo.tsref.tspipeline.tspr.tsDetails
From the project READMEado-axi
Agent-ergonomic CLI over the Azure DevOps REST API. Multiple organizations are handled with profiles; each profile carries its own org, project, and authentication (Azure CLI login or a personal access token).
Install globally for normal use with npm install -g @jeffreyhaen/ado-axi. If ado-axi is not on PATH, prefix commands with npx -y @jeffreyhaen/ado-axi.
Orientation
Run ado-axi with no arguments first. It prints the active profile plus your open work items,
project-active pull requests (active-pull-requests), and recent pipeline runs.
ado-axi # dashboard
ado-axi config list # configured profiles
ado-axi doctor # authentication check per profile
ado-axi project list # projects (30 most recently updated; --name <filter>, --limit N)
Selecting org, project, and profile
Every command accepts these, and they never count as unknown flags:
--profile <name>— a configured profile (ado-axi config list); may also be written before the command (ado-axi --profile acme pr list), including on the bare dashboard--org <org>/--project <project>— one-off overrides; an--orgthat matches a configured profile inherits that profile's authentication. Organization-root URLs (https://dev.azure.com/<org>orhttps://<org>.visualstudio.com) also work; no project/API path$ADO_AXI_ORG/$ADO_AXI_PROJECT— environment overrides
For pasted PR web URLs, extract org, project, repo, and id and pass them explicitly.
Establish org/project from the task or a project-specific profile and reuse them for the session.
If project context is missing, use ado-axi project list --org <org>; ask the user if the intended
project remains unclear. Never select a project arbitrarily, especially for mutations.
Work items
ado-axi work-item list [--state open|all|<State>] [--type <type>] [--assigned-to @me|<name>]
[--iteration @current|<path>] [--area <path>] [--tag <tag>] [--search <text>]
[--query "<raw WIQL>"] [--limit 30]
ado-axi work-item get <id> [--comments] [--full] # includes `rev` for compare-and-swap
ado-axi work-item create --type Task --title "..." [--description "..."] [--description-format markdown|html]
[--assigned-to <user>] [--parent <id>] [--area <path>] [--iteration <path>] [--tags "a; b"]
ado-axi work-item update <id> [--state <state>] [--title "..."] [--assigned-to <user>]
[--description "..."] [--description-format markdown|html]
[--add-tags a,b] [--remove-tags c] [--if-rev <n>]
[--set '{"Microsoft.VSTS.Common.Priority": 1}']
ado-axi work-item comment <id> [--body "..."] [--format markdown|html]
ado-axi work-item link list <id> [--limit 50]
ado-axi work-item link add <id> (--parent <id> | --child <id> | --related <id> | --pr <id>
| --commit <40-hex> --repo <name> | --branch <name> --repo <name>)
[--comment "..."] [--if-rev <n>]
link list resolves hierarchy links to work item ids and artifact links to pull request ids,
short commit SHAs, and branch names. link add builds the vstfs:// artifact URI for you — pass
the pull request id, not a URL — and treats an already-present link as a no-op.
list builds WIQL for you; drop to --query for anything the flags do not express.
--description-format markdown renders a Markdown description; use html only when supplying HTML. The format is only applied when a description is supplied.
work-item comment stores comments as Markdown by default; use --format html only when supplying raw HTML. The comments API requires 7.1-preview.4 or later for this format selection.
update is idempotent — setting a field to its current value reports a no-op and exits 0.
Safe concurrent updates
--if-rev <n> turns an update into a compare-and-swap: the patch carries a JSON-Patch
{"op":"test","path":"/rev"}, so the write either applies to exactly that revision or fails with
PRECONDITION_FAILED — never a silent double-claim. Read rev from work-item get.
--if-rev also disables the idempotent no-op skip, so the intended fields are always written.
--add-tags / --remove-tags mutate the tag list in place (case-insensitive, deduplicated)
instead of replacing System.Tags, so unrelated tags survive. They cannot be combined with
--tags, which replaces the whole string.
ado-axi work-item get 4211 # read `rev` from the output
ado-axi work-item update 4211 --assigned-to [email protected] --add-tags agent-claimed --if-rev 7
Pull requests
ado-axi pr list [--repo <repo>] [--status active|draft|completed|abandoned|all] [--creator @me]
[--reviewer @me] [--target <branch>] [--limit 30]
ado-axi pr get <id> [--threads] [--full] # --full = complete description AND comment text
ado-axi pr comments <id> [--full] # alias for `pr get <id> --threads`
ado-axi pr create --repo <repo> --source <branch> [--target main] --title "..." [--description "..."]
[--reviewers a,b] [--draft] [--work-items 1,2]
ado-axi pr update <id> [--title "..."] [--description "..."] [--draft true|false]
[--auto-complete true|false]
ado-axi pr complete <id> [--squash true|false] [--delete-source-branch true|false]
ado-axi pr abandon <id>
ado-axi pr checks <id> [--limit 10] [--full]
ado-axi pr diff <id> [--limit 20] [--full]
ado-axi pr reviewer list <id>
ado-axi pr reviewer add|remove <id> --reviewer <identity> [--required]
ado-axi pr approve <id> [--vote approve|approve-with-suggestions|wait-for-author|reject|reset]
ado-axi pr comment <id> [--body "..."] [--file <path> --line <n>] [--thread <id>]
ado-axi pr thread list <id> [--limit 20] [--full]
ado-axi pr thread reply <id> --thread <n> [--body "..."] [--resolve]
ado-axi pr thread resolve|reopen <id> --thread <n> [--status active|fixed|wont-fix|closed|by-design|pending]
Finish review feedback with pr thread: list gives thread ids plus an unresolved count,
reply --resolve answers and closes a thread in one call, and resolve/reopen report an
already-set status as a no-op.
Safe shell input
For Markdown or multiline comment content, pipe a quoted heredoc to stdin for
work-item comment, pr comment, and pr thread reply; omit --body:
ado-axi pr thread reply 812 --thread 5 --resolve <<'EOF'
Fixed in `3f2a1c9`: `$value` is now validated.
EOF
Never double-quote a flag value containing backticks, $, !, or quotes. Git Bash expands these
before ado-axi starts, so the CLI receives valid but mangled input and cannot detect it. The
same applies to --title, --description, --set, --variables, --parameters, and --query:
use stdin where the command supports it, or pipe a complete JSON payload to ado-axi api.
pr list shows a review tally (2/3 approved) so no follow-up call is needed to judge status.
Work-item and PR descriptions may be piped when --description is omitted. pr update and reviewer
mutations report safely detected retries as no-ops. pr complete uses the current source commit, never bypasses policy, and treats
an already completed PR as a no-op. pr abandon treats an already abandoned PR as a no-op. Run pr checks before completion to see concise policy/status
counts; use --full only when the bounded actionable list is insufficient.
Git Bash repository paths
On Windows, Git Bash converts repository paths beginning with / even when quoted. Prefix inline
comment commands with MSYS_NO_PATHCONV=1 so --file reaches Azure DevOps unchanged.
Example:
MSYS_NO_PATHCONV=1 ado-axi pr comment 812 --file '/src/Project/File.cs' --line 10 --body '...'
Without the prefix, the CLI restores paths converted by Git for Windows. It rejects other Windows
paths, and paths under /bin or /usr/bin, before creating a thread.
Pipelines
ado-axi pipeline list [--name <filter>]
ado-axi pipeline runs [--pipeline <id>] [--branch <branch>] [--result failed] [--limit 20]
ado-axi pipeline run --pipeline <id> [--branch <branch>] [--variables '{"k":"v"}']
ado-axi pipeline logs <run-id> [--log <log-id>] [--tail 120] [--full] [--failed-only]
ado-axi pipeline timeline <run-id> [--limit 20] [--full]
ado-axi pipeline watch <run-id> [--interval 10] [--timeout 1800]
watch uses seconds, refuses intervals below 2 seconds, and enforces its deadline across
authentication, HTTP requests, and response bodies (30 minutes by default). Failed, cancelled,
timed-out, and unexpected outcomes exit non-zero with TOON output.
logs returns the tail of the last log by default — pass --log <id> for a specific step.
When a run failed, start with timeline: it names the failing stage/job/step, includes the first
error issue, and gives the log id to read. logs --failed-only goes straight to that step's log.
Tests
ado-axi test results <run-id> [--outcome failed|passed|aborted|not-executed|all] [--limit 20] [--full]
ado-axi test results --run <test-run-id>
<run-id> is the pipeline run id. All pages of published test runs contribute to totals;
result counts match --outcome. --limit bounds displayed results, not totals. --full expands
error messages without increasing that limit. When a build is red, test results usually answers
what broke and pipeline logs --failed-only why.
Repositories
ado-axi repo list [--name <filter>]
ado-axi repo branches --repo <name> [--name <filter>]
ado-axi repo file <path> --repo <name> [--ref <branch> | --commit <40-hex>] [--limit <lines>] [--full]
ado-axi ref list --repo <name> [--name <prefix>] [--limit 50] [--full]
ado-axi ref create --repo <name> --name <branch> (--source <branch> | --source-object-id <40-hex>)
ado-axi ref delete --repo <name> --name <branch> [--old-object-id <40-hex>]
repo file reads a single file straight from Azure DevOps: the default branch, a branch tip
(--ref), or an exact revision (--commit). Use it for files outside the working copy — another
repository, or the target-branch version of a file under review. Folders and binaries are refused,
and paths follow the same /src/Project/File.cs form as pr comment --file.
Ref creation never overwrites an existing branch. Deletion resolves the exact branch and uses its
current object ID as the Azure DevOps concurrency guard; --old-object-id additionally asserts a
previously observed version. Existing-at-the-intended-object and already-absent requests are no-ops.
Escape hatch
Anything without a dedicated command — wikis, test plans, code search, artifacts, security — goes through the raw REST bridge:
ado-axi api _apis/wiki/wikis
ado-axi api _apis/testplan/plans --query 'filterActivePlans=true'
ado-axi api POST _apis/search/codesearchresults --host almsearch --body '{"searchText":"TODO"}'
cat payload.bin | ado-axi api POST _apis/wit/attachments --query 'fileName=payload.bin' --content-type application/octet-stream
ado-axi api _apis/projects --no-project # organization-level path
ado-axi api 'https://vsrm.dev.azure.com/acme/Platform/_apis/release/releases?api-version=7.1'
ado-axi api PATCH _apis/wit/workitems/4211 --content-type json-patch \
--body '[{"op":"test","path":"/rev","value":7},{"op":"add","path":"/fields/System.State","value":"Active"}]'
Relative paths use https://dev.azure.com/<org>/<project>/; --host selects
dev (default), vsrm, vssps, or almsearch. Full HTTPS REST URLs on those four hosts also
work: URL org/project/host/query replace default context and use matching profile authentication.
Conflicting flags or a --profile from another org are rejected; do not override URL context.
Quote URLs with query parameters. When --body is omitted and stdin is piped,
stdin is sent unchanged as the request body. --content-type accepts the shorthands
json (default), json-patch, merge-patch, text, or any media type — work item writes
require json-patch.
Conventions
- In ADO descriptions/comments,
#123references a work item,!123an Azure DevOps PR; for GitHub PRs use the full URL, never bare#123or!123, even when Boards/pipelines run in ADO. - Output is TOON on stdout; errors are TOON too, with a
helplist of next steps. - Exit codes: 0 success (including no-ops), 1 runtime error, 2 usage error.
- Unknown flags are rejected by name — read the
helpline and retry once. - Lists take
--limitand--fields a,b; detail views truncate and take--full. - On Windows/Git Bash, never pass large or multiline content through a
.cmdshim as an interpolated CLI argument such as--description "$(cat file)";cmd.execan truncate it. Pipe it instead:cat file | ado-axi work-item update <id>orcat file | ado-axi api POST <path> --content-type <media-type>. - Mutating commands (
create,update,complete, reviewer add/remove, ref create/delete,comment,approve,pipeline run) change real state — only run them when the user asked. - Never use PR completion to bypass policy and never delete a ref whose exact target is ambiguous.