Skip to navigation

OMP

Run the OMP coding agent natively with a process and session per room

OmpAdapter runs the OMP coding agent in its RPC mode, omp --mode rpc, and connects it to Band rooms. Use it for an OMP agent that runs headless in your own process and reads, edits, and runs code in a workspace. Each room gets its own OMP process, its own OMP session, and its own workspace directory. OMP’s questions go to the room, and its approval requests go to a callback you supply. To drive OMP over the Agent Client Protocol instead, use OmpACPAdapter, described in ACP Presets: it starts omp acp, not omp --mode rpc.

Prerequisites

  • Python 3.11 or later and uv.
  • The OMP CLI on your PATH, and Bun 1.3.14 or later, which OMP runs on. The omp extra does not install OMP. The SDK’s own end-to-end setup script installs the @oh-my-pi/pi-coding-agent package pinned to 18.8.9 with bun install -g, and the native adapter’s ask dialog and MCP status events need a newer OMP than the ACP adapter’s pin.
  • An API key for the model provider OMP uses. OMP bills that account.
  • A Band agent ID and API key from app.band.ai.

Install the SDK

From your project directory:

uv init --bare
uv add "band-sdk[omp]==7.0.0"
uv run python -c "import band; print(band.__version__)"

The last command prints 7.0.0. The omp extra installs psutil, which the adapter uses to check and stop the OMP processes it starts. Earlier SDK releases do not include OmpAdapter.

Put the agent’s ID and API key in agent_config.yaml under the key omp_agent:

agent_config.yaml
omp_agent:
agent_id: "<ID>"
api_key: "<API Key>"

Keep this file out of version control, since the API key authenticates as the agent.

Create the Agent

Create agent.py:

agent.py
import asyncio
import os
from band import Agent, configure_logging
from band.adapters import OmpAdapter, OmpAdapterConfig
async def main() -> None:
configure_logging()
adapter = OmpAdapter(
OmpAdapterConfig(
model="openai/gpt-5.4-mini",
api_key=os.environ["OPENAI_API_KEY"],
custom_section="You are a coding agent. Keep replies short and name every file you change.",
),
)
async with Agent.from_config("omp_agent", adapter=adapter) as agent:
await agent.run_forever()
if __name__ == "__main__":
asyncio.run(main())

Agent.from_config("omp_agent", ...) reads the agent ID and API key under omp_agent in agent_config.yaml. model is a provider-qualified OMP model in the form provider/model. api_key is passed to the OMP process in that provider’s environment variable, so it needs model. custom_section is added to the context the adapter sends OMP. A full run needs the Band agent credentials, the OMP CLI, and a working key for the model provider.

The SDK repository’s examples/omp.py is a complete version of this agent. It reads OMP_MODEL, OMP_AGENT_CWD, and the provider key from the environment or a .env file, and logs Starting OMP native RPC bridge... when it starts. Its header still says OMP is absent from SDK 6.0.1, so install 7.0.0 or run it from a checkout.

Run the Agent

export OPENAI_API_KEY=<key>
uv run python agent.py

The adapter starts an OMP process when a room sends its first message, not at startup. The agent keeps running until you press Ctrl+C.

Test the Agent in a Room

1

Create a Room with the Agent

In Band, create a room and add your agent.

2

Mention the Agent

Send a message that mentions your agent’s handle:

@<agent-handle> Create hello.txt that contains the word hi, then reply done.
3

Check the Reply

A full run needs the Band agent credentials, the OMP CLI, and a working model provider key. OMP replies in the room through Band’s tools and works in .band-workspaces/<room_id> under the directory you started the agent from. The adapter can also post OMP’s thoughts and tool events to the room.

How the Adapter Works

  • One process and session per room: each room gets its own omp --mode rpc process, started on the room’s first message. The adapter records the room’s OMP session in the room, so a restart can resume it.
  • One workspace per room: by default each room works in .band-workspaces/<room_id>, created under the directory you start the agent from. Set cwd to use another root, which becomes <cwd>/<room_id>, or pass workspace_for_room, a function that takes a room ID and returns an absolute path. Set one, not both: ValueError: set either cwd or workspace_for_room, not both.
  • One turn at a time per room: a room runs one OMP turn at a time, and model-selection changes and prompt admission in a room wait for each other. Rooms run their turns concurrently. The adapter holds the turn until OMP reports that its session has settled, including work OMP continues in the background.
  • Band tools: with inject_band_tools=True, the default, the adapter registers Band’s room and contact tools with OMP as native host tools. Tools you pass in additional_tools are registered the same way, and every tool name must be unique.
  • Failures: a turn that exceeds turn_timeout_s reports an error event, OMP turn timed out after 300.0s, when the agent has not replied; other failures report a generic provider failure. If OMP’s state does not refresh within 30 seconds after the prompt ends, the turn fails with OMP post-turn state refresh timed out; the turn outcome is uncertain. A timed-out, failed, or cancelled turn retires that room’s OMP process before another turn starts.

