# How OpenEng works

> How the OpenEng platform works: the engineering apps are thin web UIs over a sealed engine on loopback, OpenEng AI is authored in the Console and run by an engine that dials the OpenEng Broker, and one account spans both.

OpenEng is one platform with two runtime shapes. The five **engineering apps** are thin web UIs that
drive an engine on your own machine over a sealed, loopback-only channel (the Terminal, Kubernetes and Data engines are published; the Git and Chat engines are coming soon). **OpenEng AI** is authored in
the Console and run by the `openeng` engine on your machine, which opens no port at all: it dials out to
the OpenEng Broker. Both sides share one account.

| Aspect | Engineering apps | OpenEng AI |
| --- | --- | --- |
| Where the work runs | An engine per app on your machine (`openeng-terminal`, `openeng-kubernetes`, …) | The `openeng` engine on your machine |
| How the browser reaches it | Directly, over loopback: `https://engine.openeng.app:<port>`, which resolves to `127.0.0.1` | Through the OpenEng Broker, which the engine dials out to |
| How the engine signs in | A one-time key from the app (`serve --oauth=<one-time key>`) | An OpenEng key, which is a Console API key (`--key` or `OPENENG_KEY`); requires Pro |
| What it runs | Your shells, clusters, repositories, databases and local models | The configs you publish in the Console |

## Engineering apps

Every OpenEng engineering app follows the same shape: a thin web UI, served from the cloud, that talks to an **engine running on your own machine** over a sealed, loopback-only channel. The heavy work — model inference, shell execution, database queries, Kubernetes calls — happens locally. This is what makes the engineering apps private by default.

### Thin UI, local engine

The web app (for example `chat.openeng.app`) is static. It renders your data but never processes it; the one exception is Git's CI & CD view, which fetches runs from your forge in the browser ([CI & CD](git.md#cicd)). The web app keeps only your sign-in, the pairing key cache, UI preferences and (in Git) forge tokens in the browser; all other state and computation live in the engine, a single native binary bound to `127.0.0.1`:

| App | Engine | Loopback port | Web app | Engine published |
| --- | --- | --- | --- | --- |
| Terminal | `openeng-terminal` | 50052 | terminal.openeng.app | Yes |
| Kubernetes | `openeng-kubernetes` | 50054 | k8s.openeng.app | Yes |
| Data | `openeng-data` | 50057 | data.openeng.app | Yes |
| Git | `openeng-git` | 50053 | git.openeng.app | Not yet |
| Chat | `openeng-chat` | 50056 | chat.openeng.app | Not yet |

Each engine keeps its files under its own folder, `~/.openeng/<app>/`, and runs once per machine: a lock file in `~/.openeng/<app>/runtime/` makes a newly started engine replace the one already running. Platforms, installers and updates are covered in [Install, platforms and updates](install.md).

### A sealed transport

The browser reaches the local engine over HTTPS with a browser-trusted certificate, so there is no manual trust step. On top of TLS, the request and response frames of a session are **sealed**: each frame is encrypted on the loopback connection on its own, to the public key the other side offered at the handshake. A handshake token minted at each engine start authorizes every call. In the current Linux Terminal, Kubernetes and Data builds, the engine gives that token only to its own app's web origins and to local programs that send no `Origin` header, so on a shared machine another user's programs can drive your engine too. The macOS builds and the Chat and Git engines don't restrict origins yet, so on those any web page can get the token ([Transport security](security.md#app-transport)).

How the pieces fit:

- **The name.** `engine.openeng.app` is a public DNS name that resolves to `127.0.0.1` on every machine. The engine binds `127.0.0.1` only; the browser connects to `https://engine.openeng.app:<port>`.
- **The certificate.** At sign-in the engine fetches a publicly trusted certificate for `engine.openeng.app`, so every browser accepts the connection. If that fetch fails, it falls back to a local certificate. Every signed-in engine gets the same certificate and key, so the certificate proves the name, not which engine answers.
- **The seal.** When the client offered a key at `CreateSession`, each side seals every frame to the other side's session public key, which the two exchange when the session is created. Every frame uses a fresh ephemeral key: X25519, then HKDF-SHA256, then ChaCha20-Poly1305. The exchange itself isn't authenticated, a session opened without a client key isn't sealed, and a request frame that fails to unseal is passed on as it arrived.

