Development
Commands you'll run dozens of times a day while building.
orion dev
Run your app locally and let the host EMR iframe it for live preview. The CLI starts a Vite dev server, opens a Cloudflare tunnel, and registers the tunnel with your sandbox tenant.
orion devThe CLI prints the local Vite URL, the resolved tunnel URL, and registers the tunnel with your sandbox tenant. Save a file in your editor to trigger HMR inside the iframe.
Flags
| Flag | Default | Purpose |
|---|---|---|
-p, --port <port> | 5173 | Dev server port. |
--no-tunnel | — | Skip the tunnel. Only useful if you've configured the sandbox to reach localhost directly (rare). |
The CLI bundles cloudflared via the npm cloudflared dev dependency and invokes that binary directly. There's a --tunnel-provider flag that's parsed for forward compatibility, but cloudflared is the only provider currently wired through.
Requires
orion config sandbox must be set. orion dev won't fall back to the home tenant — this is intentional, so dev code never runs against your home tenant. See Host vs Sandbox.
orion build
Run your production build into dist/.
orion buildFlags
| Flag | Default | Purpose |
|---|---|---|
-o, --out-dir <dir> | dist | Output directory. Override only if your vite.config.ts already does. |
--no-minify | — | Disable minification (useful when chasing a stack trace through the bundle). |
--sourcemap | — | Emit source maps. |
orion validate
Run all the checks orion publish runs, but stop before authentication and upload — manifest schema, bundle layout, scope rules, archive forbidden-paths. Catches issues early so you fix them before authentication and upload.
orion validateThe CLI prints one section per check group (Manifest (orion-app.json), Bundle (dist/index.js), Source archive) followed by a summary line — 0 problems found., 0 problems, 1 warning., or 2 problems, 0 warnings.
publish runs validate too — running it explicitly during development gives you faster feedback.
Schema checks include the extensions.writableExtensions block when present: required fields (key, title, valueType, appliesTo), kebab-case key shape, the 9-value-type allow-list, duplicate keys across entries, and the 50-entry manifest cap. Mismatches surface with the offending index and field name — fix in orion-app.json and rerun.
Flags
| Flag | Purpose |
|---|---|
--manifest | Validate the manifest only; skip bundle + source-archive checks. Useful for checking a manifest before npm run build. |
--json | Emit findings as newline-delimited JSON, one record per line. CI-friendly. |
orion doctor
Environment + manifest health check. Validates Node/npm versions, working-directory config, manifest shape, build artifacts, and (optionally) network reachability of the host tenant.
orion doctorSections checked: Environment, Authentication (local), Working directory, Manifest, Build, and (with --network) Identity. Each check is ✓ (pass), ! (warn), or ✗ (fail). A ✗ exits non-zero.
Flags
| Flag | Purpose |
|---|---|
--json | Machine-readable JSON output for CI scripting. |
--network | Opt-in remote-identity verification. Otherwise the doctor stays local-only. |
orion generate <kind> <id>
Aliased as orion g. Scaffold a new extension into the current app — manifest entry plus the corresponding source file. The available mount points, triggers, and placements match what the host EMR currently supports.
orion generate page reports --path /reports
orion generate block status-bar --target encounter-detail/status-bar --action after
orion generate widget patient-vitals --mount-point patient-detail-sidebar
orion generate action send-summary --trigger patient-context-menu
orion generate nav reports --placement sidebar --path /reports --icon FileTextKinds
| Kind | Required flags | Optional flags |
|---|---|---|
page <id> | — | --path <path> (default /<id>), --layout app|fullscreen|modal (default app) |
block <id> | --target <name> | --action before|after (default before) |
widget <id> | --mount-point <slot> | — |
action <id> | --trigger <name> | — |
nav <id> | --placement <name>, --path <path> | --icon <lucide-icon> (default LayoutDashboard) |
All subcommands accept --force to skip catalog/collision/overwrite checks.
For the field shape of each manifest entry generate writes (and how to hand-edit one), see Manifest schema.
What it writes
For each invocation, generate writes two things:
- An entry under the matching
extensions.pages[]/extensions.blocks[]/extensions.widgets[]/extensions.actions[]/extensions.navigation[]array inorion-app.json. - A starter source file in the matching plural directory (
src/pages/,src/blocks/,src/widgets/,src/actions/, orsrc/nav/) named<PascalCaseId>.tsx(.tsfor actions). The generator also adds an import for the new component to your entry file (src/main.tsxor equivalent) — wire the route or mount manually.