> ## Documentation Index
> Fetch the complete documentation index at: https://ekso.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Identity resolution

> How ekso migrate maps source-platform users to Ekso users — match-or-create, match-only, migration-bot.

External platforms attribute every comment, worklog, and item to a user. Ekso has to record those authors faithfully or the audit trail breaks. This page explains the three strategies, when to use which, and how to clean up afterwards.

## The three strategies

Pass one of `match-or-create` / `match-only` / `migration-bot` to `apply --user-strategy`:

| Strategy                    | What it does                                                                                                                                                   | Side effects                                                                                     |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| `match-or-create` (default) | For each source user, look for an Ekso user with the same email. If one exists, reuse it. If not, mint a new user (random password, **no invite email sent**). | Tenant gains new users. Original authoring fidelity preserved.                                   |
| `match-only`                | Match by email. Source users with no Ekso match fall back to `--fallback-user`.                                                                                | No new users created. Authoring on items where no match was found rolls up to the fallback user. |
| `migration-bot`             | Force every author to `--fallback-user`.                                                                                                                       | No matching, no creation. All comments and items appear authored by one user.                    |

Pick by deciding which fidelity matters more.

## How matching works

The CLI matches by **email address**, case-insensitive. The match check is a single `GET /api/user` against your Ekso tenant per unique source-user-email; the result is cached in the migration's `IdMap` so the same email isn't matched twice.

There is no fuzzy matching, no display-name fallback. Two source users with the same email get treated as the same Ekso user (which is usually what you want — the same person used both Jira and DevOps). Two source users with no email get treated separately.

The match runs once per unique email at the start of `apply`. If a source user is created on the source platform mid-migration (rare), they show up as "no match" and follow the strategy's fallback path.

## How `match-or-create` mints users

When the strategy is `match-or-create` and a source user has no Ekso match, the CLI calls `POST /api/user` with:

* `email` = the source user's email
* `name` = the source user's display name
* `active` = `true`
* A random password generated server-side
* `inviteOnCreate` = `false` — **no welcome email is sent**

Why no email? A 5,000-user migration would otherwise blast 5,000 strangers with "Welcome to Ekso" emails the day before they were planning to be onboarded. The `inviteOnCreate=false` path lets you mint the users now, then run a deliberate communication later.

The minted users have a random password they don't know. Send them through the password-reset flow (or your SSO setup) when you're ready for them to actually sign in.

## When to use which

**Default to `match-or-create`** unless you have a reason not to. It preserves authorship without spamming users.

```bash theme={null}
ekso migrate jira apply --config migration.config.json --process proc_eng
# (--user-strategy match-or-create is the default)
```

**Use `match-only` when** you specifically don't want to mint users:

* You're piloting the migration on a sandbox tenant and don't want test users polluting your production directory.
* Your tenant uses SSO and you provision users centrally — the migrator shouldn't create them.
* You only need a subset of authoring fidelity preserved (the matched ones).

```bash theme={null}
ekso migrate jira apply \
    --config migration.config.json \
    --process proc_eng \
    --user-strategy match-only \
    --fallback-user user_migration_admin
```

Items and comments authored by source users with no Ekso match get attributed to `user_migration_admin`. The original source-user identity is preserved in the item's `Meta` so you can audit later.

**Use `migration-bot` when** authoring fidelity doesn't matter:

* The source platform's users aren't real people (synthetic test tenant).
* You're consolidating archival data and don't care who wrote what.
* You want one user to "own" everything for permission simplicity.

```bash theme={null}
ekso migrate jira apply \
    --config migration.config.json \
    --process proc_eng \
    --user-strategy migration-bot \
    --fallback-user user_migration_bot
```

Every comment, every item, every worklog appears authored by `user_migration_bot`. The original source-user identity is still preserved in `Meta`.

## Source-specific quirks

| Source           | Behaviour                                                                                                                                                                                                             |
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Jira**         | Atlassian users have email; `match-or-create` is reliable. On Data Center / Server, local (non-SSO) accounts may have no visible email, so some users fall back to create rather than match.                          |
| **Linear**       | Linear users always have email; `match-or-create` is reliable.                                                                                                                                                        |
| **Azure DevOps** | Service identities (`[Project]\Project Collection Build Service`, etc.) are filtered out at collect time — they're not real users and won't appear as authors.                                                        |
| **Zendesk**      | End-users (customers) and agents (staff) are imported. End-users get tagged `migrated-from:zendesk-enduser`; agents get `migrated-from:zendesk-agent`. Anonymous end-users (no email) follow `--user-strategy` rules. |
| **Gemini**       | All Gemini users have email; `match-or-create` is reliable.                                                                                                                                                           |

## Anonymous users

If a source user has no email at all (some Zendesk end-users, some legacy DevOps accounts):

* `match-or-create`: minted with a placeholder email like `<source-id>@anon.<source>.local`. Filterable later by tag.
* `match-only`: rolls up to `--fallback-user`.
* `migration-bot`: rolls up to `--fallback-user`.

The placeholder email is *not* a real address — these users can't receive password resets without an admin updating their profile first.

## Tagging migrated users

Every user the CLI mints (or matches) is stamped with a tag of the form `migrated-from:<source>` so you can filter, audit, or bulk-update them after the fact. Examples:

* `migrated-from:jira` — minted from a Jira migration
* `migrated-from:linear`
* `migrated-from:zendesk-enduser`, `migrated-from:zendesk-agent`
* `migrated-from:devops`
* `migrated-from:gemini`

You can find them later via `ekso user list --tag migrated-from:jira` or directly in the Ekso admin UI.

## Post-migration cleanup

After apply succeeds:

1. **Audit the user list.** `ekso user list --tag migrated-from:<source>` shows every user touched by the migration.
2. **Send password resets** to users you actually want to onboard. Skip the rest — they're filed for audit-trail purposes and don't need to sign in.
3. **Remove placeholder-email users** if you don't need them. Their original source identity is preserved in their profile metadata for audit.
4. **Rotate the `--fallback-user` credentials.** If you used `migration-bot`, that account briefly held a lot of authority. Rotate it or disable it.

## What's preserved on items

Even when authoring rolls up to a fallback user, the original source identity is preserved on each item, comment, and time entry in `Meta`. Example:

```json theme={null}
{
  "Meta": {
    "jira_reporter": "alice@old-company.com",
    "jira_reporter_name": "Alice Liddell",
    "jira_reporter_account_id": "5b10ac8d82e05b22cc7d4ef5",
    "original_created_at": "2024-08-21T16:33:21.000+0000"
  }
}
```

This means even a `migration-bot` run preserves enough information to reconstruct authorship later if you change strategies.

## Where to next

* **[Command reference](/cli/migrate/command-reference)** — full flag surface.
* **[Field mapping](/cli/migrate/field-mapping)** — `migration.fields.yaml` shape.
* **[Troubleshooting](/cli/migrate/troubleshooting)** — recovering from a partial apply.