### Pairing with a one-time key

The web app and the engine are paired with a short-lived, single-use key:

1. You sign in to the web app with your OpenEng account (Google, through `auth.openeng.app`).
2. When no engine is reachable, the app shows its pairing screen with a start command such as `openeng-terminal serve --oauth=<one-time key>`. It mints the key from the OpenEng API (`api.openeng.app`) with your sign-in.
3. You run the command. The engine exchanges the key for its own token and starts serving, and the app connects automatically.

A key expires after about five minutes, and the app reuses an unexpired key when you reload the page. The OpenEng API mints at most five unused keys an hour per account, shared by every OpenEng app (a key an engine has used no longer counts), and each app also counts the keys it mints in your browser. Once the engine connects, the app forgets the key, so the next pairing gets a fresh one. See [Getting started](getting-started.md#start-and-connect) for the walkthrough.

### Local-first & private

- **Models** are downloaded to and run from your disk (GGUF, ONNX, or your Ollama library), so by default prompts and model files never cross the wire. The exception is a model you point at an external server (`backend = external`: Ollama, LM Studio or any OpenAI-compatible endpoint), which receives the prompts you send it, wherever that server runs ([Provider vs. backend](chat.md#provider-vs-backend)).
- **Credentials** — kubeconfigs, database passwords, SSH keys, cloud keys — are resolved locally by the engine and never sent to any OpenEng service. A [connector](connectors.md)'s own keys go only to the gateway in your cloud account.
- **Your data** — code, query results, logs — is read and written locally. When you use a connector, the request and its results travel over HTTPS between the engine and your own cloud account.

> [!NOTE] What the wire schema carries
> The wire contract between each UI and its engine has no field for an OpenEng secret or product prompt. Your own payloads (paths, commands, source, your own system prompts) travel on it, and so do your own credentials, which reach only your engine over the sealed loopback: a Data DSN; a connector's `api_key` and `auth_token` in Data, Kubernetes, Terminal and Chat; a connector's write key; a kubeconfig you paste into Kubernetes; a Terminal vault value; and a Chat MCP server's headers. A test scans each schema for secret-like field names, with the marked credential fields exempted. It matches names only, so it doesn't catch every credential field (a Data write key or a pasted kubeconfig, for example).

### Cross-app integration

Because every engine speaks the same sealed protocol on a known loopback port, one engine can act as a client of another. The [Chat](chat.md) agent uses this to reach your other apps: given a chat group that has a Kubernetes cluster and some Git repos attached, the Chat engine calls the Kubernetes and Git engines directly over internal gRPC to inspect pods, read logs and cross-reference code — all on your machine, scoped to exactly the connections you configured. (The Chat and Git engines are not published yet.)

### Connectors for the cloud

When a resource lives in the cloud (a managed Kubernetes cluster, a cloud database), the engine can't reach it directly without holding your cloud credentials. [Connectors](connectors.md) solve this: you deploy a small, source-only function into your *own* cloud account, and the engine calls it over HTTPS. Your cloud credentials stay in your account and nothing passes through OpenEng; results come back to your engine over HTTPS, and the engine holds only the connector's own keys.

### End-to-end test suites

Every engineering app is specified end to end in written test suites that a computer-use agent follows in a real browser against a real engine, starting from sign-in. As of September 25, 2026 there are 151 of them: 147 for the five apps' features and 4 for the flows they share (sign-in, engine pairing, app navigation and the account menu). 56 of them first stand up a real service, such as a database in Docker, so results are checked against known data. The suites are internal to OpenEng and aren't published.

## OpenEng AI

OpenEng AI splits authoring from execution. You define models, agents, templates, loops, connections and guardrails in the [Console](console.md) and publish them as versioned [configs](configs.md). The `openeng` engine on your machine resolves those configs and runs them. You drive it from the Web Console at [app.openeng.app](https://app.openeng.app).

### The engine dials the Broker

The AI engine is not a server: it opens no network port (its model daemon talks to it over a private Unix socket). When it starts:

1. It reads your **OpenEng key**, an API key you create in the Console (Deploy → API keys). You pass it as `--key=<key>` or in `OPENENG_KEY`. Without a key it refuses to start.
2. It registers with the OpenEng API (`api.openeng.app`). The API checks the key and an **active Pro plan**, then sets up a session with the Broker. One key runs one engine at a time.
3. It dials the OpenEng Broker (`broker.openeng.app`) and keeps that outbound connection open. The key itself never goes to the Broker; the engine authenticates there with the session the API issued.

[The engine reference](engine.md#start) covers its commands, flags and files.

Pro is launching in Q4 2026 and can't be purchased yet (see [Plans & billing](account.md)), so the engine can't be registered on a Free account.

> [!WARNING] Status on September 25, 2026
> This section describes the design. The OpenEng AI side of the OpenEng API (registration, configs, keys and plans) isn't served yet, and the Broker isn't online, so no engine can register today, whatever the plan. The engineering apps' pairing and certificates, which use the same API host, work.

### Surfaces reach the engine through the Broker

The Web Console sends your requests to the engine through the Broker, and every hop is encrypted:

- **Browser to engine:** your requests travel encrypted to the Broker, which opens them to route them to your engine. On this leg the Broker is a trusted part of the path, not a blind relay.
- **Streamed replies:** the engine's streamed replies to a turn are sealed end to end to your browser when the request carries a usable browser key, so the Broker cannot read them.
- **Engine data:** the engine data the Web Console loads through the Broker (your thread list and history, learned memory, the running config, placeholder names, and loop, warm-up and device status) is sealed to the Broker, which opens it to deliver it.
- **Retention:** the Broker keeps every envelope it routes (requests with any attachments, replies and control data) for a retention window, 7 days by default, and then deletes it by age.

[Transport security](security.md#ai-transport) has the details.

Models run on your machine by default. Hosted APIs and external coding CLIs are opt-in per role and go out through one gateway ([Models & role defaults](models.md)).

### From the Console to your engine

1. **Author.** In the Console you create building blocks and attach them to a config. Nothing is live until you publish.
2. **Publish.** Publishing freezes a new version of the config, stored by the OpenEng API.
3. **Resolve.** The engine fetches the configs published to your account from the API and caches them locally. `openeng serve --config=a,b,c` preloads those configs and downloads the models they need; `--default=<config id>` picks the config used for requests that name none ([Which config the engine serves](engine.md#config-selection)).

The quickstart explains [how the engine picks up what you publish](ai-getting-started.md#4-how-the-engine-picks-up-what-you-publish), including version pins.

### Catalogs

The public catalogs are sites of their own, one per kind: agents, skills, templates, models, cells, plugins, loops, library, roles and connectors, each at `<kind>.openeng.app` (for example [models.openeng.app](https://models.openeng.app)). A config refers to catalog items by ID. When a config uses a published skill or agent, the engine fetches its Markdown body from the catalog site, for example `https://skills.openeng.app/<slug>.md`; a local copy always wins. [Public catalogs & IDs](catalogs.md) lists every catalog, its ID forms and its JSON files.

## Shared across the platform

| Service | Host | Used by |
| --- | --- | --- |
| Sign-in | auth.openeng.app | Every app, the Console, the Web Console and the billing site. One Google sign-in is your OpenEng account. |
| OpenEng API | api.openeng.app | The engineering apps' pairing keys and engine certificates. By design also OpenEng AI engine registration, published configs, keys and plans; those routes aren't live as of September 25, 2026. |
| OpenEng Broker | broker.openeng.app | By design, the AI engine's outbound link to the Web Console: the engine dials it, and the Web Console reaches the engine through it; not online as of September 25, 2026 |
| Releases | releases.openeng.app | The app engines' update checks (the current macOS builds still use the release service's former address), the AI engine's update check (the feed has no `engine` release yet as of September 25, 2026), and the public release notes |
| Billing | billing.openeng.app | Plans and payments ([Plans & billing](account.md)) |
| Downloads | openeng.app | Engine installers and binaries under `openeng.app/engine/`, which the installers and the app engines' updates download ([Install](install.md)) |

Every app engine checks releases.openeng.app for updates (the current macOS builds, which are older releases, still use the release service's former address; the next macOS builds move to releases.openeng.app) and verifies the SHA-256 checksum of a new build before it installs it. The AI engine checks the same service, but as of September 25, 2026 the feed has no `engine` release, so you update it by running the installer again. See [Updates](install.md#updates).
