Skip to main content

Documentation Index

Fetch the complete documentation index at: https://ekso.dev/llms.txt

Use this file to discover all available pages before exploring further.

A short checklist before you run any ekso migrate command. None of these are optional.

Prerequisites

You need:
  1. An Ekso tenant. If you don’t have one yet, sign up at ekso.app and pick a subdomain (e.g. acme.ekso.app).
  2. An Ekso API key with admin scope. Mint one in the admin surface — ekso migrate writes containers, items, users, files, and labels, so it needs admin write permissions for the duration of the run.
  3. A destination Ekso process. The migrator writes every item to a single DataProcess you choose at apply time via --process <process-id>. Create the process in Ekso first (or pick an existing one). The Apply layer auto-creates any custom fields you reference in your field-map; system fields (Status, Priority, Severity, etc.) must already exist on the process.
  4. A destination Ekso board. Cycles need a board to attach to. Pass --board <board-id> at apply time, or let the CLI auto-discover when the tenant has exactly one board.
  5. Read access to the source platform. Whatever credential type the source needs — API token, PAT, SQL user, GraphQL key. See the per-source page for shape:
    • Jira — Atlassian email + API token
    • Linear — Personal API key
    • Azure DevOps — Personal Access Token (PAT)
    • Zendesk — Email + API token
    • Gemini — SQL connection string or API key
  6. The Ekso CLI itself. Run ekso --version to confirm. If it’s not installed, follow Installation.

The configuration file

Every ekso migrate command takes --config <FILE> (default: ./migration.config.json). This is the file that holds your source-platform credentials. Start from the sample shipped with the CLI source tree:
{
  "_comment": "Copy this to migration.config.json and fill in real values. The working file is gitignored. Do not commit secrets.",

  "workingDirectory": "~/.ekso/migrate",

  "ekso": {
    "tenant": "acme",
    "apiKey": "ek_live_..."
  },

  "source": "jira",

  "jira": {
    "url": "https://acme.atlassian.net",
    "username": "[email protected]",
    "apiToken": "ATATT3..."
  },

  "linear": {
    "apiKey": "lin_api_..."
  },

  "devops": {
    "organisation": "your-org",
    "personalAccessToken": "..."
  },

  "zendesk": {
    "url": "https://acme.zendesk.com",
    "email": "[email protected]",
    "apiToken": "..."
  },

  "gemini": {
    "connectionMode": "api",
    "connectionString": "Server=gemini-db;Database=Gemini761;TrustServerCertificate=True;",
    "url": "https://gemini.acme.local",
    "username": "manager",
    "apiKey": "..."
  },

  "fieldMap": "migration.fields.yaml",

  "attachments": { "import": "db" }
}
You only need the block for the source you’re migrating from — the others can stay as placeholders.

Secrets policy

This file holds live credentials for both the source platform and your Ekso tenant. Treat it like any other secret:
  • Never commit migration.config.json. Add it to your .gitignore. The Ekso repo’s own gitignore already blocks migration.config.json, *.migration.json, and migration.*.json patterns.
  • Use environment variables for CI/CD. Each per-source token has an env-var override that takes precedence over the file:
    SourceEnv varOverrides
    JiraEKSO_MIGRATE_JIRA_TOKENjira.apiToken
    LinearEKSO_MIGRATE_LINEAR_KEYlinear.apiKey
    Azure DevOpsEKSO_MIGRATE_DEVOPS_PATdevops.personalAccessToken
    ZendeskEKSO_MIGRATE_ZENDESK_TOKENzendesk.apiToken
    GeminiEKSO_MIGRATE_GEMINI_KEY, EKSO_MIGRATE_GEMINI_DB_PWDgemini.apiKey, password in gemini.connectionString
    In CI, set the env vars and ship a config file with placeholder strings. The CLI reads env first, file second.
  • Rotate source-platform tokens after the migration finishes. A migration credential needs read-everything scope on the source; that’s a lot of authority to leave hanging around. Rotate the source-platform credential as soon as the apply phase succeeds. The Ekso API key can stay (or rotate it too — your call).
  • The cache file is local-only. ~/.ekso/migrate/<source>-<timestamp>.sqlite holds the data you fetched from the source platform — descriptions, comment bodies, attachment bytes. Treat the cache file the same way you’d treat the source data itself: don’t paste it into a public bug tracker, don’t commit it, delete it once apply has succeeded.

What the cache contains

The SQLite cache holds raw source data — every comment body, every attachment blob, every assignee email. It is not encrypted at rest. If you’re handling a regulated data set, run the migration on an encrypted volume and delete the cache file once apply has succeeded. The cache does not contain credentials. Tokens stay in the config file or environment, never in the SQLite file.

Verifying you’re set up

Before kicking off a real collect, prove your credentials work with a read-only call:
# Jira — should print your accessible projects
ekso migrate jira list-projects --config migration.config.json --tenant acme

# Linear — should print your teams
ekso migrate linear list-teams --config migration.config.json --tenant acme

# Azure DevOps — should print your projects
ekso migrate devops list-projects --config migration.config.json --tenant acme

# Zendesk — should print your orgs (or empty if your instance is flat)
ekso migrate zendesk list-orgs --config migration.config.json --tenant acme

# Gemini — should print your projects
ekso migrate gemini list-projects --config migration.config.json --tenant acme
If any of those fail with an auth error (exit code 3), fix the credentials before continuing. If they work, you’re ready for collect.

Where to next