agentsclimarketplace

Ado

Skill pszypowicz/claude-skills/plugins/ado/skills/ado

A small Claude Code marketplace: ado, swift-concurrency, modern-swift, go-dev, worktrees.

Install
npx -y skills add pszypowicz/claude-skills --skill ado

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Azure DevOps operations - PRs, pipelines, policies, builds, variable groups, environments, feeds, branches, work items, comments. This skill should be used when the user asks to "create a PR", "list pipelines", "run a pipeline", "check build status", "debug failed pipeline", "create a policy", "add reviewers", "create a work item", "update a task", "list environments", "approve a pipeline", "manage variable groups", "delete a branch", "comment on a PR", "review PR comments", "comment on work items", "resolve PR thread", "code suggestion", or mentions Azure DevOps, ADO, or az devops CLI. Uses az CLI with PAT auth, falling back to az login tokens.

SKILL.md

33.7 KB, ~9.4k tokens by cl100k_base, as published. Nobody here has run it

Azure DevOps Operations

Use az CLI commands for most operations and bash scripts for complex multi-step orchestration.

Authentication

Credentials come from environment variables exported in the terminal before the session starts; they are inherited read-only. This skill only reads them - it never exports or mutates session credentials. Two shapes are supported:

  • Single org (default): the plain triple ADO_ORG, ADO_PROJECT, AZURE_DEVOPS_EXT_PAT. Commands use these directly.
  • Named profiles: one namespaced triple per alias <X> - <X>_ADO_ORG, <X>_ADO_PROJECT, <X>_ADO_PAT (e.g. WORK_ADO_ORG, PERSONAL_ADO_ORG). Any number can be loaded at once; the set of *_ADO_ORG vars is the profile registry.

When no PAT is exported in either shape, an az login session can stand in for it - see "az CLI token fallback" below.

Check what is available:

echo "ORG=${ADO_ORG:-MISSING} PROJECT=${ADO_PROJECT:-MISSING} PAT=${AZURE_DEVOPS_EXT_PAT:+set} TOKEN=${ADO_TOKEN:+set}"
env | grep -o '^[A-Za-z0-9_]*_ADO_ORG' | sort   # named profiles, if any
az account show --query user.name -o tsv 2>/dev/null || echo "az: not logged in"

Selecting a profile

With the plain triple (single org), run commands as-is - $ADO_ORG / $ADO_PROJECT / $AZURE_DEVOPS_EXT_PAT are already set.

With named profiles, source the helper and bind one. It resolves an alias in this order: an explicit name, then $ADO_PROFILE, then the working directory (a clone under .../dev.azure.com/<org>/...), then the sole profile; if it cannot decide it lists the profiles and fails - ask the user which to use.

source "${CLAUDE_SKILL_DIR}/scripts/lib/ado-profile.sh"

eval "$(ado_env auto)"     # bind the whole block to the auto-detected profile...
eval "$(ado_env WORK)"     # ...or to a named one; then use $ADO_ORG etc. as normal
ado_with WORK 'az repos pr list --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false'   # ...or run one command
ado_profile                # print which alias auto-detect would choose (empty => plain triple)

ado_env / ado_with bind the generic triple only transiently (the current block, or that single command); nothing persists past it, and the wrapper scripts under scripts/ resolve the same way. Pass an ado_with command as a single-quoted string so $ADO_ORG expands after binding.

Working across profiles (source -> destination)

Every loaded profile is available at once, so a migration-style task reads from one and writes to another - address each side explicitly (one block cannot bind two orgs):

source "${CLAUDE_SKILL_DIR}/scripts/lib/ado-profile.sh"
ado_with SRC 'az boards work-item show --id <ID> --org "$ADO_ORG" --detect false -o json'                    # read from SRC
ado_with DST 'az boards work-item create --title "..." --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false'    # write to DST

For raw REST, interpolate the namespaced vars directly: "${SRC_ADO_ORG}/..." with -u ":$SRC_ADO_PAT" for the source, "${DST_ADO_ORG}/..." with -u ":$DST_ADO_PAT" for the destination.

az CLI token fallback (no PAT exported)

Once org and project are known, auth resolves in this order (mirrors scripts/lib/ado-client.sh, which the bundled scripts use automatically):

  1. AZURE_DEVOPS_EXT_PAT - PAT. The az CLI picks it up automatically; curl uses Basic auth.
  2. ADO_TOKEN - pre-minted Entra access token; curl uses Bearer auth.
  3. az CLI login - no credential env vars needed, requires a prior az login. The az devops/az repos/az pipelines/az boards commands authenticate with the signed-in account on their own; only ADO_ORG and ADO_PROJECT are still required. For curl, mint a token for the Azure DevOps resource (499b84ac-1321-427f-aa17-267ca6975798 - fixed public GUID, same for every tenant).

