English · 简体中文
Features · Architecture · Design notes · Run it · Releases · Layout · Roadmap
---
**harness-ai-app** is the mobile client of [Harness AI](https://github.com/harness-home). The agent runs on your desktop machine; this app is how the session follows you out of the room — read the trajectory, answer the questions it asks, approve the step it is waiting on, and start the next one.
It is a pure client of `harness-ai-server`. **It never connects to your desktop machine**, and there is nothing for it to connect *to*: the runtime binds loopback only. Everything you see here was pushed out by the desktop client over its own outbound link.
> [!IMPORTANT]
> **Developer preview.** Android and web are the surfaces built and verified today. A test APK is on the [Releases](https://github.com/harness-home/harness-ai-app/releases) page — signed with the Android debug key, not a store build. See [Running it](#running-it).
## What you can do
| | |
| --- | --- |
| **Follow a session** | Hosted sessions grouped by workspace, with the trajectory folded into something readable on a phone: messages as Markdown, tool calls as rows, images inline. |
| **Answer** | The runtime's questions — including plan reviews — arrive as native choices rather than as text you have to parse. Plan bodies render as Markdown. |
| **Approve** | Pending approvals in their own tab. Allowing an irreversible step passes through a confirmation; denying does not — only the side you cannot take back needs a gate. |
| **Start work** | Open a new session against a workspace the desktop has already synced. If the desktop is offline, the prompt is queued server-side and delivered when it comes back. |
| **Attachments** | Images the agent produced load on demand, with an "auto-load images" switch and your storage quota shown as it really is. Not-yet-loaded is a normal state with a first-class placeholder, not an error. |
| **Devices and account** | See your signed-in devices, the server you are pointed at, theme and language. |
Self-hosted by design: the server address is entered on the sign-in screen and persisted per install, because the address of *your* server is user data, not a constant baked into the build.
## Where it sits
```mermaid
flowchart LR
desktop["harness-ai-desktop
runtime on your machine"] -.->|"outbound push"| server["harness-ai-server
account · sessions · approvals"]
app["harness-ai-app
this repository"] <-->|"HTTPS · bearer + device id"| server
app -.->|"never connects"| desktop
style app fill:#0f766e,color:#ffffff,stroke:#0f766e
```
## Design notes
The parts of this app worth knowing before you change it:
- **Typography goes through one component.** `
` only — a bare React Native `Text` does not inherit colour, and one missed instance is black-on-black in dark mode. Machine text (paths, tool names, workspace directories) is always the mono variant.
- **Surfaces are flat.** Hairline borders and zero shadow, identical in both themes; hierarchy comes from the border, not from elevation, because Android dark elevation paints a dirty tint.
- **No reanimated, no worklets, no gesture-handler.** All three are excluded from autolinking for the local build, so importing one is a runtime crash. `pnpm verify` fails the build if an import appears — *or* if a `transition-*` / `animate-*` class appears without a `web:` prefix, which is the case an import scan cannot catch and the one that actually broke a screen.
- **UI primitives are vendored, not depended on.** Components are copied in from [react-native-reusables](https://github.com/founded-labs/react-native-reusables) and adapted (`@rn-primitives/*` only, touch-sized controls, repository code style). Each vendored file says where it came from.
- **Feedback is inline, never a toast.** In a scrolling screen a toast is a message the user misses.
The cross-surface token vocabulary is shared with the desktop and web clients; `lib/theme.tsx` is this app's single source of colour.
## Running it
**Prerequisites** — Node 22+, pnpm 11, a reachable `harness-ai-server`, and for a device build the Android SDK.
The wire contracts this app shares with the desktop client and the server come from npm as [`@harness-ai/contracts`](https://www.npmjs.com/package/@harness-ai/contracts), so a plain clone installs and builds.
```bash
pnpm install
pnpm verify # native-import guard + typecheck
pnpm start # Expo dev server (dev client)
```
| Command | What it does |
| --- | --- |
| `pnpm start` | Expo dev server against a development build. |
| `pnpm android` | Build and run on a connected device or emulator. |
| `pnpm prebuild` | Regenerate the native Android project from `app.json`. |
| `pnpm verify` | The guard that must pass: excluded-native scan plus `tsc --noEmit`. |
| `pnpm verify:attachments-web` | Browser end-to-end pass over the attachment path against a real server. |
| `pnpm icons` | Regenerate the app icons — deterministic, no imaging dependency. |
The server address defaults to `http://10.0.2.2:8720` on an emulator and `http://localhost:8720` on web; override it at sign-in, or with `EXPO_PUBLIC_HARNESS_API_BASE`.
## Releases
Every push and pull request runs the native-import guard, typecheck and a web bundle build.
A release is a tag. Pushing `v` runs the same gate, generates the native project and assembles the Android APK onto a GitHub Release:
```bash
git tag v0.1.0 && git push origin v0.1.0
```
The tag must agree with both `package.json` and `app.json`, and [CHANGELOG.md](https://github.com/harness-home/harness-ai-app/blob/main/CHANGELOG.md) must carry a section for it — all three are checked before anything is built, and that section becomes the release notes. The APK is **signed with the Android debug key** — it installs for testing and is not a store artifact; proper signing waits on the platform decision.
## Project layout
```
app/ Routes (expo-router)
(tabs)/ Sessions · Approvals · Me
session/[id].tsx Session detail and the folded trajectory
login.tsx Sign-in and the server address
new-session.tsx Start a session on a synced workspace
components/ Screen furniture and the UI kit (components/ui, partly vendored)
lib/ API client, auth, hosted-session queries, i18n, theme, preferences
scripts/ Icon generation, the native-import guard, the web e2e driver
plugins/ Expo config plugins
```
## Roadmap
| | |
| --- | --- |
| ✅ Shipped | Sign-in and self-hosted server address · session list and trajectory · questions and plan review · approvals · queued prompts · attachments with quota · themes and en/zh |
| 🚧 Open | Whether iOS ships alongside Android is still an open decision, and with it the prebuild and store path |
| 📋 Planned | Store distribution — the tagged APK is a debug-signed test build, which no store will take |
## Contributing
Issues and pull requests are welcome — start with [CONTRIBUTING.md](https://github.com/harness-home/.github/blob/main/CONTRIBUTING.md). If you touch the UI, keep to the design notes above; `pnpm verify` enforces the two rules that have actually bitten.
## License
[MIT](https://github.com/harness-home/harness-ai-app/blob/main/LICENSE) © harness-home