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

# Synheart CLI reference

> Command reference for synheart-cli — runtime artifacts, mock streams, local platform, and HSI export receiver

`synheart-cli` is the developer command-line interface for the Synheart platform. Use it to:

* Authenticate with `platform.synheart.ai` and download runtime artifacts.
* Generate local mock wearable streams for app development and QA.
* Run local platform endpoints for consent and ingest testing.
* Receive HSI exports from a Synheart mobile client over your local network.

<Note>
  For installation, see [Install the CLI](/setup/install-cli). For the full onboarding flow (account, auth, runtime), see [Setup overview](/setup/overview).
</Note>

## Developer Workflows

<CardGroup cols={3}>
  <Card title="SDK Artifact Install" icon="download">
    Authenticate, install SDK artifacts, and lock/sync exact versions across machines.
  </Card>

  <Card title="Local App Testing" icon="terminal">
    Generate mock Whoop/Garmin payloads and optional HSI output over WebSocket/SSE/UDP.
  </Card>

  <Card title="Offline Platform" icon="server">
    Run local consent+ingest endpoints and receive HSI exports from mobile apps.
  </Card>
</CardGroup>

## Command Groups

| Group           | Commands                                                                           | Purpose                                                                        |
| --------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| Authentication  | `login`, `logout`, `whoami`, `auth status`, `auth refresh`                         | Account + token management                                                     |
| SDK artifacts   | `install`, `sync`, `env`                                                           | Deterministic artifact installation per project                                |
| Runtime         | `runtime current`, `runtime upgrade`                                               | Inspect / refresh the runtime pinned in this project                           |
| Mock simulation | `mock start`, `mock record`, `mock replay`, `mock list-scenarios`, `mock describe` | Local sensor stream generation and replay                                      |
| Local services  | `local`, `receiver`                                                                | Offline platform testing and mobile export intake                              |
| Diagnostics     | `doctor`, `version`, `env`                                                         | Environment validation, identity, runtime metadata                             |
| Knowledge       | `explain`                                                                          | In-binary primers for Synheart concepts (HSI, HRV, recovery, wear, consent, …) |
| Project config  | `config show`, `config path`                                                       | Inspect the resolved project configuration from `.synheart/config.yaml`        |
| AI integration  | `mcp serve`                                                                        | Expose CLI verbs as MCP tools for Claude Code, Cursor, Claude Desktop          |
| Self-update     | `update`, `update --check`, `update --rollback`                                    | Check, apply, or roll back a CLI release                                       |

## Authenticate

```bash theme={null}
synheart login            # device-flow login against api.synheart.ai
synheart whoami           # active account: email, org, plan tier
synheart auth refresh     # force a token rotation (pick up new server-side claims)
synheart logout           # clear the local token
synheart env              # print the resolved environment + identity blocks
synheart env --format json
```

`synheart login` opens a browser to the platform login page and stores
an access token at `~/.synheart/credentials`. All other commands that
hit the network (`install`, `sync`, mock scenario sync) require an
active session; commands that only touch the local machine
(`mock start`, `local`, `receiver`, `version`, `doctor`) do not.

`synheart whoami` decodes the locally-cached JWT — no network call —
and prints the email, org, and plan tier carried by the access token.
`synheart auth refresh` forces a rotation if you need to re-pull
server-side claims that changed (plan upgrade, org switch).

If a network command fails with one of the auth error codes, `synheart auth status` walks the storage chain — file path, keyring availability, token expiry — and tells you which step failed. Same JSON shape (`--format json`) is exposed as the `synheart_auth_status` MCP tool.

