.claude/skills/sync-ado-repos/SKILL.md
Sync GitHub repos from bluebillywig org to an ADO "Repository" picklist field on all work item types
npx skillsauth add Vvanlaar/orch sync-ado-reposInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Fetches all repos from github.com/bluebillywig and creates/updates a Custom.Repository picklist field on all work item types across all inherited processes in Azure DevOps.
Write and execute a Node.js script (temp file, delete after). Use built-in fetch (Node 18+).
Auth headers:
Authorization: Bearer {GITHUB_TOKEN}Authorization: Basic {base64(':' + ADO_PAT)}ADO API version: 7.1 for all calls except field creation (4.1-preview.1) and project properties (7.1-preview.1).
.envParse C:\dev\ai\orch\.env for ADO_ORG, ADO_PAT, GITHUB_TOKEN. Use fs.readFileSync with line parsing (split on =, trim, strip quotes). Last value wins for duplicate keys.
github.com/bluebillywigGET https://api.github.com/orgs/bluebillywig/repos?per_page=100&page=N
Paginate until empty page. Extract .name, sort alphabetically, log count.
First check if Custom.Repository field exists and read its picklistId:
GET https://dev.azure.com/{org}/_apis/wit/fields/Custom.Repository?api-version=7.1
If no picklist ID from field, search all picklists for one named "Repository":
GET https://dev.azure.com/{org}/_apis/work/processes/lists?api-version=7.1
Create (if not found -- include name!):
POST .../lists?api-version=7.1
Body: { "name": "Repository", "type": "String", "items": [...repos], "isSuggested": true }
Update (if found):
PUT .../lists/{listId}?api-version=7.1
Body: { "id": "{listId}", "items": [...repos], "isSuggested": true }
GET https://dev.azure.com/{org}/_apis/work/processes?$expand=projects&api-version=7.1
Filter to customizationType === 'inherited'. The $expand=projects parameter includes which projects use each process. For EACH inherited process, fetch WITs:
GET https://dev.azure.com/{org}/_apis/work/processes/{processId}/workitemtypes?api-version=7.1
If step 3's field check returned 404, create the field. Use the older processdefinitions API with type: "string" (NOT "picklistString"):
POST https://dev.azure.com/{org}/_apis/work/processdefinitions/{processId}/fields?api-version=4.1-preview.1
Body: { "name": "Repository", "type": "string", "pickList": { "id": "{picklistId}" } }
The type must be "string" — the picklist binding is what makes it a picklist field. Using "picklistString" causes FieldTypeInvalid.
For each WIT, check wit.customization:
If customization !== 'system' (already derived/custom): add field directly:
POST .../processes/{processId}/workItemTypes/{witRefName}/fields?api-version=7.1
Body: { "referenceName": "Custom.Repository" }
If customization === 'system' (not yet derived): skip — the REST API cannot derive a WIT with the same name as the system parent. These require manual derivation via the ADO UI.
Adding a field to a WIT does NOT make it visible on the form. You must also add a control to the WIT's layout.
For each WIT where the field was added:
GET .../processes/{processId}/workItemTypes/{witRefName}/layout?api-version=7.1
Check if Custom.Repository control already exists (scan all pages/sections/groups/controls for ctrl.id === 'Custom.Repository').
Find a suitable group on the "Details" page. Prefer groups labeled "Details" or "Classification". Avoid groups that already contain an HtmlFieldControl — ADO allows only one HTML control per group (error VS403105).
If the first group fails with 500 (HTML control conflict), find another group without HTML controls.
If an existing plain control exists, remove it first:
DELETE .../processes/{processId}/workItemTypes/{witRefName}/layout/groups/{groupId}/controls/Custom.Repository?api-version=7.1
Custom.BusinessUnit / "Business Unit(s)"). This uses the already-installed ms-devlabs.vsts-extensions-multivalue-control extension:POST .../processes/{processId}/workItemTypes/{witRefName}/layout/groups/{groupId}/controls?api-version=7.1
Body: {
"id": "Custom.Repository",
"label": "Repository",
"visible": true,
"readOnly": false,
"isContribution": true,
"contribution": {
"contributionId": "ms-devlabs.vsts-extensions-multivalue-control.multivalue-form-control",
"inputs": { "FieldName": "Custom.Repository" }
}
}
Output markdown summary: repos synced, picklist created vs updated, processes and WITs updated vs skipped, controls added to layout. Include reminder to install Multivalue control extension for multi-select.
customization: system): cannot add fields or layout controls via API. Open ADO UI > Process > click the WIT to auto-derive, then re-run."string" (not "picklistString") in the processdefinitions API.name field in POST body or API returns 400.ms-devlabs.vsts-extensions-multivalue-control is already installed in the org. The field type is identical to a regular picklist string — multi-select is purely a layout control concern (use isContribution: true with the extension's contributionId).foo;bar). If isSuggested: false, ADO validates the combined string against individual picklist items and rejects it. Use isSuggested: true so values are suggestions, not enforced.node.exe directly to avoid Git Bash shell issuesdevelopment
Build a new desktop app release (Electron). Triggers on "build desktop", "new release", "desktop release", "build the app"
development
Generic Azure DevOps operations — edit tickets, query work items, add comments, change fields, move sprints, assign users, link items, and more. Triggers on "ado", "edit ticket", "update ticket", "move ticket", "assign ticket", "link ticket", "query ado", "search ado", "add comment to ticket", or ticket number mentions with edit/update intent.
testing
Use when testing and verifying a bug fix or feature for an ADO ticket. Triggers on /ado-test, "test ticket", or requests to test a ticket number.
development
Use when starting work on an Azure DevOps ticket. Triggers on "start ticket", "work on ticket", ticket number with implementation intent, or requests to plan a feature from a ticket.