Harnesses
The harness is the runtime that executes your agent loop. Swap one line to switch runtimes.
executor:
harness: claude-sdk
Tools, policies, prompts, and models stay the same across harnesses — only the runtime underneath changes.
Two ways to run a harness
Most coding agents can run in one of two modes:
- Direct — Omnigent drives the agent's model and tools itself. You get the full platform: web UI, streaming, contextual policies, persistent sessions, and mobile.
- Native TUI — Omnigent boots the vendor's own terminal UI in a pane and
mirrors it back. You get the exact native experience, wrapped with Omnigent's
collaboration and policy layer. These ids end in
-native.
Supported harnesses
| Agent | Direct | Native TUI |
|---|---|---|
| Claude Code | claude-sdk (alias claude) | claude-native |
| Codex | codex | codex-native |
| Cursor | cursor | cursor-native |
| Antigravity | antigravity | antigravity-native |
| Goose | goose | goose-native |
| Qwen Code | qwen (alias qwen-code) | qwen-native |
| Kimi | kimi (alias kimi-code) | kimi-native |
| Hermes | hermes | hermes-native |
| Pi | pi | pi-native |
| OpenCode | — | opencode-native (alias opencode) |
| Kiro | — | kiro-native |
| Copilot | copilot | — |
| OpenAI Agents SDK | openai-agents (alias openai-agents-sdk) | — |
Pi is a headless multi-model worker that runs on any gateway model — ideal for review, exploration, and read-heavy tasks delegated by a supervisor agent.
Custom ACP agents
Beyond the agents above, the generic acp harness drives any agent that
speaks the Agent Client Protocol — the open,
editor-agnostic protocol used by Gemini CLI, Qwen Code, Goose, Zed's Claude Code
bridge, and in-house agents. You point Omnigent at a launch command and it
speaks ACP against whatever that command starts.
Each ACP agent brings its own auth — Omnigent stores no credential, so log
into the agent through its own CLI first. Register agents with omnigent setup
→ configure harnesses → Custom ACP agent → Add, providing a name, a
launch command, and an optional model. Some paste-ready commands:
| Agent | Command |
|---|---|
| Gemini CLI | gemini --experimental-acp |
| Qwen Code | qwen --acp |
| Goose | goose acp |
| Claude Code | npx -y @zed-industries/claude-code-acp |
Each registered agent is stored in a top-level acp: block of
~/.omnigent/config.yaml and gets a stable slug derived from its name. It then
surfaces as its own harness id, acp:<slug>, in the web picker and in agent
YAML:
acp:
agents:
- { name: Gemini CLI, command: gemini --experimental-acp }
- { name: Claude Code, command: npx -y @zed-industries/claude-code-acp }
- { name: Goose, command: goose acp, model: gpt-5.3 }
executor:
harness: acp:gemini-cli
The agent runs its own agent loop, tools, and context window; Omnigent renders
its streaming output, reasoning, and tool cards, routes its permission requests
through your contextual policies as web elicitation
cards, and honors interrupts. Omnigent also exposes its own builtin tools
(session, sub-agent, skill, and policy tools) to the agent alongside the agent's
native tools; set OMNIGENT_ACP_MCP=0 to disable that bridge.
Note: The generic ACP harness has no fixed binary — each agent owns its own
install and login, so a missing binary is a hint, not a hard gate. A sandboxed
generic ACP agent gets read access to its binary directory, the cwd, and write
access to /tmp; an agent that must write its own config directory needs
sandbox: none (the default) for now.
Swap harnesses
Tools, policies, and other config stay the same across harnesses. Just change the
harness value in your YAML, or override it at runtime:
omni run agent.yaml --harness codex
See Models & Credentials for how to set up API keys and choose models.
Override the harness binary and launch args
By default each harness launches its vendor CLI from your PATH (e.g. claude,
codex). You can point a harness at a specific executable, or prepend base
launch args, from your Omnigent config — ~/.omnigent/config.yaml (user) or
.omnigent/config.yaml (project, takes precedence). View it with
omni config list; set a value with omni config set <key>=<value>.
The top-level harness: config key is polymorphic. The legacy scalar form still
works (and auto-migrates to the mapping form the next time the config is
written):
# Legacy scalar (deprecated, still honored):
harness: claude-sdk
# Mapping form — a default plus per-harness startup overrides:
harness:
default: claude-sdk
codex-native:
command: /usr/local/bin/codex
args: [--config, approval_policy=on-request]
pi-native:
command: /opt/bin/pi
default(optional) — the default harness id foromni run.command(optional) — overrides the vendor CLI executable for that harness.args(optional list) — base launch args; any CLI pass-through args are appended after these.
This top-level harness: config key selects the CLI default and per-binary
launch overrides. It's separate from the executor.harness value inside an
agent's own YAML, which pins the harness for that one agent.
Note: A project's per-harness overrides are deep-merged onto your global
ones — a .omnigent/config.yaml entry augments (rather than replaces) the
matching ~/.omnigent/config.yaml entry, with the project's fields winning.
Binary-path precedence
For a harness's command, the first non-empty source wins:
- The
OMNIGENT_<NAME>_PATHenvironment variable. - The config
harness.<id>.command. - The harness's built-in default executable.
args follow the same idea: the config args are the base, and CLI
pass-through args are appended after them.
<NAME> is the harness's underlying binary, not its id: the -native suffix
is stripped, so pi and pi-native share OMNIGENT_PI_PATH, and the Claude
harnesses map to OMNIGENT_CLAUDE_PATH (so claude-sdk and claude-native
share one var).
Deprecated: The older HARNESS_<NAME>_PATH env vars (for codex, pi,
kimi, goose, qwen, and hermes) are still read as a fallback but log a
warning and will be removed in v0.8.0 — use OMNIGENT_<NAME>_PATH instead.
The omni claude --command flag is likewise deprecated (set
OMNIGENT_CLAUDE_PATH or harness.claude-native.command instead) and will be
removed in a future release. No other native command has a --command flag.
Community harnesses
The built-in harnesses above ship with pip install omnigent. Beyond those,
Omnigent discovers additional harnesses at startup through a plugin registry, so
the community can add support for a new runtime as a separate package —
without changing the core omnigent package.
pip install omnigent # core harnesses only
pip install omnigent-foo # adds the `foo` harness to the same omni CLI
An installed plugin's harness shows up everywhere a built-in one does: it's
accepted in agent YAML, honored by --harness, and merged into the harness
picker in the web UI.
Build a plugin
A harness plugin is a Python package that declares an entry point in the
omnigent.community.harness group and exports a get_contribution() function.
Implementation modules live under the omnigent.community.harness.* namespace.
# pyproject.toml
[project]
name = "omnigent-foo"
dependencies = ["omnigent"]
[project.entry-points."omnigent.community.harness"]
foo = "omnigent.community.harness.foo.plugin:get_contribution"
# omnigent/community/harness/foo/plugin.py
from omnigent.harness_plugins import HarnessContribution
from omnigent.harness_install_spec import HarnessInstallSpec
def get_contribution() -> HarnessContribution:
return HarnessContribution(
name="omnigent-foo",
valid_harnesses=frozenset({"foo"}),
harness_modules={
"foo": "omnigent.community.harness.foo.harness",
},
aliases={"foo-code": "foo"},
harness_labels={"foo": "Foo"},
)
Each harness module exports create_app() -> FastAPI; the runner imports it to
launch the harness. Keep top-level imports in plugin.py light — entry-point
discovery runs early, so put heavy imports inside the callables that need them.
Note: Core rejects plugins that register flat package paths or try to override a built-in harness name. Community native-TUI harnesses aren't pluggable yet — the plugin interface covers direct and headless harnesses.
See the harness plugin interface design doc for the full plugin contract, including install/auth metadata, model-override env vars, and per-spawn environment builders.