az-minted tokens expire after about an hour. On an unexpected 401 (or an HTML sign-in page in a response body) mid-session, re-mint the token and rebuild AUTH before suspecting a permissions problem. The Bearer token also works against the vssps.dev.azure.com and feeds.dev.azure.com hosts.

If ADO_ORG or ADO_PROJECT is missing, derive them from the repo remote when possible (git remote get-url origin; HTTPS remotes look like https://dev.azure.com/<org>/<project>/_git/<repo>, SSH like [email protected]:v3/<org>/<project>/<repo>) and set them for the commands you run.

REST auth header

Set AUTH once from whichever source is available - the curl snippets in this skill pass -H "$AUTH" and work with either form:

if [[ -n "${AZURE_DEVOPS_EXT_PAT:-}" ]]; then
  AUTH="Authorization: Basic $(printf ':%s' "$AZURE_DEVOPS_EXT_PAT" | base64 | tr -d '\n')"
else
  AUTH="Authorization: Bearer ${ADO_TOKEN:-$(az account get-access-token --resource 499b84ac-1321-427f-aa17-267ca6975798 --query accessToken -o tsv)}"
fi

Stop and instruct the user only when no auth source works (no PAT in either shape, no ADO_TOKEN, and az account show fails):

Either run az login in your terminal, or set the following (outside Claude Code) and start a new session:

export ADO_ORG=https://dev.azure.com/<org>
export ADO_PROJECT=<project>
export AZURE_DEVOPS_EXT_PAT=<pat>

Prefer the az CLI; fall back to curl -H "$AUTH" for REST endpoints that az doesn't cover (az rest is ARM-only and does not work against ADO APIs).

All az commands use --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false.

Exception: These subcommands are org-scoped - they take --org but not --project:

  • az boards work-item show, update, relation add
  • az repos pr show, update, set-vote
  • az repos pr work-item add
  • az repos pr reviewer add
  • az repos pr policy list
  • az repos pr policy queue

Only az boards work-item create and az boards query accept --project.

PR Operations

# List PRs
az repos pr list -r <repo> --status active --top N --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false

# Show PR details (org-scoped - no --project)
az repos pr show --id <ID> --org "$ADO_ORG" --detect false

# Show PR policy evaluations
az repos pr policy list --id <ID> --org "$ADO_ORG" --detect false

# Create PR
az repos pr create -r <repo> -s <branch> --title "text" \
  --auto-complete true --squash true --delete-source-branch true \
  --required-reviewers [email protected] [email protected] \
  --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false

# Update PR
az repos pr update --id <ID> --title "new" --description "new" \
  --auto-complete true --squash true \
  --org "$ADO_ORG" --detect false

# Complete/merge PR
az repos pr update --id <ID> --status completed --squash true \
  --delete-source-branch true --bypass-policy true \
  --org "$ADO_ORG" --detect false

# Abandon PR
az repos pr update --id <ID> --status abandoned --org "$ADO_ORG" --detect false

# Vote on PR
az repos pr set-vote --id <ID> --vote approve --org "$ADO_ORG" --detect false

# Add reviewers (optional or required)
# NOTE: az repos pr reviewer add fails under PAT auth with "A valid reviewer must
# be supplied." regardless of input format (email, entitlement GUID, identity GUID).
# Use REST PUT with an identity GUID resolved from vssps - see "Reviewer identity
# resolution" below.
az repos pr reviewer add --id <ID> --reviewers <GUID1> <GUID2> --required true \
  --org "$ADO_ORG" --detect false

# Link work item to PR
az repos pr work-item add --id <PR_ID> --work-items <WI_ID> \
  --org "$ADO_ORG" --detect false

# Requeue failed BVP
az repos pr policy list --id <ID> -o json --org "$ADO_ORG" --detect false  # find failed evaluation IDs
az repos pr policy queue --id <ID> -e <eval-id> --org "$ADO_ORG" --detect false

Reviewer identity resolution

Adding PR reviewers under PAT auth requires the vssps identity id, not the entitlement id returned by az devops user list. They are different GUIDs for the same user, and only the vssps one works. az repos pr reviewer add fails for both, so use REST:

# AUTH as set in the Authentication section (Basic PAT or az Bearer token)
VSSPS="${ADO_ORG/dev.azure.com/vssps.dev.azure.com}"
REPO_ID=$(az repos show -r <repo> --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false --query id -o tsv)

# 1. Resolve identity id from email
REVIEWER_ID=$(curl -sS -H "$AUTH" \
  "${VSSPS}/_apis/identities?searchFilter=General&filterValue=<email>&api-version=7.1" \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['value'][0]['id'])")

# 2. Add as required reviewer
curl -sS -X PUT -H "$AUTH" -H "Content-Type: application/json" \
  "${ADO_ORG}/_apis/git/repositories/${REPO_ID}/pullRequests/<PR_ID>/reviewers/${REVIEWER_ID}?api-version=7.1" \
  -d "{\"vote\":0,\"isRequired\":true,\"id\":\"${REVIEWER_ID}\"}"

If the PUT response body comes back empty (no displayName, no error), the id was wrong - re-resolve via vssps instead of retrying with the same value. az devops user list ids silently fail this way.

PR Comments & Threads

All PR comment operations require curl with $AUTH (az rest does not work with ADO APIs).

# AUTH as set in the Authentication section (Basic PAT or az Bearer token)
THREADS="${ADO_ORG}/${ADO_PROJECT}/_apis/git/repositories/<repo>/pullRequests/<prId>/threads"

# List active threads (script - handles filtering + formatting)
${CLAUDE_SKILL_DIR}/scripts/ado-pr-threads.sh --pr-id <ID> --repo <repo> --status active

# List threads on a specific file
${CLAUDE_SKILL_DIR}/scripts/ado-pr-threads.sh --pr-id <ID> --repo <repo> --file "/src/main.tf"

# Create general comment
curl -s -H "$AUTH" -H "Content-Type: application/json" -X POST \
  "${THREADS}?api-version=7.1" \
  -d '{"comments":[{"content":"LGTM, one question about error handling.","commentType":1}],"status":"active"}'

# Create file-level comment
curl -s -H "$AUTH" -H "Content-Type: application/json" -X POST \
  "${THREADS}?api-version=7.1" \
  -d '{"comments":[{"content":"Should use a data source here.","commentType":1}],"status":"active","threadContext":{"filePath":"/src/main.tf","rightFileStart":{"line":42,"offset":1},"rightFileEnd":{"line":42,"offset":1}}}'

# Code suggestion (uses ```suggestion block - ADO renders as applicable diff)
curl -s -H "$AUTH" -H "Content-Type: application/json" -X POST \
  "${THREADS}?api-version=7.1" \
  -d '{"comments":[{"content":"Consider:\n\n```suggestion\ndata \"azurerm_resource_group\" \"example\" {\n  name = var.rg_name\n}\n```","commentType":1}],"status":"active","threadContext":{"filePath":"/src/main.tf","rightFileStart":{"line":42,"offset":1},"rightFileEnd":{"line":44,"offset":1}}}'

# Reply to thread
curl -s -H "$AUTH" -H "Content-Type: application/json" -X POST \
  "${THREADS}/<threadId>/comments?api-version=7.1" \
  -d '{"parentCommentId":1,"content":"Fixed in latest push.","commentType":1}'

# Update a comment
curl -s -H "$AUTH" -H "Content-Type: application/json" -X PATCH \
  "${THREADS}/<threadId>/comments/<commentId>?api-version=7.1" \
  -d '{"content":"Updated response."}'

# Delete a comment (soft-delete, returns HTTP 200)
curl -s -H "$AUTH" -H "Content-Type: application/json" -X DELETE \
  "${THREADS}/<threadId>/comments/<commentId>?api-version=7.1"

# Resolve thread
curl -s -H "$AUTH" -H "Content-Type: application/json" -X PATCH \
  "${THREADS}/<threadId>?api-version=7.1" \
  -d '{"status":"fixed"}'
# Status values: active, fixed, wontFix, closed, byDesign, pending

# Reactivate thread
curl -s -H "$AUTH" -H "Content-Type: application/json" -X PATCH \
  "${THREADS}/<threadId>?api-version=7.1" \
  -d '{"status":"active"}'

Pipeline Operations

az pipelines list --name <filter> --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false
az pipelines runs list --pipeline-ids <id> --top N --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false
az pipelines run --id <id> --branch <branch> --parameters key=value --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false
az pipelines build cancel --build-id <id> --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false
az pipelines create --name <name> --repository <repo> --yml-path <path> --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false
az pipelines update --id <id> --name <name> --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false
az pipelines delete --id <id> --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false

Run specific stages only (skip others)

az pipelines run does not expose stagesToSkip. Use the /pipelines/{id}/runs REST endpoint directly. Stages listed in stagesToSkip end skipped, and downstream stages that depend on them run as if the upstream succeeded - so this is the correct way to rerun e.g. only a cleanup/destroy stage after a cancelled apply, without editing the pipeline YAML or adding approval gates.

# Identifier is the YAML `- stage: <id>`, not the displayName. Grab it from a
# prior run's timeline: `records[].type == 'Stage'` -> `.identifier`.
curl -sS -H "$AUTH" -X POST \
  "$ADO_ORG/$ADO_PROJECT/_apis/pipelines/<pipelineId>/runs?api-version=7.1-preview.1" \
  -H "Content-Type: application/json" \
  -d '{
    "resources": { "repositories": { "self": { "refName": "refs/heads/<branch>" } } },
    "stagesToSkip": ["RepoValidate", "TerraformValidate", "TerraformPlan", "TerraformApply"]
  }'

