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.

If you’re a Countersoft Gemini customer reading this — welcome. Ekso is built by the same team that built Gemini. The migration story is the upgrade story: every concept you rely on in Gemini has a clean home in Ekso, and the migrator was designed with your install in mind. ekso migrate gemini pulls projects, issues, comments, attachments, time entries, sprints, versions, and components from Countersoft Gemini into your Ekso tenant. Two commands — collect and apply. Read Migrate overview and Before you start first.

What gets imported

Because the Gemini schema and Ekso’s canonical migration schema were designed by the same team, the mapping is the cleanest of any source — most fields transfer 1:1.
Gemini conceptEkso shape
ProjectDataContainer (Code = project.code, Name = project.name)
IssueDataItem
CommentDataAnnotation
AttachmentDataFile (multipart upload)
Time entryDataItem.Time[] (in the same item POST — billable flag preserved)
ComponentConfigLabel (prefix component:) + item Tags
Version (release / fix)DataCycle
SprintDataCycle
Custom fieldDataItem.Field[] (via --field-map) or Meta
Resource (watcher)DataItem.Meta.gemini_resources[]
Follower (subscriber)preserved in Meta
Link (parent/child, related, duplicate)DataLink
User / GroupDataUser
Authoring fidelity preserved on every comment, every time entry, every issue.

What does NOT get imported

  • Workflow definitions / state machines. v1 imports the current status of each issue. State-transition rules don’t migrate — Ekso’s process system is a successor; redesign the workflow at migration time.
  • License data. Out of scope for the data migration; that’s a sales conversation.
  • Saved reports / queries. Re-author on the Ekso side.

Before you start

Pre-flight checklist on top of the general one:
  • A running Gemini install (v7+ recommended).
  • One of:
    • SQL access to the Gemini DB (recommended — fastest, most complete), or
    • API access to the Gemini REST API (works behind the firewall).
You don’t need both — pick whichever your network and policies allow. See “Two modes” below. Add a gemini block to your migration.config.json:
{
  "ekso": { "tenant": "acme", "apiKey": "ek_live_..." },

  "source": "gemini",

  "gemini": {
    "connectionMode": "sql",

    "connectionString": "Server=gemini-db.local;Database=Gemini761;User Id=migrate;Password=...;TrustServerCertificate=True;",

    "url":      "https://gemini.acme.local",
    "username": "manager",
    "apiKey":   "..."
  }
}
If connectionMode=sql, url/username/apiKey are ignored. If connectionMode=api, connectionString is ignored. You can configure both and switch via --connection-mode at runtime. Env-var overrides for CI:
  • EKSO_MIGRATE_GEMINI_KEY overrides gemini.apiKey.
  • EKSO_MIGRATE_GEMINI_DB_PWD is read by the connection string when interpolated as ${EKSO_MIGRATE_GEMINI_DB_PWD}.

Two modes — when to use which

ModeWhenProsCons
SQL Server direct (connectionMode: "sql")The CLI can reach the Gemini DB on TCP 1433.Fastest. Reads attachment bytes directly from varbinary / FILESTREAM. Every column is queryable.Many Gemini installs don’t expose SQL externally. Needs DB read credentials.
REST API (connectionMode: "api")The CLI can reach the Gemini web app over HTTPS.Works through firewalls. No DB credentials. Schema-stable.Slower for large data sets. Some internal fields aren’t exposed.
Recommendation: SQL mode for migrations done by the Gemini admin on-site; API mode for everyone else. Override the configured mode at runtime:
ekso migrate gemini collect --connection-mode api ...
ekso migrate gemini apply   --connection-mode api ...

Step 1 — list projects

ekso migrate gemini list-projects \
    --config migration.config.json \
    --tenant acme
Sample output:
NAME              CODE   ID    USERS
Platform          PLAT   1     14
Mobile            MOB    2     7
If this fails with a SQL connection error, switch to --connection-mode api.

Step 2 — collect

ekso migrate gemini collect \
    --config migration.config.json \
    --project PLAT \
    --tenant acme
Repeat --project for multiple. Sample run:
fetching projects... 1 fetched (SQL mode)
fetching PLAT issues... 3214/3214  ok
fetching comments... 8104/8104  ok
fetching time entries... 9421/9421  ok
fetching attachments... 481/481  ok (varbinary read direct)
saved cache: ~/.ekso/migrate/gemini-2026-04-29T143205.sqlite
Useful flags:
  • --connection-mode {sql,api} — override the configured mode.
  • --no-attachments — skip downloads.
  • --no-comments — skip comments.
  • --exclude-closed — skip items in final-state statuses.
  • --resume — pick up where a killed collect left off.
