Documentation Index
Fetch the complete documentation index at: https://ekso.dev/llms.txt
Use this file to discover all available pages before exploring further.
ekso migrate devops pulls work items, comments, attachments, links, and iterations from Azure DevOps (and on-prem Azure DevOps Server / TFS) into your Ekso tenant. Two commands — collect and apply. Read Migrate overview and Before you start first.
What gets imported
| DevOps concept | Ekso shape |
|---|
| Team Project | DataContainer (Code = ProjectName, project GUID in Meta.devops_project_id) |
| Work Item (Bug, Task, User Story, Feature, Epic, Issue, …) | DataItem |
| Discussion comment | DataAnnotation |
| Attachment | DataFile (multipart upload) |
| Link (Parent, Child, Related, Successor, Predecessor, Tested By, …) | DataLink |
| Iteration (Sprint) | DataCycle |
| Area Path | ConfigLabel (prefix area:) + DataItem.Tags |
| Tag | ConfigLabel |
| Identity (DevOps user) | DataUser (matched or minted) |
System.WorkItemType | DataItem.Meta.devops_workitemtype |
Microsoft.VSTS.Scheduling.StoryPoints | DataItem.Field[] (via --field-map) |
Custom field (Custom.<Name>) | DataItem.Field[] (via --field-map) or Meta |
Authoring fidelity preserved — every comment, every change is attributed to the original DevOps identity (matched by email).
What does NOT get imported
- Revision history. Each work item has full edit history in DevOps; v1 imports only the current state. Re-evaluate if a customer needs SOX/audit migration.
- State transition rules. The migrator snapshots the current state of each item; transition rules don’t transfer.
- Build & release pipelines. Out of scope.
- Repos / Git history. Out of scope — work items only.
- Test plans / suites / runs. Test management is out of scope for v1.
- Boards & queries (saved WIQL). Re-author on the Ekso side.
- Service identities (
[Project]\Project Collection Build Service, etc.) are filtered at collect — they’re not real users.
Before you start
Pre-flight checklist on top of the general one:
- An Azure DevOps organisation (
https://dev.azure.com/<your-org>).
- A Personal Access Token (PAT) with Work Items (Read) + Identity (Read) scopes.
Add a devops block to your migration.config.json:
{
"ekso": { "tenant": "acme", "apiKey": "ek_live_..." },
"source": "devops",
"devops": {
"organisation": "your-org",
"personalAccessToken": "..."
}
}
Or use the env-var override EKSO_MIGRATE_DEVOPS_PAT for CI use cases.
The organisation field is the segment after dev.azure.com/ in your DevOps URL. For on-prem Azure DevOps Server, use the full base URL — see the on-prem section below.
Step 1 — list projects
ekso migrate devops list-projects \
--config migration.config.json \
--tenant acme
Sample output:
NAME ID STATE
Platform 01a3b9c8-1f44-4eaa-9c6e-7d5b2c1d3f4e wellFormed
Mobile 02b4ca99-2055-5fbb-ad7f-8e6c3d2e4a5f wellFormed
Step 2 — collect
ekso migrate devops collect \
--config migration.config.json \
--project Platform \
--tenant acme
Repeat --project for multiple. Sample run:
fetching projects... 1 fetched
running WIQL query... 4127 work items found
fetching work items... 4127/4127 (chunked at 200) ok
fetching discussion comments... 9803/9803 ok
fetching attachments... 421/421 ok
fetching iterations... 23 iterations ok
saved cache: ~/.ekso/migrate/devops-2026-04-29T143205.sqlite
Useful flags:
--no-attachments — skip downloads.
--no-comments — skip discussion.
--resume — pick up where a killed collect left off.
Step 3 — dry-run apply
ekso migrate devops apply \
--config migration.config.json \
--process proc_engineering \
--tenant acme \
--dry-run
Step 4 — apply for real
ekso migrate devops apply \
--config migration.config.json \
--process proc_engineering \
--tenant acme
If interrupted, re-run with --resume.
Identity resolution for DevOps
DevOps identities have email — --user-strategy match-or-create is reliable.
Service identities ([Project]\Project Collection Build Service, [Acme]\Project Collection Service Accounts, etc.) are filtered out at collect time — they aren’t real users and don’t pollute your Ekso user list. There’s a regression test pinning this.
Read Identity resolution.
Custom fields for DevOps
DevOps fields use Reference Name identifiers like Microsoft.VSTS.Scheduling.StoryPoints or Custom.<Name>:
devops:
Microsoft.VSTS.Scheduling.StoryPoints: { ekso: StoryPoints, kind: decimal }
Microsoft.VSTS.Common.Severity:
ekso: Severity
kind: picker
picker:
"1 - Critical": P0
"2 - High": P1
"3 - Medium": P2
"4 - Low": P3
Custom.RootCause: { ekso: RootCause, kind: text }
Discover your reference names:
curl -u :PAT \
https://dev.azure.com/your-org/your-project/_apis/wit/fields?api-version=7.1 \
| jq '.value[] | {referenceName, name, type}'
Pass it to apply:
ekso migrate devops apply \
--config migration.config.json \
--process proc_engineering \
--field-map migration.fields.yaml
See Field mapping.
Iterations, Area Paths, Work Item Types
| DevOps | Ekso | Notes |
|---|
| Iteration | DataCycle | Hierarchy flattens in v1. MyProj\Sprint 1\Week 1 becomes a cycle named Sprint 1 / Week 1. Hierarchical cycle support is on the v2 roadmap. |
| Area Path | ConfigLabel (area:Backend/API) + DataItem.Tags | Slash-joined label preserves the path. |
| Work Item Type (Bug, Task, Story, Feature, Epic) | DataItem.Meta.devops_workitemtype | A single Ekso process can hold all work item types. The original type is preserved in Meta for audit. |
Cycles attach to a board on the Ekso side. Pass --board <BOARD_ID> if the tenant has more than one board.
On-prem Azure DevOps Server (TFS)
The same CLI works against on-prem Azure DevOps Server / TFS — point the organisation at the full base URL of your collection:
"devops": {
"organisation": "https://tfs.acme.local/tfs/DefaultCollection",
"personalAccessToken": "..."
}
Collection-scoped PATs work the same way as Azure DevOps Service PATs. The Microsoft TFS SDK bundled with the CLI handles both.
Iron rule — WIQL chunking and 429 retry
WIQL queries return up to 200 work-item IDs per call (Azure cap). The migrator paginates by chunking IDs client-side at 200. The WorkItemTrackingHttpClient.GetWorkItemsAsync call also caps at 200 IDs per request — chunked the same way.
DevOps rate-limit responses surface as VssServiceResponseException with HttpStatusCode==429. The CLI catches this, honours Retry-After, and backs off up to 6 attempts (~64 s of accumulated backoff). Past 6 attempts, exit code is 7.
The DevOps adapter bundles the official Microsoft TFS SDK (Microsoft.TeamFoundationServer.Client + Microsoft.VisualStudio.Services.Client), adding ~30 MB to the standalone Ekso CLI binary. This is the bundled trade-off — single binary, no plugin install. If binary size becomes a constraint, the v2 roadmap includes a plugin model that makes DevOps separately installable.
Troubleshooting DevOps-specific issues
| Symptom | Fix |
|---|
exit 3 — DevOps PAT invalid | Mint a new PAT with Work Items (Read) + Identity (Read) scopes. Check it’s not expired. |
exit 7 — VssServiceResponseException 429 | Wait — DevOps rate limits are tied to TUs (throughput units). Re-run with --resume. |
Service identity filtered (info, not error) | “Project Collection Build Service” etc. is correctly filtered. No action needed. |
Iteration hierarchy flattened | Documented limitation. MyProj\Sprint 1\Week 1 flattens to Sprint 1 / Week 1. |
Work item type not on destination process | Item created; type stored in Meta.devops_workitemtype. Add the type to your Ekso process if you want first-class handling. |
Custom.<FieldName> unknown to field-map | Reference name didn’t match any field on this DevOps project. Run the discovery curl to verify. |
See Troubleshooting for the full per-source error table.
Why migrate to Ekso
Azure DevOps centralises work items, repos, builds, and tests; Ekso focuses on the work-item layer with financial intelligence and AI primitives DevOps doesn’t model. See Ekso vs Azure DevOps for the broader comparison.
Where to next