Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
86e4325d1This file is pinned to the selected release. Download the original to open it in your design tool.
# Development
## Repository layout
```
desktop/ the app (Flutter; macOS first). third_party/xterm is the patched terminal core
cli/ the harness daemon and CLI (TypeScript, one bundle). src/engines/ is one folder per engine
backend/ the relay (Node, Prisma/MongoDB, Redis)
provider/ the API-provider spec, reference and example providers, conformance runner
devices/ firmware for the Harness device (ESP-IDF, devices/harness-device/firmware)
store/ harnesses, shared viewers, the registry, Hello World, starter, schemas, and author tools
```
For your first contribution, [build a harness](../CONTRIBUTING.md#your-first-harness). You can
check and install a package with the released CLI without building the platform.
## Platform support
macOS is the primary supported and tested desktop experience. Linux builds and a Windows runner
exist, but full Linux and Windows support remains work in progress. Embedded harness webviews
currently run only on macOS; platform code being present does not imply feature parity.
Harness authors should list the operating systems and tool versions they actually tested.
## Account-free local use
**Outstanding requirement:** someone should be able to open the desktop app, start local sessions,
and use locally installed harnesses without an OpenHarness account. Sign-in should be needed only
when they choose to link remote machines. The engine may still require its own account or API key.
The current source does not meet that requirement: desktop bootstrap checks
`cliLogin.checkStatus()` in `desktop/lib/state/app_state.dart`, and `startCommand` in
`cli/src/cli.ts` refuses to start without a saved sign-in session. Removing one screen alone
will not provide a working local mode.
Completion should be verified with a clean local profile: start the daemon and app without saved
account credentials, create and resume a local session, then sign in and link a remote machine
without losing that work. Cancelling remote sign-in or signing out must leave local work usable.
This is tracked work, not a claim that account-free startup is already available.
## Build and test
```bash
# cli
cd cli && npm install && npm run typecheck && npm test
make install-cli # bundle this tree into ~/.harness/cli and restart the daemon on it
# desktop (Flutter ≥ 3.47 / Dart ≥ 3.13; SPM on for macOS)
cd desktop && flutter pub get && flutter analyze && flutter test
flutter run -d macos # or -d linux
# backend
cd backend && npm install && npm run typecheck && npm test
# provider
cd provider/e2e && npm install && npm test
# device
make device-test
```
Harness package updates have a dedicated coverage gate and a desktop-to-daemon integration test:
```bash
cd cli && npm run test:dsh-updates
cd ../desktop
DSH_UPDATE_CLI_ROOT="$PWD/../cli" flutter test test/store_update_e2e_test.dart
```
The coverage gate requires 100% statements, branches, functions and lines in the updater, version
comparison, package locks and daemon mutation handler, and runs in the on-demand CI workflow.
The integration test uses temporary local Git packages and a real WebSocket connection: click Update,
reject a broken release, retry successfully,
update a shared viewer, then reopen the preserved workspace and fetch its rendered preview. It needs
Node and the CLI dependencies, with no account or model calls. Its fixture is
`cli/scripts/smoke-dsh-updates.ts`; `DSH_UPDATE_CLI_ROOT` makes this integration run explicit.
Each product releases on its own tag and the suffix routes the workflow: `vX.Y.Z_cli` bundles and
publishes the daemon (running daemons pick it up within a minute), `vX.Y.Z_backend` builds the image,
`vX.Y.Z_desktop` builds, signs and publishes both macOS bundles and both Linux architectures.
`make release-cli|release-backend|release-desktop` cut them; `make upload-circle` publishes device
firmware for USB delivery through the host. `ci.yml` runs the CLI suite on demand (Actions -> CI -> Run workflow) and holds
no secrets, which is what lets it run on a fork's branch.
`make remote-machine`
brings up a second machine in Docker so the remote path can be exercised from one laptop.
## Isolated end-to-end testing
With Node, tmux, Flutter and a running Docker engine, run from the repository root:
```bash
(cd cli && npm ci)
(cd backend && npm ci)
(cd desktop && flutter pub get && bash scripts/test-terminal-local-e2e.sh)
```
The runner creates disposable MongoDB and Redis containers, a backend, a daemon, identities,
projects and a dedicated tmux server. It exercises both local and encrypted backend connections,
including creation retries, terminal input and resize, reconnect, agent/daemon restart, deletion,
and domain harness workspace/viewer/verdict recovery. The identity service and model CLI are
fixtures; it needs no real account and does not replace the running Harness daemon or engine hooks.
It cleans up its processes and containers when finished.
Set `HARNESS_E2E_DOCKER_CONTEXT` to use a separate Docker context. Set `HARNESS_STACK_KEEP=1` to
retain fixture logs and files for debugging; services and containers still stop. The test is
explicitly skipped in a plain `flutter test` run and exercised by the script above.
For the backend-to-provider chain, install dependencies in `provider/reference-provider`, then
run `PROVIDER_E2E=1 npm test` in `backend`. The cross-implementation provider suite in `provider/e2e`
also needs dependencies installed in `provider/example-provider`.
See [the reliability run](reliability-2026-09-16.md) for verified coverage and remaining limits.