SQL mode is fast — a 10K-issue project usually completes in 5–10 minutes including attachments. API mode is slower, especially for attachment-heavy projects.

Step 3 — dry-run apply

ekso migrate gemini apply \
    --config migration.config.json \
    --process proc_engineering \
    --tenant acme \
    --dry-run

Step 4 — apply for real

ekso migrate gemini apply \
    --config migration.config.json \
    --process proc_engineering \
    --tenant acme
If interrupted, re-run with --resume.

Time tracking — the strongest fidelity point

Gemini has first-class time tracking, and Ekso preserves it natively. Every Gemini time entry becomes one row in DataItem.Time[] on its parent item — written in the same POST /api/item call that creates the item. No separate POST, no time-tracking applier. The billable flag is preserved on each entry’s Meta.source_billable. After migration:
  • ekso time list --item <id> lists every imported entry.
  • ekso time list --user <id> lists every entry by user, across all migrated projects.
  • Standard Ekso reporting (profitability, cost-center, billable hours) works on the imported data the same way it works on natively-created data.
This is Gemini’s strongest fidelity point — none of the other adapters preserve time history this completely, because none of the other source platforms model it as well.

Identity resolution for Gemini

Gemini users have email — --user-strategy match-or-create is reliable. No special handling needed. Read Identity resolution.

Custom fields for Gemini

Gemini custom fields are accessed by name. Map them to Ekso process fields:
gemini:
  PullRequestUrl: { ekso: PullRequestUrl, kind: text }
  Severity:
    ekso: Severity
    kind: picker
    picker:
      Critical: P0
      High:     P1
      Medium:   P2
      Low:      P3
Pass it to apply:
ekso migrate gemini apply \
    --config migration.config.json \
    --process proc_engineering \
    --field-map migration.fields.yaml
In SQL mode, custom field values come from dbo.IssueCustomFields. In API mode, they come from the issue payload. Both modes route to the same Ekso Field[] slot. See Field mapping.

Sprints, Versions, Components

GeminiEksoNotes
SprintDataCycleAlways — no flag.
Version (release / fix)DataCycleSprint-shaped (name + dates + member items).
ComponentConfigLabel (component:Backend) + DataItem.TagsAlways — no flag.
Cycles attach to a board on the Ekso side. Pass --board <BOARD_ID> if the tenant has more than one board.

Iron rule — dual-mode dispatch

The Gemini adapter holds two repository implementations: SqlSrvGeminiRepository (T-SQL queries) and ApiGeminiRepository (HTTP client). The mode is fixed at adapter construction — once you pick SQL or API, the same mode is used for the entire run. If you need to switch modes mid-migration (e.g. SQL for collect, API for re-collect on a different machine), run a fresh collect in the new mode. The cache files are interchangeable on apply — apply doesn’t care which mode produced the cache. The recommended path is SQL mode whenever your network allows it — it’s faster and pulls full-fidelity data including attachment bytes directly from the DB. API mode is the firewall-friendly fallback.

Older Gemini versions

The migrator targets Gemini v7+ schemas. Older versions (v5, v6) work in API mode if your install’s API supports it. Schema drift is surfaced in Meta.gemini_unmapped_columns — the migration completes; data shape just differs slightly. v2 TODO: explicit version-aware schema modules if a customer needs first-class v5/v6 support.

Multiple Gemini installations on one SQL Server

If your SQL Server hosts multiple Gemini DBs, set the right Database= in the connection string:
"connectionString": "Server=gemini-db;Database=Gemini761_Production;..."

Self-hosted Ekso

Ekso runs self-hosted as well as SaaS. If you’ve been running Gemini on-prem and want to keep that posture, deploy Ekso to the same network and migrate locally — neither the source data nor the Ekso credentials need to leave your infrastructure.

Troubleshooting Gemini-specific issues

SymptomFix
SQL connection refusedNetwork can’t reach the DB. Switch to --connection-mode api, or run from a host inside the corporate network.
SQL credentials invalidDB user lacks read on Gemini tables. Grant db_datareader.
API 401Wrong / disabled API key. Get a fresh one from Gemini admin.
Schema drift — unknown columnOlder or newer Gemini schema than the supported set. Surfaced in Meta.gemini_unmapped_columns; migration still completes.
Mode mismatch — SQL configured but only API accessPass --connection-mode api at the command line.
See Troubleshooting for the full per-source error table.

Why move to Ekso

Ekso is what the Gemini team would build today — same DNA, modern stack, AI native, financial intelligence built in. Self-host or SaaS. See Ekso vs Countersoft Gemini for the full upgrade story.

Where to next