Common use case: previous BVP run was cancelled mid-apply, leaving an orphan resource group in state. Skip every upstream stage and let only TerraformDestroy run - it reads the existing state backend and tears down what the cancelled apply created.

Contrast with cancellation cascade (which is not overridden by stagesToSkip on a running build): when a running build is cancelled, the upstream ends Canceled and downstream defaults to Skipped via the implicit succeeded() condition. No rerun button appears on the skipped stage. The fix there is a fresh queue with stagesToSkip as above, not re-running within the cancelled build.

Note: the older /build/builds?api-version=7.1 endpoint silently ignores stagesToSkip. Use /pipelines/{id}/runs?api-version=7.1-preview.1.

Policy Operations

# Step 1: Get repository ID
REPO_ID=$(az repos show -r <repo> --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false --query id -o tsv)
# Step 2: List policies filtered by repository
az repos policy list --repository-id "$REPO_ID" --branch <branch> --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false
az repos policy update --id <id> --blocking true --enabled true --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false
az repos policy delete --id <id> --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false

Create policy (complex - use script for identity resolution):

${CLAUDE_SKILL_DIR}/scripts/ado-create-policy.sh --repo <name> --type build --pipeline-id <id> [--branch main] [--display-name TEXT] [--blocking]
${CLAUDE_SKILL_DIR}/scripts/ado-create-policy.sh --repo <name> --type approver [--min-approvers N] [--creator-vote] [--reset-on-push] [--branch main] [--blocking]
${CLAUDE_SKILL_DIR}/scripts/ado-create-policy.sh --repo <name> --type required-reviewer --reviewer <email|name|team|GUID> [--reviewer ...] [--filename-patterns "/*.tf,/pipelines/*"] [--branch main] [--blocking]

