# spt-mobile

Android companion app for [spt](https://sabermage.github.io/spt-releases): browse the
endpoints across your machines' subnets, watch live activity digests, message your agents
two-way with per-agent notifications, and speak to them from a Pebble watch — dictations
land directly with the agent you starred. Your phone pairs with each of your spt machines
over an encrypted peer-to-peer link that keeps working when you move between Wi-Fi and
cellular.

Messages and dictations are never lost to a bad connection: anything that can't be
delivered right now queues durably (on the phone for outgoing voice, on your machines for
incoming messages) and drains automatically on reconnect.

<!-- [doc->REQ-RELEASE-PACKAGING] -->
## Install the app

Android 8.0 or newer, 64-bit ARM (any recent phone).

**Recommended — [Obtainium](https://github.com/ImranR98/Obtainium)**, so updates arrive
automatically:

1. Install Obtainium.
2. In Obtainium: **Add App** → paste `https://github.com/SaberMage/spt-mobile`.
3. Install. Obtainium will notify you when a new release is out.

**Manual:** download the APK from the
[latest release](https://github.com/SaberMage/spt-mobile/releases/latest) and open it.
Android will ask you to allow installs from your browser or Obtainium the first time.
Updates install over the existing app and keep your pairings.

## Install the host adapter

On each machine running spt that your phone should pair with:

```sh
spt adapter add --release SaberMage/spt-mobile
```

Update later with:

```sh
spt adapter update mobile
```

<!-- [doc->REQ-HOST-INPLACE-UPDATE] -->
Updating works **in place**: the running host keeps its canonical exe path unlocked (it
runs from a shadow of itself), notices the swapped binary within a few seconds, and
restarts itself into the new version — no manual stop needed. (One-time exception: a host
older than v1.0.3 predates this and must be stopped by hand for the update that first
delivers it.)

Then start the phone's gateway endpoint (pick any id; `mobile-gw` is a fine default):

```sh
spt endpoint run --adapter mobile --id mobile-gw
```

<!-- [doc->REQ-HOST-SUSPEND-HONOR] -->
Stop it the same way you stop any endpoint — no adapter-specific flow:

```sh
spt endpoint suspend mobile-gw    # or: spt endpoint shutdown mobile-gw
```

Either verb records the registry suspend edge; the host polls its own status and takes
the whole gateway down (relay listener included) within a few seconds of seeing
`Suspended`. `spt endpoint run …` brings it back and wakes a suspended endpoint
automatically.

The adapter binary currently ships for Windows x86_64; on other platforms, build it from
source (see Development below).

## Pair your phone

1. The **pair code prints in the terminal when the endpoint starts** (the
   `spt endpoint run` screen). To see it again later:

   ```sh
   spt rc mobile-gw --view
   ```

2. In the app's **Hosts** tab, paste that JSON line into "Pair-code JSON" and tap
   **Pair**. The box reports progress and the paired host appears below it.
3. Repeat for each machine. The app keeps the hosts in a priority order you control and
   fails over between them automatically.
4. Tap **Star** on a host to choose which of its endpoints receives your voice
   dictations.

## Pebble voice

The app runs a local webhook receiver for Pebble Index voice transcripts:

1. **Hosts** tab → **Pebble voice** card: copy the webhook URL
   (`http://127.0.0.1:8646/`) and the token.
2. In the Pebble app's Index webhook settings, set that URL and add a header named
   `x-widget-token` with the token as its value.
3. Dictate. The transcript is queued safely on the phone, then delivered to the starred
   endpoint of the first reachable host. If everything is offline, the pending count
   shows on the card and the queue drains in order once a host is reachable again.

## Browse and message

- **Browse** tab: every endpoint across your paired machines' subnets, grouped by machine
  → project → endpoint (mirrors `spt endpoint list`), with a shared-subnets line per
  machine and live status. Tap an endpoint to open its interlaced view — the live activity
  digest and your two-way message history in one timeline, with markdown + XML rendering and
  arbitrary text selection. Type at the bottom to message the agent.
- **Messages** tab: your paired gateways, each opening a single unified in/out message
  thread across all of that gateway's endpoints (no digest noise — just the conversation).
  Tap any message to jump straight into that endpoint's digest view at that message.

## Development

Working rules and orientation live in [AGENTS.md](AGENTS.md); design and decision records
under [docs/](docs/). Build-from-source, tests, and the release procedure:
[docs/RELEASING.md](docs/RELEASING.md).

```sh
cd app && ./gradlew assembleDebug testDebugUnitTest   # app + JVM tests
cd rust && cargo test                                 # device-link slice
cd host && cargo test                                 # host adapter
traceable-reqs check                                  # requirement evidence gate
```