| Code          | Meaning                          | Recovery                                                         |
| ------------- | -------------------------------- | ---------------------------------------------------------------- |
| `SH-AUTH-001` | Not logged in                    | `synheart login`                                                 |
| `SH-AUTH-003` | Credentials file unreadable      | `synheart auth status` to see the path / permissions             |
| `SH-AUTH-004` | Keyring access failed            | Unlock the OS keyring; retry                                     |
| `SH-AUTH-009` | Refresh token expired or invalid | `synheart login` (the stored token is dead; retrying won't help) |
| `SH-AUTH-010` | Refresh failed transiently       | Retry once; if it persists, escalate to `auth status`            |

## Runtime artifact workflow

Use this flow to bootstrap or update the Synheart Runtime native binary
in your app repo. The CLI manages the **runtime artifact only** — the
SDK packages themselves are installed through the host platform's
package manager (pub.dev, Maven Central, Swift Package Manager).

```bash theme={null}
synheart login
synheart install runtime
synheart sync
synheart env
```

### Install a specific channel or version

```bash theme={null}
synheart install runtime --channel latest
synheart install runtime --version 1.2.3
```

### Runtime variants

The runtime ships in three variants tied to plan entitlement:

| Variant  | Who gets it                                           |
| -------- | ----------------------------------------------------- |
| `edge`   | Default for free / pro plans                          |
| `stable` | Locked-down builds for production deployments         |
| `lab`    | Research / experimental builds (requires entitlement) |

Without `--variant`, the registry picks the variant your plan
entitles. Pass `--variant edge|stable|lab` to override (subject to
entitlement — the server rejects requests for variants you don't have
access to with a typed error).

```bash theme={null}
synheart install runtime --variant stable
synheart install runtime --variant lab --channel latest
```

The variant is recorded in `synheart.lock` so `sync` always pulls the
same one.

### Inspect or refresh the pinned runtime

```bash theme={null}
synheart runtime current             # what's pinned in this project's lockfile
synheart runtime current --format json
synheart runtime upgrade             # re-fetch latest, preserving the pinned variant
```

`runtime upgrade` is `install runtime` plus "keep the variant from the
lockfile" — useful when you just want to bump the version without
changing edge/stable/lab. Returns `SH-RT-NOLOCK` if there's no
lockfile to upgrade from.

### `synheart.lock`

`synheart install` writes a `synheart.lock` next to your project root.
The lockfile pins the exact runtime version, channel, and per-platform
artifact hashes that were resolved. Commit it.

`synheart sync` reads the lockfile and reinstalls byte-for-byte — no
new resolution happens. Run `synheart sync` in CI so every build pulls
the same runtime your developers built against.

```bash theme={null}
synheart sync             # reinstall exactly what synheart.lock pins
synheart sync --check     # exit non-zero if anything would change
```

### Where runtime artifacts land

| Project type      | Path                                                    |
| ----------------- | ------------------------------------------------------- |
| Flutter (iOS)     | `ios/Frameworks/SynheartRuntime.xcframework/`           |
| Flutter (Android) | `android/src/main/jniLibs/<abi>/libsynheart_runtime.so` |
| Swift Package     | `.build/synheart/SynheartRuntime.xcframework/`          |
| Kotlin / JVM      | `build/synheart/jniLibs/<abi>/`                         |
| Standalone        | `~/.synheart/install/runtime/<version>/<platform>/`     |

`synheart install` auto-detects project type by walking up from the
current directory looking for `pubspec.yaml`, `Package.swift`, or
`build.gradle.kts`. Override with `--project-type` if needed.

## Mock simulation

`synheart mock` generates synthetic vendor streams locally so you can
develop and QA your app without a real wearable. The CLI streams **raw
vendor-formatted JSON** (the same shape WHOOP / Garmin webhooks emit);
HSI transformation happens inside the SDK runtime in your app, not in
the CLI.

```bash theme={null}
synheart mock start                                  # default: whoop / baseline scenario
synheart mock start --vendor garmin --scenario workout
synheart mock start --rate 100hz --duration 5m
synheart mock start --seed 42                        # deterministic output for tests
```

Default endpoints:

* WebSocket: `ws://127.0.0.1:8787`
* SSE: `http://127.0.0.1:8788/events`
* UDP: `127.0.0.1:8789`

Listen with whichever transport your app uses; all three carry the
same payload.

### Record and replay

Capture a live mock stream to disk and replay it deterministically
later — useful for regression tests that need a fixed stream.

```bash theme={null}
synheart mock record --vendor whoop --duration 15m --out session.ndjson
synheart mock replay --in session.ndjson --speed 2.0 --loop
```

`record` and `replay` accept the same transport flags as `start`
(`--port`, `--host`, `--web`).

### Scenario inspection

```bash theme={null}
synheart mock list-scenarios            # all scenarios across all vendors
synheart mock list-scenarios --vendor whoop
synheart mock describe baseline         # required scenario name argument
```

A scenario is a named time-series profile (e.g. `baseline`, `workout`,
`recovery_high`, `stress_event`). `describe` prints the metadata —
duration, signal envelope, expected event mix — so test authors can
pick the right profile.

## Local platform server

`synheart local` mirrors the cloud's consent + ingest endpoints on
`127.0.0.1`. Use it for offline app development — your SDK can post
ingests, fetch consent tokens, and exercise the full cloud flow
without burning real platform quota or needing network.

Defaults:

| Setting           | Default                          |
| ----------------- | -------------------------------- |
| Port              | `8083`                           |
| API key           | `mock-dev-api-key`               |
| HMAC secret       | `mock-dev-hmac-secret`           |
| Consent profiles  | loaded from `data/profiles.json` |
| Persisted ingests | `~/.synheart/local/ingested/`    |

```bash theme={null}
synheart local                                            # plain HTTP on :8083
synheart local --port 9000 --api-key my-key               # custom credentials
synheart local --https                                    # TLS + /etc/hosts entry
synheart local --https --domain api.synheart.example --https-port 8443
synheart local --web --web-port 8090                      # status dashboard
synheart local cleanup                                    # remove /etc/hosts entry
synheart local cleanup --remove-certs                     # also untrust local CA
```

The `--https` mode generates a local CA, trusts it in the OS keychain,
adds a `127.0.0.1 <domain>` entry to `/etc/hosts`, and serves the
mock platform behind that domain — so your SDK can hit
`https://api.synheart.example` exactly as it would hit the production
host. Run `synheart local cleanup --remove-certs` to reverse the OS
changes.

The `--web` flag runs a small status dashboard on a separate port
showing connected SDK clients, queued ingests, and recent consent
grants.

## HSI export receiver

`synheart receiver` accepts **HSI exports from a Synheart mobile
client**. Use it when you want to debug a real on-device session by
replaying it on your laptop — the client packages a session as one
or more HSI snapshots and posts them to the receiver over the local
network.

```bash theme={null}
synheart receiver                                          # default port 8788, auto-generated token
synheart receiver --port 9000 --token my-token             # custom port/token
synheart receiver --out ./exports --format ndjson --gzip   # persistence options
```

On startup the receiver prints a bearer token and a QR code; scan
from Life to pair the device. Subsequent uploads from the paired
device are accepted without re-pairing until you stop the receiver.

## Mock stream — full flag reference

```bash theme={null}
synheart mock start \
  --vendor whoop \           # whoop | garmin (default: whoop)
  --scenario baseline \      # see `mock list-scenarios`
  --rate 50hz \              # tick rate
  --duration 5m \            # auto-stop (default: indefinite)
  --host 127.0.0.1 \         # bind address
  --port 8787 \              # WS port; SSE = +1, UDP = +2
  --seed 42 \                # deterministic output
  --out session.ndjson \     # also record while streaming
  --web --web-port 8790      # embedded status dashboard
```

`synheart mock record` and `synheart mock replay` accept the same
flags plus `--in` (replay input file), `--speed` (real-time multiplier),
and `--loop` (restart on EOF).

## Diagnostics

```bash theme={null}
synheart doctor               # walk environment / scenarios / auth / network
synheart version              # short: just `synheart <version>`
synheart version --build      # full: hash, build date, OS/arch (support tickets)
synheart version --format json
synheart whoami               # email, org, plan tier (decoded from JWT, offline)
synheart env                  # paths + identity + pinned runtime + app IDs
synheart env --format json
```

`synheart doctor` reports environment, scenario data, auth status, and
network bind state inline as `ok` / `warn` / `error`. It exits 0 even
when something's missing — specific commands (`synheart mock`,
`synheart install`) surface their own typed errors when they actually
need a missing piece. Pass `--port <n>` to check a non-default port.