Variable Groups

az pipelines variable-group list --group-name <filter> --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false
az pipelines variable-group show --id <id> --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false
az pipelines variable-group variable create --group-id <id> --name KEY --value VALUE --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false
az pipelines variable-group variable update --group-id <id> --name KEY --new-value VALUE --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false
az pipelines variable-group variable delete --group-id <id> --name KEY --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false

Work Items

Custom Fields

Project-specific custom fields and work item types should be defined in your CLAUDE.md. See examples/project-claude-ado.md for a template.

Read Operations

# Show work item (all fields + relations)
az boards work-item show --id <ID> --expand all --org "$ADO_ORG" --detect false -o json

# Show specific fields only (NOTE: --expand and -f are mutually exclusive)
az boards work-item show --id <ID> -f "System.Title,System.State,System.AssignedTo,<custom-field-1>,<custom-field-2>" --org "$ADO_ORG" --detect false -o json

# Query work items (WIQL) - this command accepts --project
az boards query --wiql "SELECT [System.Id], [System.Title], [System.State] FROM workitems WHERE [System.AreaPath] UNDER '<AreaPath>' AND [System.State] = 'Active' AND [System.WorkItemType] = '<TaskType>'" --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false

# List child work items of a parent
az boards query --wiql "SELECT [System.Id], [System.Title], [System.State], [System.AssignedTo] FROM workitems WHERE [System.Parent] = <PARENT_ID>" --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false

# Show work item with relations (to find parent/child links)
az boards work-item show --id <ID> --expand relations --org "$ADO_ORG" --detect false -o json
# Parse parent: jq '.relations[] | select(.attributes.name == "Parent") | .url' - extract ID from URL tail

