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 concept | Ekso shape |
|---|
| Project | DataContainer (Code = project.code, Name = project.name) |
| Issue | DataItem |
| Comment | DataAnnotation |
| Attachment | DataFile (multipart upload) |
| Time entry | DataItem.Time[] (in the same item POST — billable flag preserved) |
| Component | ConfigLabel (prefix component:) + item Tags |
| Version (release / fix) | DataCycle |
| Sprint | DataCycle |
| Custom field | DataItem.Field[] (via --field-map) or Meta |
| Resource (watcher) | DataItem.Meta.gemini_resources[] |
| Follower (subscriber) | preserved in Meta |
| Link (parent/child, related, duplicate) | DataLink |
| User / Group | DataUser |
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
| Mode | When | Pros | Cons |
|---|
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
| Gemini | Ekso | Notes |
|---|
| Sprint | DataCycle | Always — no flag. |
| Version (release / fix) | DataCycle | Sprint-shaped (name + dates + member items). |
| Component | ConfigLabel (component:Backend) + DataItem.Tags | Always — 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
| Symptom | Fix |
|---|
SQL connection refused | Network can’t reach the DB. Switch to --connection-mode api, or run from a host inside the corporate network. |
SQL credentials invalid | DB user lacks read on Gemini tables. Grant db_datareader. |
API 401 | Wrong / disabled API key. Get a fresh one from Gemini admin. |
Schema drift — unknown column | Older or newer Gemini schema than the supported set. Surfaced in Meta.gemini_unmapped_columns; migration still completes. |
Mode mismatch — SQL configured but only API access | Pass --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