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:

Supported harnesses

AgentDirectNative TUI
Claude Codeclaude-sdk (alias claude)claude-native
Codexcodexcodex-native
Cursorcursorcursor-native
Antigravityantigravityantigravity-native
Goosegoosegoose-native
Qwen Codeqwen (alias qwen-code)qwen-native
Kimikimi (alias kimi-code)kimi-native
Hermeshermeshermes-native
Pipipi-native
OpenCodeopencode-native (alias opencode)
Kirokiro-native
Copilotcopilot
OpenAI Agents SDKopenai-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.

Grok Build

Grok Build (xAI's grok CLI) ships as a builtin harness with the id grok (alias grok-build). Under the hood it drives grok agent stdio over the Agent Client Protocol — Omnigent renders its streaming output, reasoning, and tool cards and routes its permission requests through your contextual policies, just like the generic acp harness below. The difference is that it's built in: you select the grok harness id directly instead of registering a launch command.

omni run --harness grok

Like the generic ACP agents, Grok Build brings its own auth and model — Omnigent stores no credential and a /model pick is rejected up front. Install the CLI and log in through xAI first:

curl -fsSL https://x.ai/cli/install.sh | bash
grok login --device-auth   # xAI OAuth (device-code capable); or set XAI_API_KEY

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 setupconfigure harnessesCustom ACP agentAdd, providing a name, a launch command, and an optional model. (To pull agents in from an existing OpenClaw/acpx registry instead of typing each one, see Import agents from OpenClaw below.) Some paste-ready commands:

AgentCommand
Gemini CLIgemini --experimental-acp
Qwen Codeqwen --acp
Goosegoose acp
Claude Codenpx -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 for a session.

To disable that MCP relay permanently for a specific agent, set omnigent_mcp: false on its acp: entry. The agent keeps its own native tools; Omnigent simply stops lending its builtin tools to that agent in session/new (the field is still sent as an empty list, which ACP requires). This is required for agents whose ACP server rejects per-session MCP servers — such as the OpenClaw Gateway bridge described below. The value must be a boolean; omnigent setup reports an error if it isn't.

acp:
  agents:
    - name: OpenClaw
      command: openclaw acp --url <gateway-url> --token-file <token-file>
      omnigent_mcp: false

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.

Import agents from OpenClaw

If you already keep an agent registry for OpenClaw or the acpx CLI, Omnigent can import those agents into its acp: block instead of re-adding each one by hand. Run omnigent setupconfigure harnessesImport from OpenClaw. The row shows how many agents were detected automatically. Omnigent looks in two default locations:

SourcePath
acpx~/.acpx/config.json
OpenClaw~/.openclaw/openclaw.json

Both files are read as JSON5, and you can pick Choose another file… to point at a config elsewhere. Omnigent lists the agents it found, derives a stable slug from each name, and — after you confirm — appends them to the acp: block of ~/.omnigent/config.yaml. From then on they behave exactly like manually added ACP agents.

Import stores only the launch command, not credentials — each agent still authenticates through its own CLI. Re-running the import is safe: agents already present are skipped, and a new agent whose name collides with an existing slug gets a numbered suffix (e.g. gemini-cli-2) so nothing is overwritten. An agent whose binary isn't on your PATH is flagged as a hint, not blocked.

To launch a single OpenClaw/acpx agent once without saving it to your config, use --from-openclaw on omni run:

omni run --from-openclaw "Gemini CLI" -p "review the last commit"

Match the agent by its display name (case-insensitive) or derived slug. This runs the agent through the acp harness for that one session; it can't be combined with an AGENT path or with --harness.

This path drives the selected coding agent directly. It does not bring OpenClaw's Gateway session, routing, memory, or channels into the conversation — for that, register the Gateway bridge (below).

Drive the OpenClaw Gateway

Beyond importing individual coding agents, the openclaw acp command exposes a live OpenClaw Gateway session as an ACP server over stdio, giving Omnigent access to OpenClaw's own routing, memory, and channels. Register it as an acp: agent, disabling Omnigent's MCP relay because the Gateway bridge rejects per-session MCP servers:

acp:
  agents:
    - name: OpenClaw
      command: openclaw acp --url <gateway-url> --token-file <token-file>
      omnigent_mcp: false

Replace <gateway-url> and <token-file> with your running Gateway's connection details, then launch it:

omni run --harness acp:openclaw

Caution: Prefer --token-file so the Gateway token isn't stored in the launch command. Don't commit or share ~/.omnigent/config.yaml, and use a token with the narrowest permissions OpenClaw supports.

Omnigent owns the outer conversation and transcript; OpenClaw owns the Gateway-backed session. OpenClaw's Control UI is a separate Gateway client, so messages entered there while Omnigent is offline are not imported into the Omnigent conversation — use Omnigent as the canonical conversation when you need its transcript and resume behavior. Bidirectional sync with the Control UI and per-session Omnigent MCP are not supported by this integration.

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

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:

  1. The OMNIGENT_<NAME>_PATH environment variable.
  2. The config harness.<id>.command.
  3. 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.