findings-to-ado-backlog (orchestrator)
Run the full pipeline: a source document in, an ADO backlog out. You coordinate six
sibling skills; each owns its step and its data contract. Your job is to sequence them,
keep the working files together, and enforce the safety gates so nothing irreversible
happens without the user seeing it first.
Why an orchestrator: the value is in the gates, not the glue. Creating work items is a
write the user cannot easily undo, so the pipeline is deliberately staged: read-only
extraction and classification first, a dry run that creates nothing, an explicit human
approval, then the real write. Each sub-skill is reusable on its own; this skill is the
teachable happy path that ties them together.
Data flow
Three small JSON files carry state between steps. They share a stable
per finding
(a row number or ID column) so a created ticket can be traced back to its source row.
Full shapes live in
${CLAUDE_PLUGIN_ROOT}/references/data-contracts.md
— read it once; do
not duplicate schemas here.
extract-findings -> findings.json
classify-work-items -> backlog_input.json (consumed by create-backlog.cs)
ado-create-work-items -> backlog_result.json (consumed by tracking.py writeback)
Working directory: create one beside the source (e.g. next to the xlsx) and keep all
three JSON files there. This keeps a run self-contained and re-runnable.
Process
0. Prereqs + auth (optional but recommended on first run)
Confirm the toolchain is present before you invest in extraction. This is read-only.
powershell
powershell -ExecutionPolicy Bypass -File "${CLAUDE_PLUGIN_ROOT}/scripts/setup_check.ps1"
It checks
, .NET >= 10, Python + openpyxl, and the
/
env vars. For auth specifics (Entra token vs
, org/project), delegate to
ado-auth. The create script defaults to an Entra token via
az account get-access-token --resource 499b84ac-1321-427f-aa17-267ca6975798 --query accessToken -o tsv
.
1. Extract → (delegate to extract-findings)
Have
extract-findings read the source (it uses
${CLAUDE_PLUGIN_ROOT}/scripts/read_source.py
for xlsx/csv; docs and pasted text are read
directly) and normalize it to
.
Confirm the column mapping with the user
before moving on — which column is the
, which are
/
, where
and
come from. A wrong mapping silently poisons everything downstream.
2. Triage → scoped subset (delegate to triage-findings)
Don't file everything blindly. Have
triage-findings filter
to the wave
worth creating now.
Recommend Critical + confirmed first — it is the smallest defensible
batch and proves the pipeline before you fan out. Hold
items for a later wave
and tell the user you are doing so.
3. Classify → (delegate to classify-work-items)
Have classify-work-items map the scoped findings to ADO work items. It must:
- Discover the target project's process (Agile / Scrum / Basic / CMMI) and pick
industry-standard types that actually exist on that board — e.g. a defect is on
Agile/Scrum/CMMI but Basic has no Bug (use ). See the process→types table in
.
- Optionally add a or parent to group the batch; every item links under
it via
System.LinkTypes.Hierarchy-Reverse
.
- Decide assignment — ask the user who these go to. A fresh backlog is usually created
unassigned (assigned later in planning), but ask: leave unassigned, assign to the user
themselves, assign the batch to one person, or map a per-row owner. Set
(a UPN like ) on each item, or assign the whole batch at create time with the
env var. The dry run validates the identity before any real write.
- Emit raw ADO field reference names (,
Microsoft.VSTS.Common.Priority
,
; Bug body Microsoft.VSTS.TCM.ReproSteps
; Story/PBI body
Microsoft.VSTS.Common.AcceptanceCriteria
). HTML fields must be valid HTML.
- Estimate time per item and attach it as a child Task (hours in Original/Remaining
Work; the detailed breakdown in the Task description) — see .
GATE — estimates. classify proposes the hours per item as a table. Show it and get the
user's OK / adjustments before the dry run. Estimates are cheap to fix now, annoying to fix
across already-created Tasks.
4. DRY RUN → validate, create nothing (delegate to ado-create-work-items)
This is the first gate. The create script defaults to dry run, which sends each item to ADO
with
— it catches a bad type, a missing required field, or a wrong
area/iteration path
without creating anything.
powershell
$env:AZDO_DRY_RUN = "true"
dotnet run "${CLAUDE_PLUGIN_ROOT}/scripts/create-backlog.cs" -- "<workdir>/backlog_input.json"
Show the user the validated PASS/FAIL list (type, title per
). Fix any FAIL in
and re-run until clean.
GATE — stop here. Do not proceed to the real run until the user has explicitly
approved the validated list. Present the count, the types, and the parent, and wait for a
clear yes.
5. REAL RUN → (delegate to ado-create-work-items)
Only after approval. Setting
to
creates the parent (if any), every
child,
and a child Task (with the hour estimate) under each item, links them all, and writes
.
powershell
$env:AZDO_DRY_RUN = "false"
dotnet run "${CLAUDE_PLUGIN_ROOT}/scripts/create-backlog.cs" -- "<workdir>/backlog_input.json"
Then
verify the created items — confirm each
got an
and
in
, and that any rows logged
are surfaced to the user, not buried.
6. Write-back tracking — spreadsheets only (delegate to ado-writeback-tracking)
Only if the source is a spreadsheet (a row per finding). For docs/pasted text there is no
row to write to — skip this step.
GATE — back up the source first. Write-back mutates the user's spreadsheet in place.
Copy the file before running it.
Have
ado-writeback-tracking drive
${CLAUDE_PLUGIN_ROOT}/scripts/tracking.py
: first
ensure the
Ticket ID | Ticket URL | WI State | Created
columns exist (
), then
match each result
to the source key column and fill them (
). Both subcommands
are idempotent — rows that already have a Ticket ID are left as-is — so a re-run is safe. Pass
matching the key column you confirmed in step 1.
7. Report back
Summarize the run for the user:
- Created: count + clickable links (the per item, and the parent if any).
- Held / skipped: the triage wave you deferred (e.g. ), plus any dry-run
FAILs or real-run errors and why.
- Follow-ups: the obvious next wave (run steps 2–6 again on the deferred subset), and any
ambiguous findings that need a human decision before they can be classified.
Safety gates (the whole point)
- Dry run before real — step 4 always precedes step 5; the script defaults to dry run.
- Explicit approval before any write — never jump from validation to creation on your own.
- Back up the source before write-back — step 6 edits the user's file in place.
If anything is ambiguous (column mapping, which process, which parent), ask rather than
guess — a wrong guess multiplies across every item in the batch.