openeng is the OpenEng AI engine. It's one binary that runs on your own machine, runs the models and
agents your published configs describe, and does the work you start from the Web Console at
app.openeng.app. It binds no local port: it dials out to the OpenEng
Broker, and the browser reaches your engine through that link. That makes it a different kind of
program from the engineering-app engines (openeng-terminal, openeng-kubernetes and the others),
which listen on a loopback port on your machine (How OpenEng works).
Status on September 25, 2026: OpenEng AI isn't live yet
The Console and Web Console interfaces load, but the OpenEng AI API routes and the Broker aren't deployed. Nothing can be saved or published, and no AI engine can register or connect. Pro, Enterprise and pay-as-you-go launch in Q4 2026 and can't be purchased yet. This page describes OpenEng AI as it works once those services are live (status).
Before you start
The engine is published for Linux x86_64 only; on Windows, run it inside WSL. Install covers the installer, checksums and uninstalling. The engine starts only with an OpenEng key (an API key from the Console) and registers only for an account with an active Pro plan. Pro launches in Q4 2026 and can't be purchased yet (Plans & billing).
Commands
| Command | What it does |
|---|---|
openeng or openeng serve | Starts the engine: registers your key, then dials the Broker and serves requests. serve is the default command. |
openeng pull <role> | Downloads one model of the embedded suite into ~/ (below). Needs no key. |
openeng headless | The entry point for headless machines (below). |
openeng daemon | The sandboxed model process the engine starts by itself to run local model weights, so they never load inside the serving process. You don't run it yourself. |
openeng --help | Prints the usage summary (-h and help work too). |
Any other command prints unknown command followed by the usage summary, and exits with an error.
There is no --oauth flag and no browser sign-in for this engine; the key is the only way it
authenticates. (The engineering-app engines are different: they start with a one-time key from the
app, openeng-terminal serve --oauth=; see Getting started.)
Start the engine
openeng serve --key=<your OpenEng key>
# or keep the key in the environment
export OPENENG_KEY=<your OpenEng key>
openeng serve
To get a key, open the Console, go to Deploy → API keys and press Issue key. The value is shown exactly once, so copy it then (API keys & sandboxes).
The engine looks for the key in this order: --key=<key> (or --key <key>), then OPENENG_KEY.
With neither, it prints
cannot start: no OpenEng key (--key=
and exits. An empty --key= is refused too, with cannot start: empty --key.
Once it has a key, the engine:
- Registers the key with the OpenEng API, which checks the key and your Pro plan and sets up the engine's Broker session. The key goes to the OpenEng API (registration, config and placeholder-value fetches) and, with each update check, to releases.openeng.app (below); it never goes to the Broker.
- Resolves the config it serves by default (below) and applies it: the role-to-model bindings, the storage paths, the resource limits and the config's other settings.
- Warms up: it downloads the models that config needs and aren't on disk yet. If a resource the config requires can't be made ready, the engine refuses requests for that config rather than serving it partly.
- Starts the update check (below).
- Dials the Broker and serves requests over that outbound link. If the link drops, the engine reconnects on its own; if the Broker ever rejects its session, it registers again with your key.
It works in the directory you start it from: file tools and shell commands run there, and files you
attach in the Web Console are saved under attachments/ in that directory. Attachments reach the
engine inside the turn request, through the Broker. The Broker keeps every envelope it routes
(requests with any attachments, replies and control data) for a retention window, 7 days by default,
then deletes it by age (Transport security).
One engine per key. The API ties each key to one running engine. Starting a second engine with the
same key fails with this key already runs an engine — stop it or generate a new key. Pro includes
one API key (Plans & billing).
To stop the engine, press Ctrl+C in the terminal where it runs.
Local models need a sandbox
The engine runs local model weights only inside its sandboxed model process (openeng daemon). On
Linux, that sandbox needs one of these to work on the machine:
- a live systemd user session, so that
systemd-run --userruns (it also applies the config's CPU and memory limits), or - bubblewrap (
bwrap), with unprivileged user namespaces allowed.
The engine checks that the backend actually runs, not just that it's installed. Desktop Linux usually has a systemd user session; containers, CI runners and SSH logins without a user session often have neither. In WSL, enable systemd for the distribution or install bubblewrap.
When the sandbox works, the engine prints
openeng: local runtime =
as it starts. When it doesn't, the engine still starts, but it prints
local model inference refused (no functional sandbox enclosure): … and every request for a local
model fails with that message. To fix it, install bubblewrap (for example sudo apt install bubblewrap), enable a systemd user session, or run the engine outside the nested container.
Hosted and cloud models, an Ollama server and external-CLI models still work without the sandbox. On
such a host, calls to hosted and cloud models and to Ollama go directly from the engine, and it
prints a one-time warning that they're running HOST-DIRECT. Set OPENENG_ to
refuse those calls instead (Models).
Flags
openeng serve accepts these flags, written either as --name=value or --name value:
| Flag | What it does |
|---|---|
--key=<key> | Your OpenEng key. Takes precedence over OPENENG_KEY. |
--default=<config id> | The config used for requests that don't name one. Takes precedence over OPENENG_. |
--config=<id>,<id>,… | Preloads these configs at start: the engine fetches each one and downloads any embedded model it references that isn't on disk yet. A config that can't be fetched is logged and skipped. |
A config id is the <name>_<suffix> id shown, with a copy button, on each card of the Console's
Configs page (Configs).
Which config the engine serves
The engine never authors configuration; it runs what you published in the Console.
- In the Web Console, every session starts with you picking a published config and one of its versions. The engine fetches that version the first time a session uses it. Published versions never change, so to use a newer publish, pick the newer version.
- Requests that name no config use the engine's default config, chosen in this order:
--default=<config id> - the
OPENENG_environment variable (the older nameDEFAULT_ CONFIG OPENENG_still works and prints a one-time warning asking you to rename it)CONFIG_ ID - your account's default: the config you own that is named
default, otherwise the first config you own.
- With nothing published, the engine prints
NO PUBLISHED CONFIG — refusing to serve turns until a configuration is publishedand answers every request with "No configuration published, please create and publish a configuration to start accessing the engine." The Web Console shows the same message until you publish a config (Configs).
The engine keeps its last resolved copy of the default config in ~/. At
start it reuses that copy if it was fetched in the last 30 seconds, and otherwise checks with the API
first. If the API can't be reached, the engine starts with the copy it has rather than none.
Embedded models: openeng pull
openeng pull <role> downloads one model of the engine's embedded suite (a GGUF file from Hugging
Face) into ~/. It resumes an interrupted download and does nothing if the model is
already there. Without a role it pulls chat. The installer runs openeng pull chat for you unless
you set OPENENG_ (Install).
| Role | Model | Download size |
|---|---|---|
chat | Gemma 3 4B Instruct | about 2.5 GB |
coding | Qwen2.5 Coder 3B Instruct | about 2.0 GB |
planner | Qwen2.5 7B Instruct | about 4.5 GB |
summarization | Qwen2.5 1.5B Instruct | about 1.0 GB |
classify | Qwen2.5 0.5B Instruct | about 0.4 GB |
semantic-mapping | Qwen2.5 Coder 3B Instruct (the same file as coding) | about 2.0 GB |
guardrail | Qwen2.5 0.5B Instruct (the same file as classify) | about 0.4 GB |
reviewer | Gemma 3 4B Instruct (the same file as chat) | about 2.5 GB |
Roles that share a file download it once. An unknown role prints
unknown model role '<role>' — known: … with the list above. You rarely need to pull by hand: at start,
the engine downloads what its config needs, and --config does the same for the configs you preload.
Which model serves which role in a config is set in the Console (Models & role defaults).
Headless machines
openeng headless [--driver auto|work-pull|schedulers]
openeng headless takes the key the same way as serve (--key, then OPENENG_KEY) and picks a
driver: work-pull (fleet work), schedulers (the cron jobs you publish), or auto for both, which
is the default and also what an unknown value falls back to. In the current build the command stops
there: it prints the driver it resolved and exits, without running scheduler or fleet work.
Environment variables
| Variable | Default | What it does |
|---|---|---|
OPENENG_KEY | — | Your OpenEng key, used when --key isn't given. |
OPENENG_DEFAULT_CONFIG | — | The config id for requests that name no config. --default takes precedence. |
OPENENG_CONFIG_ID | — | The older name for OPENENG_. Still read; the engine warns once. |
OPENENG_MODEL | chat | The model the engine serves by default: a model role (chat is the embedded chat model) or a model tag, for example an Ollama tag such as qwen2.. |
OPENENG_HOME | ~/.openeng | The root folder for all of the engine's files (below). |
OPENENG_<COMPONENT>_DIR | <root>/ | Moves one component elsewhere, for example OPENENG_. |
OPENENG_SELF_UPDATE | on | 0 turns off both the update check and applying a downloaded update. |
OPENENG_UPDATE_CHANNEL | stable | The release channel to follow: stable or beta. |
OPENENG_UPDATE_CHECK_SECS | 21600 (6 hours) | Seconds between update checks. |
OPENENG_SANDBOX | workspace-write if a sandbox works on this machine, else off | How shell commands the agent runs are confined: workspace-write (read anywhere, write only inside the working directory), read-only, or off. The sandbox is bubblewrap on Linux (Seatbelt on macOS in builds for that platform; there is no macOS AI engine build yet). |
OPENENG_SANDBOX_MANDATORY | off | 1 makes the engine refuse calls to hosted and cloud models and to Ollama when no sandbox works on this machine, instead of sending them directly with a warning. Local models are refused in that case either way (Local models need a sandbox). |
OPENENG_AGENT_SHELL | off | 1 lets the agent run shell commands in a working directory that isn't in the engine's trusted list (~/). |
OPENENG_RESOURCE_FRACTION | the config's Resources step | A fraction between 0 and 1 of this machine's CPU and memory. It overrides the published CPU and memory percentages; GPU and storage still follow the config. With no published config, the engine uses 0.10. |
OPENENG_MCP_DENY | — | Comma-separated MCP tool names that are always blocked; this wins over everything (MCP permissions). |
OPENENG_MCP_AUTO_ALLOW | — | Comma-separated MCP tool names that run without asking, whatever their risk class, destructive included. |
OPENENG_MCP_ALLOW_WRITE | off | 1 lets write-class MCP tools run without asking; destructive ones still ask. |
OPENENG_ROLE_RULES | enforce | off turns behavioral roles off on this machine; assign picks roles without applying their rules. |
The installer has its own variables (OPENENG_BIN_DIR, OPENENG_, OPENENG_);
see Installer options.
Files: the ~/.openeng layout
Everything the engine stores lives under one root, ~/.openeng (/ on Linux).
The engine doesn't use the operating system's application-data folders. The engineering-app engines
keep their own files in subfolders of the same root, such as ~/.
Each component's folder is resolved in this order:
OPENENG_, when it's set and not blank;<COMPONENT>_ DIR - the path your published config sets for it in the Global paths step (Configs); an environment variable always wins over the config;
$, whenOPENENG_ HOME/ <component> OPENENG_HOMEis set;~/.. openeng/ <component>
The overrides combine: OPENENG_ with OPENENG_ puts model
weights on the big disk and everything else under /data/oe.
| Component | Default folder | Variable | What's in it |
|---|---|---|---|
| root | ~/.openeng | OPENENG_HOME | Everything below, plus the root files listed after this table |
| models | <root>/models | OPENENG_ | Model weights: GGUF files, ONNX model folders and Ollama pull markers, with an index.json |
| threads | <root>/threads | OPENENG_ | Each chat thread's history, metadata and workspace |
| memory | <root> itself | OPENENG_ | Global learned memory (memory_v2/) |
| config-state | <root>/ | OPENENG_ | What each config version has learned: its memory, dynamic skills and adaptation ledger |
| skills | <root>/skills | OPENENG_ | Your user-level skills |
| config | <root>/config | OPENENG_ | roles.json, the role-to-model map the engine routes by |
| catalog | <root>/catalog | OPENENG_ | The model catalog and an encrypted key store |
| usage | <root>/usage | OPENENG_ | The append-only usage ledger (ledger.jsonl) |
| journal | <root>/journal | OPENENG_ | The gateway journal, one file per thread |
| dashboards | <root>/ | OPENENG_ | Dashboard definitions |
| roles | <root>/roles | OPENENG_ | The behavioral-roles pack (not the same as config/) |
| agents | <root>/agents | OPENENG_ | Agent profiles |
| workers | <root>/workers | OPENENG_ | The worker registry |
| subagents | <root>/ | OPENENG_ | The specialist catalog |
| research | <root>/research | OPENENG_ | The research knowledge store, kept when threads are deleted |
| logs | <root>/logs | OPENENG_LOG_DIR | Reserved for log files (below) |
| runtime | <root>/runtime | OPENENG_ | How the engine finds its model daemon: socket, locks and handshake. Every process involved needs the same value. |
| cas | <root>/cas | OPENENG_CAS_DIR | Content-addressed artifact store |
| missions | <root>/missions | OPENENG_ | Long-running goal runs |
| loops | <root>/loops | OPENENG_ | Loop definitions and run state |
| fleet | <root>/fleet | OPENENG_ | Fleet identity and state |
| transmit | <root>/transmit | OPENENG_ | Keypairs and grants for secure transmission |
| update | <root>/update | OPENENG_ | A downloaded update waiting for the next start |
| checkpoints | <root>/ | OPENENG_ | Checkpoints of resumable runs |
| maps | <root>/maps | OPENENG_ | Repository maps |
| web | <root>/web | OPENENG_WEB_DIR | Documents fetched during web research |
| mcp-tokens | <root>/ | OPENENG_ | OAuth tokens for MCP servers, readable only by you |
| attachments | <root>/ | OPENENG_ | A cache of delivered attachments |
In the current engine, OPENENG_, OPENENG_ and OPENENG_ have no
effect yet: nothing in the served engine writes to those tiers.
Files at the root include:
config-cache.: the last resolved copy of the default config (above).json entitlement.: the last plan information the engine received.json ai-config.toml: engine settings, such asthreshold_pctunder[complexity]: how complex a request must be before the engine plans it as a multi-step run, written as a percentage. The default, 65, is the same threshold as 0.65 on the 0–1 scale the Console uses (Execution flow).trust.json: the directories you trust.
Two more places hold engine data. A project you work in can have its own .openeng/ folder next to
its code, like .git, for project-scoped permissions, plans and skills; it always stays with the
project. Temporary scratch files go to the operating system's temp folder.
Variables without the _DIR suffix are switches, not folders. For example, OPENENG_THREADS sets
the number of CPU threads for local inference; it doesn't move the threads folder.
Logs
The engine writes its log to standard error in the terminal where it runs; every line starts with
openeng:. The current build doesn't write log files, so the logs folder stays empty. To keep a
log, redirect it:
openeng serve 2>> "$HOME/openeng-engine.log"
Lines worth knowing:
boot auth via OpenEng key (registering with …), thenregistered engine '<id>' …: the key and your plan were accepted.config resolved — roles=: the default config was applied, with its role bindings.… warm-up: config <id>@: the models and other resources that config needs are in place.<version> READY (…) UNAVAILABLEinstead lists the required resources that aren't ready.resource caps (published): cpu …% gpu …% memory …% storage …%: the limits from the config's Resources step.broker transport — dialing …: the engine is connecting to the Broker.NO PUBLISHED CONFIG …: publish a config in the Console (above).CRITICAL update … applied on disk — RESTART REQUIRED: restart the engine (below).
Updates
The engine is built to update itself (as of September 25, 2026 there is no engine release to update
to yet; see the end of this section). At start and then every 6 hours (OPENENG_) it asks
releases.openeng.app for the latest engine release on its channel
(stable, or OPENENG_) for its platform. Each check sends your OpenEng key to
releases.openeng.app (in the X-OpenEng-Key header), whether the key came from --key or
OPENENG_KEY; OPENENG_ stops the checks, and with them this use of the key. When
there's a newer version, it:
- downloads it and checks its SHA-256 checksum; a file that doesn't match is never installed;
- refuses anything that isn't a native executable for this operating system, such as an error page or a binary for another platform;
- stages it in
~/;. openeng/ update/ - swaps it in the next time you start the engine, after checking the checksum again.
A release marked critical, or a running version below the minimum supported version, is swapped on
disk right away, and the engine prints RESTART REQUIRED. It never stops itself in the middle of
work; restart it when you're ready. If the release service can't be reached, the engine keeps running
the version it has and checks again later. OPENENG_ turns all of this off.
As of September 25, 2026, the release service doesn't list an engine release yet, so the check finds
nothing to install. To update before then, run the installer again (Install).
Troubleshooting
| The engine prints | What to do |
|---|---|
cannot start: no OpenEng key … | Pass --key=<key> or export OPENENG_KEY. Issue a key under Deploy → API keys. |
cannot start: empty --key | The --key= value is blank; check the variable you expanded into it. |
the API rejected the OpenEng key … | The key is mistyped or was revoked. Issue a new key. |
an active Pro plan is required to run an engine | The account isn't on Pro. Pro launches in Q4 2026 (Plans & billing). |
this key already runs an engine … | Stop the other engine that uses this key, or issue another key if your plan allows it. |
NO PUBLISHED CONFIG … | Publish a config in the Console (Configs). |
config resolve failed (…) — serving last-good cached config | The API couldn't be reached at start; the engine runs your last config and fetches again on the next start. |
warm-up: config … UNAVAILABLE — … required resource(s) not ready | A model or other resource the config needs couldn't be downloaded or found. Check the network and disk space, then restart the engine; the rest of the line names what's missing. |
local model inference refused (no functional sandbox enclosure): … | No sandbox works on this machine, so the built-in local models can't run. Install bubblewrap, enable a systemd user session, or run outside the container (Local models need a sandbox). Hosted, external-CLI and Ollama (catalog) models still work. |
… external model calls are running HOST-DIRECT … | The same missing sandbox: hosted and cloud model calls go directly from the engine. Fix the sandbox, or set OPENENG_ to refuse them. |
unknown model role '<role>' … | Use one of the roles listed in the message (above). |
unknown command '<name>' | The engine has only the commands listed above. |
For problems with the Console or the Web Console, see the OpenEng AI quickstart and Troubleshooting.