Product
Oasis CLI: an AI Coding harness that goes on the machine
Today we are releasing Oasis CLI Harness.
It is a single file you install on the industrial PC you are working on. From there it writes your code, talks to your field devices directly, and tells you whether the machine is actually fit to run what you just built.
The industrial AI gap
AI coding agents have become genuinely good over the last two years. They all share one shape, though: they run on your laptop, and they work on files.
That shape fits web development, where the files really are the product. It fits industrial work badly, because in a plant the files are half the job at most. The rest is the machine: how the kernel schedules, what is actually on the EtherCAT segment, what the registers in the Modbus device hold right now, what that undocumented OPC UA server exposes. None of it is in the repository, so an agent that can only read files cannot see any of it.
What that leaves you doing is couriering. Read a value off the machine, paste it into the chat. Read the answer, type it back into the machine. Watch what happens, report back. The agent is guessing from your description, and you are the only thing joining it to anything real.
The obvious fix is to put the agent on the machine. The reason nobody does is that a coding agent with a shell on a live industrial PC is an alarming idea, and it should be. A careless write goes to a real register, on real hardware, attached to something that moves.
How Oasis CLI Addresses this
We started from that alarm rather than arguing with it. Three things follow, and all of them come from the same decision: the agent runs on the machine, not beside it.
It can reach the plant. Modbus, OPC UA and EtherCAT are tool calls, the same as reading a file. The agent takes its own readings instead of asking you for them.
It can measure the machine. Forty-five conformance checks, most of them about real-time behaviour, turn "is this box fit to hold a control loop?" into a question with an answer, and into a document you can hand a customer.
It is built to be trusted with both. It can start read-only until you approve a plan. Every file operation is sandboxed. Writing to live IO carries a permission tier that cannot be switched off. Every write is logged.
Built for the box it runs on
Oasis CLI (the binary is oasis-agent) is a single static executable, 9.24 MiB, with no runtime to install. You put it on the target and run it there. It has the ordinary things a coding agent has: read, write, edit, grep, glob, shell sessions. Those tools do not care what language they are looking at, and neither does the agent. Rust, C, Python, shell, the ladder export nobody wants to touch.
What is not language-agnostic is the domain knowledge, and that is deliberate. It arrives as skills: ten of them, loaded on demand, each written for a job that goes wrong in a specific way:
| Skill | For |
|---|---|
rt-provisioning | Making a machine real-time capable: distro RT kernel, mainline PREEMPT_RT, or runtime preemption switching, and which of those a vendor-kernel board can actually take |
rt-tuning | A box that fails its checks or is over its jitter budget. Reads a check report and orders the fixes |
rt-control-loop | Writing a loop that must hold a cycle: scheduling, memory locking, safe state on overrun, exporting the loop's own timing |
structured-text | IEC 61131-3: the scan-cycle model, the syntax traps that look like C and are not, portable dialect versus vendor extensions |
ethercat-bringup | A segment that will not reach OP, or needs checking before it is trusted |
ethercat-application | Driving a segment: master stack, addressing, state machine, safe state on bus fault |
modbus-debug | Transport, unit id, addressing and encoding, in the order that finds faults fastest |
plc-test | Validating control logic against a reachable slave, and restoring the device afterwards |
opcua-commission | Discovery, certificates, identity, address space, security posture |
check-triage | What a verdict actually licenses you to claim, before you report it to anyone |
The rt-provisioning skill is a good example of why this is not documentation with extra steps. Its first job is to stop the agent confusing PREEMPT_DYNAMIC with PREEMPT_RT. They are two unrelated mechanisms with near-identical names, and picking the wrong one costs you a boot. That is the kind of mistake a general model makes confidently, and it is exactly the kind a harness can prevent.
Because building on a live machine is scary
It can start read-only. --plan refuses every mutating tool until the agent has presented a plan and you have approved it. You read what it intends to do before anything is touched.
Every file tool runs behind a realpath sandbox rooted at --cwd. Symlinks are resolved before the check, not after, so the classic escape does not work.
Tools carry risk tiers, and one of them cannot be waived. Safe reads batch in parallel; anything that mutates serialises behind a permission prompt. The active EtherCAT plane, meaning writing IO or forcing a segment operational, carries a HardStop tier, and --skip-permissions does not waive it. If you have decided to run unattended, that decision still does not extend to driving outputs.
Every write is logged, one actor-stamped JSONL line per operation, so afterwards there is a record of what changed and who asked for it.
Then there is the half that answers the question you actually have about the machine: is it fit to run this? Oasis CLI ships 45 conformance check descriptors across five modules. Thirty-three of those are for PREEMPT_RT alone, covering preemption mode, isolcpus effectiveness, RT throttling, timer migration, C-states, SMT, IRQ affinity, runqueue delay, measured jitter against a budget, and control-loop cycle time and overruns. The rest cover OPC UA, EtherCAT, Modbus and the IEC 61131 toolchain.
Three properties of that catalogue are enforced rather than promised, and they are the reason it is worth trusting:
- Confidence is checked when the descriptor loads. A check whose criteria are only a proxy for the property in its title cannot claim to have proven it. It fails to load rather than quietly overstating itself.
- A non-answer is never a pass. A missing tool, a probe that produced no number, a command that would not start, all report
not_applicableorerror, with a reason. None of them ever produces a green tick. - A failure arrives with what to do about it. Descriptors carry framework mappings (IEC 62443-3-3, NIST SP 800-53) and written remediation.
The Audit tool turns a profile of those checks into the document you hand a customer. It states its own limits, keeps everything it could not assess in a section of its own rather than omitting it, and is byte-stable apart from a single timestamp line, so two runs of the same audit diff cleanly.
That last property sounds like a detail. It is the difference between a report you can put under version control and a report you have to read in full every time.
Optimised for Smaller Local Models
--base-url is required and has no default. There is no address baked into this binary for it to phone home to. You choose where the model runs: your own hardware and your own weights over any OpenAI-compatible endpoint, or Magnum 1 if you would rather we ran it in your environment for you.
Running a smaller, self-hosted model well is a different engineering problem from calling a frontier API, and most of our work went into two things.
The first is the harness itself. A strict tool contract, a versioned system prompt, and a soft-nudge family that catches the failure modes small models actually have: repetition that escalates to a refusal, checkpoint and delegation prompts, and an unverified-claim nudge for when the model asserts something it has not checked. At most one nudge lands per iteration. The result is that a smaller model is held to the same shape of answer as a larger one.
The second is the prompt cache, which we treat as the first-class citizen of the whole design. The system prompt, the tool registry, tool schemas, registration order and history rendering are all held stable, because any one of them turning over invalidates the entire prefix. The numbers are the argument:
- A turn boundary costs 134 ms at 100% prefix reuse, against 17.2 s at 0%. Two orders of magnitude.
- Steady-state reuse measures 94–100%, turn boundaries included.
- Process start to first inference request is 24 ms at p50.
- In persistent mode a turn lands in about 0.35 s.
Context reclamation is built to protect the same property. Eviction runs first and is lossless: drop old tool results, keep the last three, never evict a pinned one, and only commit when the reclaim beats the cache churn it causes. Summarising compaction is the second tier, and its pinned head survives byte-identical so the prefix is not invalidated from token zero. Measured across four consecutive live compactions, reuse stayed at 81–100%.
None of that is a faster model. It is the same model, not made to re-read its own preamble.
Protocols are tool calls, not a project
Fourteen protocol tools across three packs, callable exactly like Read or Bash:
| Pack | Tools | What it means in practice |
|---|---|---|
| Modbus | ModbusRead, ModbusWrite | The agent reads a holding register and reasons about the value, instead of asking you to read it and paste it back |
| OPC UA | OpcUaBrowse, OpcUaRead, OpcUaWrite | It can walk the address space itself, so "what nodes does this server actually expose?" is a question it answers rather than asks |
| EtherCAT | EtherCatScan, EtherCatIdentify, EtherCatSdoRead, EtherCatSdoWrite, EtherCatReadIo, EtherCatWriteIo, EtherCatPulseIo, EtherCatGoOperational, EtherCatStopIo | Scan a segment, identify what is on it, read and write SDOs, drive IO by hand to check wiring, take the segment to OP |
The benefit is the one you feel on day one: there is no integration layer to write before the real work starts. On a normal project, "let the tooling talk to the bus" is itself a week of work: a library, a wrapper, a script to parse a vendor CLI's output. All of it happens before anyone has automated anything.
Two design decisions are worth naming.
Each pack carries its own prober. A protocol claim is measured by this process, on this machine, rather than parsed out of another program's stdout. Vendor CLI output is not a stable interface, and scraping it means a formatting change becomes a wrong reading rather than an error.
EtherCAT vendor identification needs no configuration. The ETG's published vendor register is compiled into the binary. Product names are not, because there are tens of thousands of parts and they revise constantly, so product_name comes back null with a reason and a remedy until you point the agent at a directory of vendor ESI XML. That is the same principle as the checks: the honest null, not the confident guess.
From a Raspberry Pi to an industrial PC
One static binary, no runtime dependencies, three architectures:
- x86-64: industrial PCs, rack-mount servers, ordinary workstations
- ARMv8 / AArch64: 64-bit ARM edge controllers
- ARMv7: 32-bit ARM, including older single-board computers
It also runs under WSL 2 on Windows, which is usually how people try it before they put it on hardware.
The same binary, the same tool surface, and the same checks whether the target is a Raspberry Pi on a bench or a controller in a cabinet. Nothing is compiled out for the small board.
It talks to the rest of your stack
Oasis CLI speaks MCP, the Model Context Protocol, so the systems your team already runs become tool calls alongside the built-in ones. --mcp-config autoloads tools from any number of servers over stdio or Streamable HTTP, with OAuth 2.1 and PKCE for remote ones. Run --mcp-login once from a machine with a browser, and headless runs on the plant floor reuse the cached tokens.
Why it matters: the context an engineer needs is rarely all in the repository. It is in the historian, the ticketing system, the asset register, the internal wiki. MCP is how those reach the agent without anyone writing a bespoke integration for each one.
Two details we handled carefully, both in service of the cache. MCP tools are namespaced mcp__<server>__<tool> and appended after the built-ins, so adding a server does not move the cached schema prefix. And a server that fails to connect is skipped rather than fatal, unless you mark it required, which you should for any server whose absence would quietly reshape what the agent can do.
Free
Oasis CLI Harness is free to download and free to use, on as many machines as you like. No trial, no seat count, no licence key, and no plan to add one. Install it with a single line:
curl -fsSL https://get.mutexer.com/oasis/install.sh | bash
It installs under your home directory and refuses to run under sudo, because everything it needs lives in your home and installing as root would put the command somewhere your own shell cannot find it.
What it costs to run is whatever your endpoint costs, and nothing at all if you host the model yourself on hardware you already own.
Every published build, with checksums for each platform, is on the Oasis CLI releases page.
The shift from hardware-defined to software-defined automation has been running for a decade, and the part that has lagged is not the hardware or the models. It is the tooling in between: the layer that has to be trusted enough to point at a live machine.
That is the layer we are working on. If you put Oasis CLI on a box and it tells you something useful, or tells you something wrong, we would like to hear about it.