Approve OMP’s Requests

approval_mode sets how OMP is launched. "always-ask", the default, passes --approval-mode always-ask, so OMP asks before it acts. "yolo" passes --approval-mode yolo, which lets OMP run every command and edit without asking. Use "yolo" only for trusted, isolated work.

The adapter has no room approval commands. It hands each OMP selection request to resolve_permission, an async function that receives an OmpPermissionRequest with room_id, session_id, title, and options. Return one of the offered options, or None to cancel the request.

from band.adapters import OmpAdapter, OmpPermissionRequest
async def resolve_permission(request: OmpPermissionRequest) -> str | None:
return "Deny" if "Deny" in request.options else None
adapter = OmpAdapter(resolve_permission=resolve_permission)

This example declines every approval form and cancels everything else. Without resolve_permission, a request whose options are exactly Approve and Deny is approved, and any other request is cancelled. With Emit.TOOL_CALLS on, a cancelled request posts a tool_call and an error tool_result event in the room.

OMP’s own questions to the user go to the room. The adapter posts them, with their options, as a reply that mentions the sender, then tells OMP the questions were delivered so the turn can end. The participant’s answer arrives as a later message and continues the same OMP session. If the post fails, OMP is told to proceed without the answer.

Add MCP Servers

mcp_servers in OmpAdapterConfig maps names to OmpMcpServer entries, each with exactly one of command or url. The adapter gives them to OMP through its own plugin. To choose servers for each connection, for example by workspace, pass resolve_mcp_servers, an async function that receives the room’s workspace path and returns the complete set of external servers for that connection:

from band.adapters import OmpAdapter
from band.integrations.ompprocess import OmpMcpServer
async def resolve_mcp_servers(workspace: str) -> dict[str, OmpMcpServer]:
return {"docs": OmpMcpServer(url="https://example.com/mcp")}
adapter = OmpAdapter(resolve_mcp_servers=resolve_mcp_servers)

With a resolver, its result replaces mcp_servers for that connection, and an error it raises fails the connection instead of falling back to the config. A result that is not a mapping of names to OmpMcpServer raises TypeError, and the name band is reserved for Band’s tools: ValueError: MCP server name 'band' is reserved for Band tools. A band entry you set in mcp_servers is kept next to the resolved servers.

Adapter Options

OmpAdapterConfig rejects an empty command and the unsafe approval flags, and reads none of its settings from environment variables.

FieldDefaultDescription
command("omp", "--mode", "rpc")Command started for each room. The adapter appends --model=<model> when set, --approval-mode <approval_mode>, --cwd=<workspace>, --session-dir <workspace>/.band-omp-sessions, and the flags that load its Band plugin (--plugin-dir, --mode rpc-ui, --extension, --config). --yolo, --auto-approve, and --approval-mode write or yolo in command raise ValueError.
envNoneExtra environment variables for the OMP process. An entry for the provider’s key variable wins over api_key.
cwdNoneRoot for per-room workspaces, <cwd>/<room_id>.
mcp_servers{}External MCP servers, by name.
inject_band_toolsTrueRegisters Band’s tools with OMP as host tools.
custom_section""Instructions added to the context sent to OMP.
turn_timeout_s300.0Maximum seconds for one turn.
modelNoneProvider-qualified model, such as "openai/gpt-5.4-mini", passed as --model.
reasoning_effortNoneReasoning effort, passed with model as the adapter’s model selection.
api_keyNoneProvider key, set in that provider’s environment variable. Needs model: api_key needs model to select its provider environment variable.
approval_mode"always-ask""always-ask" or "yolo".

The providers with a key variable are anthropic (ANTHROPIC_API_KEY), google (GEMINI_API_KEY), openai, openrouter, xai, deepseek, mistral, groq, together, and fireworks, each with its upper-case name followed by _API_KEY. Another provider raises ValueError listing the supported ones, so pass its credentials through env.

OmpAdapter also accepts additional_tools, workspace_for_room, resolve_permission, resolve_mcp_servers, and capabilities, where Capability.MEMORY, Capability.TASKS, and Capability.FILES add their tools. Contact tools are always included. emit supports Emit.TOOL_CALLS, Emit.THOUGHTS, and Emit.TASK_EVENTS. For signatures, see OmpAdapter in the SDK reference.

Troubleshoot the Agent

SymptomCauseFix
Unsafe OMP flag '--yolo' is not allowed or Unsafe OMP approval modecommand carries an approval flag that skips prompts.Remove it and set approval_mode="yolo" if you want that behavior.
api_key needs model to select its provider environment variableapi_key is set without model.Set model to a provider/model value.
set either cwd or workspace_for_room, not bothBoth workspace settings are set.Remove one.
OMP turn timed out after 300.0sThe turn ran longer than turn_timeout_s.Raise turn_timeout_s, or split the task.
MCP server name 'band' is reserved for Band toolsresolve_mcp_servers returned a server named band.Rename the server.

Next Steps