ekso migrate command. Each per-source page links here for the global flag surface so the source-specific pages can stay focused on the source-specific quirks.
The four commands
Every source supports the same four verbs:| Command | What it does |
|---|---|
list-* | Read-only. Enumerate the source containers (projects, teams, orgs) the configured credentials can see. Useful for verifying setup. |
collect | Pull source data into a local SQLite cache. Network: source-only. No Ekso writes. |
apply | Walk the cache and write to the Ekso REST API. Network: Ekso-only. Idempotent — re-runs skip already-applied rows. |
status | Read the most recent cache file and print row counts per table, plus IdMap progress. No network. |
list-* verb is named per-source to match the customer’s mental model:
ekso migrate jira list-projectsekso migrate linear list-projectsekso migrate devops list-projectsekso migrate zendesk list-projectsekso migrate gemini list-projects
Global flags (every migrate command)
These flags work on everyekso migrate <source> <verb> invocation, alongside the standard CLI flags from Configuration (--url, --api-key, --format, --quiet, etc.).
| Flag | Description | Default |
|---|---|---|
--config <FILE> | Path to the migration config JSON. Holds source-platform credentials. | ./migration.config.json |
--working-dir <DIR> | Where to put the SQLite cache. | ~/.ekso/migrate/ |
collect flags
| Flag | Description | Required? |
|---|---|---|
--project <KEY> | Source container to collect. Repeat for multiple. | Required for Jira / Linear / DevOps / Gemini; optional for Zendesk (omit to collect every organisation under the configured Zendesk subdomain). |
--no-attachments | Skip downloading binary attachments. Smaller and faster cache. | No |
--no-comments | Skip fetching comments. | No |
--exclude-closed | Filter closed items at the source-API layer (Jira, Zendesk, Gemini). | No |
--resume | Resume an interrupted collect. Skips containers already cached. | No |
--edition <cloud|datacenter|server> | (Jira only) Override Jira edition detection (default: auto-detect via serverInfo). | No |
--connection-mode <MODE> | (Gemini only) sql or api. Overrides gemini.connectionMode in the config. | No |
apply flags
| Flag | Description | Required? |
|---|---|---|
--process <PROCESS_ID> | Destination Ekso process. Every migrated item attaches to this process. | Yes |
--board <BOARD_ID> | Destination board. Cycles attach here. Auto-discovered when the tenant has exactly one board. | If multiple boards |
--field-map <FILE> | YAML file mapping source custom fields to Ekso process fields. See Field mapping. | No |
--user-strategy <STRATEGY> | Identity resolution: match-or-create, match-only, migration-bot. | No (default: match-or-create) |
--fallback-user <USER_ID> | User ID used by match-only and migration-bot when there’s no source match. | If using match-only or migration-bot |
--dry-run | Walk the cache and log what would happen without writing to Ekso. | No |
--resume | Skip rows that already have an ID-map entry. Picks up where a failed apply left off. | No |
--cache <FILE> | Path to a specific cache file. Default: most recent <source>-*.sqlite in the working dir. | No |
--user-strategy does.
status flags
status is read-only and has no source-specific flags. It reads the most recent cache file (or --cache <FILE>) and prints:
- Schema version of the cache
- Row counts per
Source*table (issues, comments, attachments, etc.) - IdMap progress per entity kind (how many items / users / files have been applied)
- Whether the cache is fresh (collect-only) or partially / fully applied
A typical run
Idempotency model
Everyapply writes (source-id → Ekso-id) pairs into an IdMap table inside the cache. A re-run reads the IdMap before each write and skips rows that already have an Ekso ID. This means:
- Running
applytwice in a row is a no-op the second time. - A killed
apply(Ctrl-C, network blip, machine reboot) can resume cleanly with--resume. - Running
applywithout--resumeafter a partial run is still safe — it just re-checks every row and skips the applied ones.--resumeskips the per-row IdMap lookup for speed.
collect — each collect writes a new timestamped file).
Per-cache schema versioning
Every cache file is stamped with aschema_version. If you upgrade the CLI between collect and apply and the schema version changes, apply refuses to run and tells you to re-collect. This is intentional — silent data shape mismatches are worse than an explicit “please re-collect” error.
Where to next
- Identity resolution — pick the right
--user-strategy. - Field mapping — write
migration.fields.yaml. - Troubleshooting — exit codes and recovery.
- Per-source: Jira / Linear / Azure DevOps / Zendesk / Gemini.