Skip to content

OpenEng AI

The openeng engine

16 min read

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

CommandWhat it does
openeng or openeng serveStarts 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 ~/.openeng/models (below). Needs no key.
openeng headlessThe entry point for headless machines (below).
openeng daemonThe 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 --helpPrints 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=<one-time key>; see Getting started.)

Start the engine

bash
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=<key> or OPENENG_KEY). Generate one in the Console (Pro required). and exits. An empty --key= is refused too, with cannot start: empty --key.

Once it has a key, the engine:

  1. 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.
  2. 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.
  3. 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.
  4. Starts the update check (below).
  5. 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 --user runs (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 = SANDBOXED daemon (enforced enclosure; weights never load in this process) 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_SANDBOX_MANDATORY=1 to refuse those calls instead (Models).

Flags

openeng serve accepts these flags, written either as --name=value or --name value:

FlagWhat 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_DEFAULT_CONFIG.
--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:
    1. --default=<config id>
    2. the OPENENG_DEFAULT_CONFIG environment variable (the older name OPENENG_CONFIG_ID still works and prints a one-time warning asking you to rename it)
    3. 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 published and 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 ~/.openeng/config-cache.json. 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 ~/.openeng/models. 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_NO_MODELS=1 (Install).

RoleModelDownload size
chatGemma 3 4B Instructabout 2.5 GB
codingQwen2.5 Coder 3B Instructabout 2.0 GB
plannerQwen2.5 7B Instructabout 4.5 GB
summarizationQwen2.5 1.5B Instructabout 1.0 GB
classifyQwen2.5 0.5B Instructabout 0.4 GB
semantic-mappingQwen2.5 Coder 3B Instruct (the same file as coding)about 2.0 GB
guardrailQwen2.5 0.5B Instruct (the same file as classify)about 0.4 GB
reviewerGemma 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

bash
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

VariableDefaultWhat 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_DEFAULT_CONFIG. Still read; the engine warns once.
OPENENG_MODELchatThe 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.5-coder:3b.
OPENENG_HOME~/.openengThe root folder for all of the engine's files (below).
OPENENG_<COMPONENT>_DIR<root>/<component>Moves one component elsewhere, for example OPENENG_MODELS_DIR=/mnt/big/models.
OPENENG_SELF_UPDATEon0 turns off both the update check and applying a downloaded update.
OPENENG_UPDATE_CHANNELstableThe release channel to follow: stable or beta.
OPENENG_UPDATE_CHECK_SECS21600 (6 hours)Seconds between update checks.
OPENENG_SANDBOXworkspace-write if a sandbox works on this machine, else offHow 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_MANDATORYoff1 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_SHELLoff1 lets the agent run shell commands in a working directory that isn't in the engine's trusted list (~/.openeng/trust.json).
OPENENG_RESOURCE_FRACTIONthe config's Resources stepA 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_WRITEoff1 lets write-class MCP tools run without asking; destructive ones still ask.
OPENENG_ROLE_RULESenforceoff turns behavioral roles off on this machine; assign picks roles without applying their rules.

The installer has its own variables (OPENENG_BIN_DIR, OPENENG_ENGINE_URL, OPENENG_NO_MODELS); see Installer options.

Files: the ~/.openeng layout

Everything the engine stores lives under one root, ~/.openeng (/home/<user>/.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 ~/.openeng/terminal.

Each component's folder is resolved in this order:

  1. OPENENG_<COMPONENT>_DIR, when it's set and not blank;
  2. the path your published config sets for it in the Global paths step (Configs); an environment variable always wins over the config;
  3. $OPENENG_HOME/<component>, when OPENENG_HOME is set;
  4. ~/.openeng/<component>.

The overrides combine: OPENENG_HOME=/data/oe with OPENENG_MODELS_DIR=/mnt/big/models puts model weights on the big disk and everything else under /data/oe.

ComponentDefault folderVariableWhat's in it
root~/.openengOPENENG_HOMEEverything below, plus the root files listed after this table
models<root>/modelsOPENENG_MODELS_DIRModel weights: GGUF files, ONNX model folders and Ollama pull markers, with an index.json
threads<root>/threadsOPENENG_THREADS_DIREach chat thread's history, metadata and workspace
memory<root> itselfOPENENG_MEMORY_DIRGlobal learned memory (memory_v2/)
config-state<root>/config-stateOPENENG_CONFIG_STATE_DIRWhat each config version has learned: its memory, dynamic skills and adaptation ledger
skills<root>/skillsOPENENG_SKILLS_DIRYour user-level skills
config<root>/configOPENENG_CONFIG_DIRroles.json, the role-to-model map the engine routes by
catalog<root>/catalogOPENENG_CATALOG_DIRThe model catalog and an encrypted key store
usage<root>/usageOPENENG_USAGE_DIRThe append-only usage ledger (ledger.jsonl)
journal<root>/journalOPENENG_JOURNAL_DIRThe gateway journal, one file per thread
dashboards<root>/dashboardsOPENENG_DASHBOARDS_DIRDashboard definitions
roles<root>/rolesOPENENG_ROLES_DIRThe behavioral-roles pack (not the same as config/roles.json)
agents<root>/agentsOPENENG_AGENTS_DIRAgent profiles
workers<root>/workersOPENENG_WORKERS_DIRThe worker registry
subagents<root>/subagentsOPENENG_SUBAGENTS_DIRThe specialist catalog
research<root>/researchOPENENG_RESEARCH_DIRThe research knowledge store, kept when threads are deleted
logs<root>/logsOPENENG_LOG_DIRReserved for log files (below)
runtime<root>/runtimeOPENENG_RUNTIME_DIRHow the engine finds its model daemon: socket, locks and handshake. Every process involved needs the same value.
cas<root>/casOPENENG_CAS_DIRContent-addressed artifact store
missions<root>/missionsOPENENG_MISSIONS_DIRLong-running goal runs
loops<root>/loopsOPENENG_LOOPS_DIRLoop definitions and run state
fleet<root>/fleetOPENENG_FLEET_DIRFleet identity and state
transmit<root>/transmitOPENENG_TRANSMIT_DIRKeypairs and grants for secure transmission
update<root>/updateOPENENG_UPDATE_DIRA downloaded update waiting for the next start
checkpoints<root>/checkpointsOPENENG_CHECKPOINTS_DIRCheckpoints of resumable runs
maps<root>/mapsOPENENG_MAPS_DIRRepository maps
web<root>/webOPENENG_WEB_DIRDocuments fetched during web research
mcp-tokens<root>/mcp-tokensOPENENG_MCP_TOKENS_DIROAuth tokens for MCP servers, readable only by you
attachments<root>/attachmentsOPENENG_ATTACHMENTS_DIRA cache of delivered attachments

In the current engine, OPENENG_MEMORY_DIR, OPENENG_DASHBOARDS_DIR and OPENENG_WORKERS_DIR have no effect yet: nothing in the served engine writes to those tiers.

Files at the root include:

  • config-cache.json: the last resolved copy of the default config (above).
  • entitlement.json: the last plan information the engine received.
  • ai-config.toml: engine settings, such as threshold_pct under [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:

bash
openeng serve 2>> "$HOME/openeng-engine.log"

Lines worth knowing:

  • boot auth via OpenEng key (registering with …), then registered 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>@<version> READY (…): the models and other resources that config needs are in place. UNAVAILABLE instead 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_UPDATE_CHECK_SECS) it asks releases.openeng.app for the latest engine release on its channel (stable, or OPENENG_UPDATE_CHANNEL) 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_SELF_UPDATE=0 stops the checks, and with them this use of the key. When there's a newer version, it:

  1. downloads it and checks its SHA-256 checksum; a file that doesn't match is never installed;
  2. refuses anything that isn't a native executable for this operating system, such as an error page or a binary for another platform;
  3. stages it in ~/.openeng/update/;
  4. 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_SELF_UPDATE=0 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 printsWhat to do
cannot start: no OpenEng key …Pass --key=<key> or export OPENENG_KEY. Issue a key under Deploy → API keys.
cannot start: empty --keyThe --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 engineThe 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 configThe 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 readyA 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_SANDBOX_MANDATORY=1 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.