From claude-team-toolkit
Azure DevOps repos/PRs/work items/pipelines via REST. Cloud + self-hosted Server. Use for PR list/create/comment, WIQL queries, pipeline runs. Multi-org via AZDO_PROFILE.
npx claudepluginhub tuannv14/claude-team-toolkit --plugin claude-team-toolkitThis skill is limited to using the following tools:
Direct REST against Azure DevOps Services or self-hosted Server. No `az`
Prevents silent decimal mismatch bugs in EVM ERC-20 tokens via runtime decimals lookup, chain-aware caching, bridged-token handling, and normalization. For DeFi bots, dashboards using Python/Web3, TypeScript/ethers, Solidity.
Share bugs, ideas, or general feedback.
Direct REST against Azure DevOps Services or self-hosted Server. No az
CLI dependency (the extension does NOT support self-hosted Server).
Arguments: $ARGUMENTS. Profile resolution: --profile → AZDO_PROFILE /
AZURE_DEVOPS_PROFILE → ~/.azure-devops/active_profile → [default].
~/.azure-devops/credentials (mode 600):
[default]
org_url = https://dev.azure.com/your-org
pat = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
api_version = 7.0
project = MyProject # optional default
[work-server]
org_url = https://devops.company.com/CollectionName
pat = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
api_version = 5.1 # Server often needs 5.1
project = InternalProject
insecure = false # true only for self-signed certs
PAT scopes (least privilege): Code (Read & Write), Pull Request Threads (Read & Write), Work Items (Read & Write), Build (Read & Execute). Avoid
Full access.
Get PAT: https://<org-or-server>/_usersSettings/tokens.
source "$HOME/.claude-team-toolkit/lib/credentials.sh"
ctt_load_creds azure-devops "$PROFILE"
# Build Basic auth (username empty, PAT in password slot)
AZDO_AUTH=$(printf ":%s" "$CTT_PAT" | base64 -w0 2>/dev/null || printf ":%s" "$CTT_PAT" | base64)
[ "$CTT_INSECURE" = "true" ] && AZDO_CURL="curl -sk --ssl-no-revoke" || AZDO_CURL="curl -s --ssl-no-revoke"
ORG="${CTT_ORG_URL%/}"
APIV="${CTT_API_VERSION:-7.0}"
PROJECT_DEFAULT="$CTT_PROJECT"
azdo_api() {
local method="$1" path="$2"; shift 2
local sep="?"; [[ "$path" == *\?* ]] && sep="&"
$AZDO_CURL -X "$method" \
-H "Authorization: Basic $AZDO_AUTH" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
"$@" \
"${ORG}${path}${sep}api-version=${APIV}"
}
configure — interactive setupPrompt: profile name → org URL → PAT (hidden) → default project → API version (default 7.0; suggest 5.1 if URL doesn't contain dev.azure.com) → insecure (y/N for self-signed). Validate via _apis/connectionData. Save to creds file (mode 600).
profile list|use|current|remove — see lib/credentials.shprojects — list projectsazdo_api GET "/_apis/projects" | jq -r '.value[] | "\(.id)\t\(.name)\t\(.state)"'
repos [project] — list reposPROJECT="${1:-$PROJECT_DEFAULT}"
azdo_api GET "/$PROJECT/_apis/git/repositories" \
| jq -r '.value[] | "\(.id)\t\(.name)\t\(.webUrl)"'
branches <repo> [project] — list branchesazdo_api GET "/$PROJECT/_apis/git/repositories/$REPO/refs?filter=heads" \
| jq -r '.value[] | .name | sub("^refs/heads/"; "")'
pr-list <repo> [project] [--status active|completed|abandoned|all]azdo_api GET "/$PROJECT/_apis/git/repositories/$REPO/pullrequests?searchCriteria.status=${STATUS:-active}" \
| jq -r '.value[] | "\(.pullRequestId)\t\(.status)\t\(.title)\t\(.createdBy.displayName)"'
pr-get <pr-id> <repo> [project]azdo_api GET "/$PROJECT/_apis/git/repositories/$REPO/pullrequests/$PR_ID"
pr-create <repo> <source-branch> <target-branch> <title> [description]BODY=$(jq -n \
--arg s "refs/heads/$SOURCE" \
--arg t "refs/heads/$TARGET" \
--arg title "$TITLE" \
--arg desc "$DESC" \
'{sourceRefName: $s, targetRefName: $t, title: $title, description: $desc}')
azdo_api POST "/$PROJECT/_apis/git/repositories/$REPO/pullrequests" -d "$BODY"
pr-comment <pr-id> <repo> <text> — add comment threadBODY=$(jq -n --arg t "$TEXT" '{
comments: [{parentCommentId: 0, content: $t, commentType: 1}],
status: 1
}')
azdo_api POST "/$PROJECT/_apis/git/repositories/$REPO/pullrequests/$PR_ID/threads" -d "$BODY"
wi-get <id> — fetch work item with all fieldsazdo_api GET "/_apis/wit/workitems/$WI_ID?\$expand=all"
wi-query <wiql> — run a WIQL queryBODY=$(jq -n --arg q "$WIQL" '{query: $q}')
azdo_api POST "/$PROJECT/_apis/wit/wiql" -d "$BODY" | jq -r '.workItems[].id'
WIQL example:
SELECT [System.Id], [System.Title], [System.State]
FROM workitems
WHERE [System.AssignedTo] = @Me AND [System.State] <> 'Closed'
ORDER BY [System.ChangedDate] DESC
wi-create <type> <title> [project] — create work itemBODY=$(jq -n --arg t "$TITLE" '[{op:"add", path:"/fields/System.Title", value:$t}]')
azdo_api POST "/$PROJECT/_apis/wit/workitems/\$$TYPE" \
-H "Content-Type: application/json-patch+json" \
-d "$BODY"
pipelines [project]azdo_api GET "/$PROJECT/_apis/pipelines" | jq -r '.value[] | "\(.id)\t\(.name)"'
pipeline-run <pipeline-id> [project] [--branch <name>]BODY=$(jq -n --arg b "${BRANCH:-main}" '{
resources: {repositories: {self: {refName: ("refs/heads/" + $b)}}}
}')
azdo_api POST "/$PROJECT/_apis/pipelines/$PIPELINE_ID/runs" -d "$BODY"
builds [project] [--top N]azdo_api GET "/$PROJECT/_apis/build/builds?\$top=${TOP:-20}" \
| jq -r '.value[] | "\(.id)\t\(.buildNumber)\t\(.status)\t\(.result // "—")"'
jq -n --arg for JSON; never string-interpolate user input.api_version=5.1, includes /Collection
in URL, may use self-signed cert (opt-in insecure=true).insecure=true disables TLS verification — only on trusted internal
networks, never for public hosts.