Create & Update

# Create task under a project
az boards work-item create --type "<TaskType>" --title "Implement feature X" \
  --description "What needs to be done and why" \
  --assigned-to "[email protected]" \
  --area "<AreaPath>" \
  --iteration "<IterationPath>" \
  -f "<custom-field-1>[email protected]" "<custom-field-2>[email protected]" \
  --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false

# Update work item (state, assignment, custom fields)
az boards work-item update --id <ID> --state Active --assigned-to "[email protected]" \
  --org "$ADO_ORG" --detect false

# Set custom fields on existing work item
az boards work-item update --id <ID> \
  -f "<custom-field-1>[email protected]" "<custom-field-2>[email protected]" \
  --org "$ADO_ORG" --detect false

# Quick append discussion comment (az CLI shorthand - no comment ID returned, no @mention support)
az boards work-item update --id <ID> --discussion "Started work on this" \
  --org "$ADO_ORG" --detect false

Comments

Full CRUD on work item comments requires REST API (curl with $AUTH). The --discussion flag above is append-only and does not support @mentions.

@Mentions in comments: Use the REST API with HTML mention format. The --discussion flag renders mentions as plain text.

# AUTH as set in the Authentication section (Basic PAT or az Bearer token)
WI_COMMENTS="${ADO_ORG}/${ADO_PROJECT}/_apis/wit/workItems/<id>/comments"

# Post comment with @mention (use identity GUID and email)
curl -s -H "$AUTH" -H "Content-Type: application/json" -X POST \
  "${WI_COMMENTS}?api-version=7.1-preview.4" \
  -d '{"text":"<a href=\"mailto:[email protected]\" data-vss-mention=\"version:2.0,<IDENTITY_GUID>\">@Display Name</a> please review."}'
# AUTH as set in the Authentication section (Basic PAT or az Bearer token)
WI_COMMENTS="${ADO_ORG}/${ADO_PROJECT}/_apis/wit/workItems/<id>/comments"

# List comments (most recent first)
curl -s -H "$AUTH" -H "Content-Type: application/json" \
  "${WI_COMMENTS}?\$top=10&order=desc&api-version=7.1-preview.4"

# Add comment (returns comment with id for later update/delete)
curl -s -H "$AUTH" -H "Content-Type: application/json" -X POST \
  "${WI_COMMENTS}?api-version=7.0-preview.3" \
  -d '{"text":"Started investigation. Root cause is missing RBAC assignment."}'

# Update comment
curl -s -H "$AUTH" -H "Content-Type: application/json" -X PATCH \
  "${WI_COMMENTS}/<commentId>?api-version=7.1-preview.4" \
  -d '{"text":"Updated: fix is in PR #142."}'

# Delete comment (soft-delete, returns HTTP 204)
curl -s -H "$AUTH" -H "Content-Type: application/json" -X DELETE \
  "${WI_COMMENTS}/<commentId>?api-version=7.1-preview.4"

Relations

# Add parent relation (make task child of user story)
az boards work-item relation add --id <CHILD_ID> --relation-type parent --target-id <PARENT_ID> \
  --org "$ADO_ORG" --detect false

# Add child relation
az boards work-item relation add --id <PARENT_ID> --relation-type child --target-id <CHILD_ID> \
  --org "$ADO_ORG" --detect false

# Link work item to PR (from PR side - preferred)
az repos pr work-item add --id <PR_ID> --work-items <WI_ID> \
  --org "$ADO_ORG" --detect false

# List relation types available
az boards work-item relation list-type --org "$ADO_ORG" --detect false

Teams

# List teams in project
az devops team list --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false

# List team members
az devops team list-member --team "TeamName" --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false

Scripts

# PR threads (list, filter by status/file)
${CLAUDE_SKILL_DIR}/scripts/ado-pr-threads.sh --pr-id <id> --repo <repo> --status active
${CLAUDE_SKILL_DIR}/scripts/ado-pr-threads.sh --pr-id <id> --repo <repo> --file "/src/main.tf" --json

# Run details with stage/job tree
${CLAUDE_SKILL_DIR}/scripts/ado-get-run.sh --run-id <id>

# Task logs
${CLAUDE_SKILL_DIR}/scripts/ado-get-logs.sh --run-id <id> --failed-only
${CLAUDE_SKILL_DIR}/scripts/ado-get-logs.sh --run-id <id> --task "Plan" --tail 100