`synheart env` prints local paths, plus three identity blocks when
they're available. All sources are local — no network calls:

| Block             | Source                                                           | Shows when                              |
| ----------------- | ---------------------------------------------------------------- | --------------------------------------- |
| `Auth`            | locally-decoded JWT                                              | logged in                               |
| `Runtime`         | `synheart.lock`                                                  | project has a pinned runtime            |
| `iOS` / `Android` | `Runner.xcodeproj/project.pbxproj` and `app/build.gradle{,.kts}` | the project ships an iOS or Android app |

```text theme={null}
$ synheart env
  Cache:     ~/.synheart/cache
  Config:    ~/.synheart
  Project:   .
  Lockfile:  synheart.lock (exists)
  Vendor:    synheart/vendor (exists)
  Type:      flutter
  iOS:       ai.synheart.themirror
  Android:   ai.synheart.themirror
  OS/Arch:   darwin/arm64

  Auth:      you@example.com (pro, org_abc)
  Runtime:   synheart-runtime v5.4.0  variant=edge  channel=latest
```

`synheart version` prints just the version by default. Pass `--build`
when you need build metadata (commit hash, build date, OS/arch) for a
support ticket. JSON output (`--format json`) always includes the
full set.

## Learn the platform

```bash theme={null}
synheart explain                  # list available topics
synheart explain hsi              # primer on the Human State Interface
synheart explain hrv              # what HRV is and what HSI does with it
synheart explain wear             # how wearable cloud connectors work
synheart explain consent          # consent service and the PDP
```