Branches, Tags & Feeds

az repos ref delete --name heads/<branch> -r <repo> --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false
az artifacts feed list --org "$ADO_ORG" --detect false
az artifacts feed create --name <name> --org "$ADO_ORG" --detect false
az artifacts feed delete --feed <name> --org "$ADO_ORG" --detect false

Tags

Prefer annotated tags (git tag -a): ADO's Tags view shows the tagger, date, and message only for annotated tag objects - a lightweight tag renders with an empty creator and no message. Fetch the remote first so the tag lands on the current commit and existing tags are visible.

git fetch origin --tags
git tag -a v1.2.3 <commit> -m "<repo> v1.2.3: what this release ships"
git push origin v1.2.3

Environments, Checks & Approvals (REST API)

These operations have no az CLI support. Use curl with the REST API. See the "Manage Environment Checks & Approvals" workflow recipe below, and reference.md for advanced patterns (branch control checks, deployment records).

Workflow Recipes

PR Lifecycle

# 1. Create PR with auto-complete
az repos pr create -r my-repo -s feature/foo --title "Add feature" \
  --auto-complete true --squash true --delete-source-branch true \
  --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false

# 2. Check status and policy evaluations
az repos pr show --id 42 --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false
az repos pr policy list --id 42 --org "$ADO_ORG" --detect false

# 3. Requeue failed BVP if needed
az repos pr policy list --id 42 -o json --org "$ADO_ORG" --detect false  # find eval ID
az repos pr policy queue --id 42 -e <eval-id> --org "$ADO_ORG" --detect false

# 4. Force-complete if stuck
az repos pr update --id 42 --status completed --squash true \
  --delete-source-branch true --bypass-policy true \
  --org "$ADO_ORG" --detect false

# 5. Abandon if no longer needed
az repos pr update --id 42 --status abandoned --org "$ADO_ORG" --detect false

# 6. Delete leftover branch
az repos ref delete --name heads/feature/foo -r my-repo --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false

Debug Failed Pipeline

# 1. Find pipeline and recent runs
az pipelines list --name "bvp" --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false
az pipelines runs list --pipeline-ids 8 --top 5 --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false

# 2. Inspect run (stage/job tree)
${CLAUDE_SKILL_DIR}/scripts/ado-get-run.sh --run-id 12345

# 3. Get failed task logs
${CLAUDE_SKILL_DIR}/scripts/ado-get-logs.sh --run-id 12345 --failed-only

# 4. Drill into specific task
${CLAUDE_SKILL_DIR}/scripts/ado-get-logs.sh --run-id 12345 --task "Terraform Plan" --tail 100

Manage Policies

# List policies on a repo (requires repo GUID)
REPO_ID=$(az repos show -r my-repo --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false --query id -o tsv)
az repos policy list --repository-id "$REPO_ID" --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false

# Add BVP
${CLAUDE_SKILL_DIR}/scripts/ado-create-policy.sh --repo my-repo --type build --pipeline-id 7 --display-name "BVP" --blocking

# Disable temporarily
az repos policy update --id 5 --enabled false --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false

# Re-enable
az repos policy update --id 5 --enabled true --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false

# Delete
az repos policy delete --id 5 --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false

Manage Variable Groups

az pipelines variable-group list --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false
az pipelines variable-group show --id 3 --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false
az pipelines variable-group variable create --group-id 3 --name TF_STATE_RG --value rg-terraform --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false
az pipelines variable-group variable update --group-id 3 --name TF_STATE_RG --new-value rg-terraform-v2 --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false
az pipelines variable-group variable delete --group-id 3 --name OLD_VAR --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false

Manage Environment Checks & Approvals

# List environments
# AUTH as set in the Authentication section (Basic PAT or az Bearer token)
BASE="${ADO_ORG}/${ADO_PROJECT}/_apis"

curl -s -H "$AUTH" "$BASE/distributedtask/environments?api-version=7.1"

# List checks on environment
curl -s -H "$AUTH" "$BASE/pipelines/checks/configurations?resourceType=environment&resourceId=<ENV_ID>&\$expand=settings&api-version=7.1-preview.1"

# Approve a pipeline run
curl -s -X PATCH -H "$AUTH" -H "Content-Type: application/json" \
  -d '[{"approvalId":"<ID>","status":"approved","comment":"Verified plan"}]' \
  "$BASE/pipelines/approvals?api-version=7.1-preview.1"

PR Review Workflow