`synheart explain` ships in-binary primers for every unfamiliar concept the CLI exposes (HSI, HRV, recovery, wear, consent, mock, local, receiver, update). Each primer includes a few example commands and a list of related topics.

The primers are also exposed as the `synheart_explain` MCP tool, so AI agents (Claude Code, Cursor) can ground themselves on Synheart concepts without leaving the chat.

## Project configuration

Every command honors a project-level config at `.synheart/config.yaml` — discovered by walking up from the current directory. Resolution precedence (highest wins):

1. Explicit CLI flag (e.g. `--port 9000`)
2. Environment variable
3. Project config (`.synheart/config.yaml`)
4. Hardcoded default

```yaml theme={null}
# .synheart/config.yaml
mock:
  port: 9000
  host: 127.0.0.1
  scenario: workout
  vendor: garmin

local:
  port: 8090
  domain: api.synheart.local

receiver:
  port: 7777
  host: 0.0.0.0
```

```bash theme={null}
synheart config show              # resolved config + path of the active file
synheart config show --format json
synheart config path              # exit 1 if no project config (shell-conditional friendly)
```

Drop a `.synheart/` directory in your repo and the data-plane commands — `synheart doctor`, `synheart mock start`, `synheart mock record`, `synheart mock replay`, `synheart local`, `synheart receiver` — pick up their port/scenario/vendor from the matching section automatically. Other commands (auth, install, sync, explain, mcp, update) ignore project config because they don't have a per-project shape.

## AI agent integration (MCP)

```bash theme={null}
synheart mcp serve                # speak the MCP protocol on stdin/stdout
```

`synheart mcp serve` exposes seven read-only verbs as MCP tools so agents (Claude Code, Cursor, Claude Desktop) can call them directly:

| Tool                      | Wraps                    |
| ------------------------- | ------------------------ |
| `synheart_explain`        | concept primer text      |
| `synheart_doctor`         | environment diagnostic   |
| `synheart_config_show`    | resolved project config  |
| `synheart_auth_status`    | auth state diagnostic    |
| `synheart_whoami`         | current logged-in user   |
| `synheart_list_scenarios` | available mock scenarios |
| `synheart_version`        | CLI version + build info |

Per-client setup:

<Tabs>
  <Tab title="Claude Code">
    ```bash theme={null}
    claude mcp add --scope user synheart "$(which synheart)" mcp serve
    ```
  </Tab>

  <Tab title="Cursor / Claude Desktop">
    Add to the client's MCP config (paths vary by client):

    ```json theme={null}
    {
      "mcpServers": {
        "synheart": {
          "command": "synheart",
          "args": ["mcp", "serve"]
        }
      }
    }
    ```
  </Tab>
</Tabs>

Once configured, ask the agent things like:

* *"What can you tell me about HSI?"* → calls `synheart_explain` with `topic: hsi`
* *"Run synheart doctor and tell me if anything's broken."* → calls `synheart_doctor`, summarizes
* *"What scenarios can I run with mock data?"* → calls `synheart_list_scenarios`

All tools are read-only in v1 — agents can describe state but not mutate it. Mutating tools (mock start, login, install) come in v2 with explicit confirmation flows.

## Self-update

```bash theme={null}
synheart update                   # interactive: prompt, then download + swap binary
synheart update --yes             # apply without prompting (CI / non-TTY)
synheart update --check           # report only; exit 1 if newer available (CI-friendly)
synheart update --rollback        # restore the previous binary
synheart update --force           # apply even if package-manager-managed
synheart update --format json     # stable JSON shape
```

The CLI fetches the release manifest from `https://dist.synheart.ai/synheart-cli/latest/manifest.json`, downloads the matching archive for your platform, verifies its SHA-256 against the manifest, and atomically swaps the new binary into place. The previous binary is archived at `~/.synheart/bin/synheart.prev`, so `synheart update --rollback` reverts in one step.

Self-update is **refused** when the binary appears to be managed by a package manager (Homebrew, apt, Chocolatey, `go install`) — those installs should upgrade through their package manager, not through `synheart update`. Pass `--force` to override if you know what you're doing.

The installer scripts remain the supported recovery path for fresh installs and for clients on a release that pre-dates self-update:

* macOS / Linux: `curl -fsSL https://synheart.sh/install | sh`
* Windows (PowerShell): `iwr -useb https://synheart.sh/install.ps1 | iex`

A passive notification appears on stderr (once per 24h) when a newer version is available. Suppress with:

* `SYNHEART_NO_UPDATE_CHECK=1` — explicit opt-out
* `CI=true` — auto-suppressed in build environments
* `--format json` — never pollutes machine output
* `synheart mcp serve` and `synheart completion` — auto-quieted (protocol / setup contexts)

Update failures surface as `SH-UPD-APPLY` (download/verify/swap failed; the existing binary is left untouched) or `SH-UPD-CHECK` (manifest fetch failed). Both retry safely.

## CI/CD

For deterministic builds, install the runtime once, commit the
lockfile, and `sync` in CI:

```yaml theme={null}
# .github/workflows/build.yml
- run: curl -fsSL https://synheart.sh/install | sh
- run: synheart login --token ${{ secrets.SYNHEART_CI_TOKEN }}
- run: synheart sync --check       # fails the build if synheart.lock would change
- run: flutter build apk
```

Use `synheart login --token` (non-interactive) with a CI service-
account token. Tokens are scoped per project and per environment;
rotate via the platform dashboard.

## Global flags

These persistent flags work on every command:

* `--format text|json` — output format. JSON output is schema-stable (snake\_case fields, RFC 3339 timestamps); the CLI synthesizes a JSON error body with `error_code` on every command failure so scripts can branch on it.
* `--quiet` / `--verbose` — suppress or expand log output. `--verbose` also reveals the underlying cause on typed errors.
* `--no-color` — disable ANSI colors. The `NO_COLOR` env var is also honored ([https://no-color.org](https://no-color.org)).

## Error codes

When a command fails, the CLI returns a typed error like:

```text theme={null}
error: SH-AUTH-001 — Not logged in.

  No Synheart credentials found in the keyring or config file.

Try this
  synheart login
```

Codes follow `SH-<DOMAIN>-<NUMBER>`. Domains in active use today: `AUTH`, `WEAR`, `HSI`, `CONS`, `ING`, `CFG`, `NET`, `INST`, `RT` (runtime lifecycle), `UPD` (self-update). Codes are stable identifiers — search them in your shell history, link them in support tickets, branch on them in scripts (`error_code` field in JSON output). Renames or reassignments would be a breaking change.

## Environment variables

| Variable                   | Purpose                                                                                                           |
| -------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `SYNHEART_API_URL`         | Defaults to `https://api.synheart.ai`. Overriding requires an enterprise plan, or rebuilding the CLI from source. |
| `SYNHEART_INSTALL_DIR`     | Override the CLI install directory used by the installer scripts.                                                 |
| `SYNHEART_NO_UPDATE_CHECK` | Set to `1` to suppress the passive update notification.                                                           |
| `SYNHEART_SCENARIOS_DIR`   | Override the directory `mock` looks in for scenario YAML files.                                                   |
| `NO_COLOR`                 | Any non-empty value disables ANSI color output (industry standard).                                               |
| `CI`                       | When set to anything truthy, suppresses the passive update notification automatically.                            |

## Troubleshooting

<AccordionGroup>
  <Accordion title="Install/sync requires login">
    Run `synheart login` first. Artifact commands require a valid
    access token. If you keep getting kicked back to login, your
    token may have expired — `synheart logout` then `synheart login`
    again.
  </Accordion>

  <Accordion title="Mock stream port already in use">
    Use `--port` with `synheart mock start` or check availability
    with `synheart doctor --port 8787`. Port 8787 (WS), 8788 (SSE),
    and 8789 (UDP) are the defaults; bumping `--port` shifts all
    three together (`--port N` → WS=N, SSE=N+1, UDP=N+2).
  </Accordion>

  <Accordion title="Need reproducible SDK versions in CI">
    Commit `synheart.lock` and run `synheart sync` in CI to install
    pinned artifacts. Add `synheart sync --check` to catch lockfile
    drift on PRs before the runtime version changes silently.
  </Accordion>

  <Accordion title="`synheart local --https` fails to write to /etc/hosts">
    `--https` mode needs sudo to add the `127.0.0.1 <domain>` entry
    and to trust the generated CA. Either run with sudo, or use
    plain HTTP (`synheart local`, no `--https`) for development —
    the SDK accepts both.
  </Accordion>

  <Accordion title="Receiver pairing QR doesn't scan from Life">
    Make sure the receiver and the Life app are on the same Wi-Fi
    network and the receiver's port (default 8788) isn't blocked by
    your firewall. `synheart doctor --port 8788` confirms binding.
  </Accordion>

  <Accordion title="`SYNHEART_API_URL` not picked up">
    The CLI re-reads environment variables on every invocation, but
    a stale `synheart.lock` can pin the install URL. Delete
    `synheart.lock` and re-run `synheart install`.
  </Accordion>
</AccordionGroup>