# 1. Show PR details + list active threads
az repos pr show --id <ID> --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false
${CLAUDE_SKILL_DIR}/scripts/ado-pr-threads.sh --pr-id <ID> --repo <repo> --status active

# 2. Read a specific thread in full (--json + python3 for formatting)
${CLAUDE_SKILL_DIR}/scripts/ado-pr-threads.sh --pr-id <ID> --repo <repo> --json \
  | python3 -c "import sys,json; threads=json.load(sys.stdin); t=[x for x in threads if x['id']==<threadId>]; print(json.dumps(t[0],indent=2)) if t else print('Not found')"

# 3. Reply to reviewer feedback
# AUTH as set in the Authentication section (Basic PAT or az Bearer token)
THREADS="${ADO_ORG}/${ADO_PROJECT}/_apis/git/repositories/<repo>/pullRequests/<ID>/threads"
curl -s -H "$AUTH" -H "Content-Type: application/json" -X POST \
  "${THREADS}/<threadId>/comments?api-version=7.1" \
  -d '{"parentCommentId":1,"content":"Fixed in latest push.","commentType":1}'

# 4. Provide code suggestion
curl -s -H "$AUTH" -H "Content-Type: application/json" -X POST \
  "${THREADS}?api-version=7.1" \
  -d '{"comments":[{"content":"Consider:\n\n```suggestion\nnew_code_here\n```","commentType":1}],"status":"active","threadContext":{"filePath":"/path","rightFileStart":{"line":10,"offset":1},"rightFileEnd":{"line":12,"offset":1}}}'

# 5. Resolve addressed threads
curl -s -H "$AUTH" -H "Content-Type: application/json" -X PATCH \
  "${THREADS}/<threadId>?api-version=7.1" \
  -d '{"status":"fixed"}'

# 6. Ask for clarification (create new general thread)
curl -s -H "$AUTH" -H "Content-Type: application/json" -X POST \
  "${THREADS}?api-version=7.1" \
  -d '{"comments":[{"content":"Question: what is the expected behavior when X?","commentType":1}],"status":"active"}'

Work Item → Development → PR Workflow

# 1a. Get ticket context (all fields + relations for parent/child)
az boards work-item show --id <WI_ID> --expand all --org "$ADO_ORG" --detect false -o json

# 1b. Load work item comments for context
# AUTH as set in the Authentication section (Basic PAT or az Bearer token)
curl -s -H "$AUTH" -H "Content-Type: application/json" \
  "${ADO_ORG}/${ADO_PROJECT}/_apis/wit/workItems/<WI_ID>/comments?\$top=10&order=desc&api-version=7.1-preview.4"

# 2. Get parent story for context (parse parent URL from relations, extract ID)
az boards work-item show --id <PARENT_ID> --expand all --org "$ADO_ORG" --detect false -o json
# Note parent's: custom fields, area-path, iteration-path

# 3a. Pick up existing unassigned task
az boards work-item update --id <WI_ID> --state Active --assigned-to "[email protected]" \
  --org "$ADO_ORG" --detect false
# Set custom fields if missing
az boards work-item update --id <WI_ID> \
  -f "<custom-field-1>[email protected]" "<custom-field-2>[email protected]" \
  --org "$ADO_ORG" --detect false

# 3b. Or create new task from parent story (inherit custom fields, area, iteration)
az boards work-item create --type "<TaskType>" --title "Implement X" \
  --description "Description of the task" \
  --area "<AreaPath>" \
  --iteration "<IterationPath>" \
  -f "<custom-field-1>[email protected]" "<custom-field-2>[email protected]" \
  --assigned-to "[email protected]" \
  --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false
# Link to parent
az boards work-item relation add --id <NEW_TASK_ID> --relation-type parent --target-id <PARENT_ID> \
  --org "$ADO_ORG" --detect false

# 4. Do development work...

# 5. Create PR
az repos pr create -r my-repo -s feature/branch --title "Implement X" \
  --auto-complete true --squash true --delete-source-branch true \
  --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false

# 6. Link work item to PR
az repos pr work-item add --id <PR_ID> --work-items <WI_ID> \
  --org "$ADO_ORG" --detect false

# 7. Add reviewers to PR (use GUIDs from identity fields, not emails - PAT can't resolve emails)
az repos pr reviewer add --id <PR_ID> --reviewers <REVIEWER1_GUID> <REVIEWER2_GUID> --required true \
  --org "$ADO_ORG" --detect false

Find Team Members for Review

# 1. List teams
az devops team list --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false -o table

# 2. Get members of a team
az devops team list-member --team "<TeamName>" --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false -o table

# 3. Add as PR reviewer (use member GUID from list-member output - email lookup fails with PAT auth)
az repos pr reviewer add --id <PR_ID> --reviewers <MEMBER_GUID> \
  --org "$ADO_ORG" --detect false

Troubleshooting

--expand and -f are mutually exclusive

az boards work-item show does not allow --expand and -f (fields) together. Use one or the other.

Creating and activating a task requires two calls

Setting --state Active and --assigned-to in the same create call is not supported. Create the task first (it starts as New), then update it in a second call:

# 1. Create
az boards work-item create --type "<TaskType>" --title "..." --description "..." \
  --area "<AreaPath>" --iteration "<IterationPath>" \
  --org "$ADO_ORG" -p "$ADO_PROJECT" --detect false -o json
# 2. Activate and assign
az boards work-item update --id <NEW_ID> --state Active --assigned-to "[email protected]" \
  --org "$ADO_ORG" --detect false

Identity Discovery

At the start of each session that involves assigning work items or adding PR reviewers, resolve the current user's identity:

az ad signed-in-user show --query '{displayName: displayName, mail: mail, id: id}' -o json

Use the returned email for --assigned-to and the GUID for reviewer operations. Do not persist this to memory - the user may switch accounts between sessions.

Instructions

Check CLAUDE.md for project-specific ADO configuration (custom work item types, area paths, iteration paths, custom fields, team conventions).

When the user asks for an ADO operation:

  1. Resolve auth per the Authentication section (PAT, ADO_TOKEN, or az login token); instruct the user only if no source works
  2. Use az CLI with -o json when parsing programmatically, -o table for display
  3. For complex queries, chain commands (e.g., list pipelines -> find ID -> run pipeline)
  4. Use scripts from ${CLAUDE_SKILL_DIR}/scripts/ for: create-policy, get-run, get-logs, pr-threads
  5. For environments/checks/approvals and comments, use REST curl patterns
  6. For work items, remember: az boards work-item show/update/relation add are org-scoped (no --project), only create and query take --project
  7. When creating tasks from stories, inherit custom fields, area-path, and iteration-path from the parent
  8. When linking work items to PRs, prefer az repos pr work-item add (from PR side)
  9. If an az command fails unexpectedly, fall back to raw curl
  10. When reading a work item or PR for context, also load comments/threads for full picture
  11. For PR review, start by listing active threads to see what needs attention
  12. Code suggestions use ```suggestion blocks - ADO renders them as applicable diffs

Additional Resources

For detailed reference material and real output examples, consult:

  • reference.md - Full az CLI flag tables, JMESPath query patterns, REST API details for environments/checks/approvals, work item comments, PR comment threads, work item field reference, identity resolution cascade, policy type GUIDs
  • examples.md - Real output samples for all major commands (PR list/show/policy, pipeline list/runs, run tree, work item JSON, query results, task logs, PR threads, work item comments, code suggestions)
  • examples/project-claude-ado.md - Template for project-specific ADO configuration (custom fields, work item types, area/iteration paths) to add to your CLAUDE.md

What ships with it: 9 files

57.5 KB alongside SKILL.md, 6 of them executable

examples/

scripts/

Gives 0 of the 12 instructions most pr commit review skills give in ~9.4k tokens

Counted across 888 of the 1,342 authors here whose files we hold, read 2026-08-07

  • Use conventional commits formatin 127 of 888, across 115 files
  • Keep subject line under 72 charactersin 62 of 888, across 48 files
  • Delete branches after mergein 51 of 888, across 38 files
  • Use imperative mood in subject linein 51 of 888, across 42 files
  • Use imperative mood in commit messagesin 44 of 888
  • Verify directory is ignored before creating worktreein 43 of 888, across 12 files
  • Generate a conventional commit messagein 43 of 888
  • Add unignored worktree directories to gitignorein 42 of 888, across 10 files
  • Make atomic commitsin 39 of 888, across 27 files
  • Run tests before committingin 36 of 888, across 25 files
  • Verify clean test baselinein 35 of 888, across 9 files
  • Split unrelated changes into separate commitsin 35 of 888, across 30 files

Said here and by no other author read

  • Use az CLI for most operations
  • Use bash scripts for complex orchestration
  • Read auth credentials from environment variables
  • Never export or mutate session credentials
  • Use --detect false on all az commands
  • Omit --project on org-scoped commands

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.