Dome Systems

Use Dome as a model broker

Let Cursor, Claude Code, or Codex call any model with your provider key held server-side and every completion audited.

Your assistant already calls a model every time you chat with it. That call carries its own problems: a provider key sitting in the client's config, spend nobody notices until the invoice, and a model locked to whatever provider the client shipped with.

Hand this to an AI agent. It registers itself as a Dome agent, holds a provider key in Dome, and rewrites its own model configuration to go through Dome.

Open in Cursor

In this tutorial, you will hold a provider key in Dome, register your assistant, and repoint its own inference (not a script, the assistant itself) at the Dome gateway. The provider never learns Dome is in front of it; it just sees a different caller.

Prepare your environment

Sign in and provision a disposable workspace.

Add a model connection

Register a provider model and hold its key in Dome.

Create the agent

Register an agent for your assistant and mint its API key.

Authorize inference

Grant Gateway access and permit llm:invoke.

Point your assistant at Dome

Rewrite Cursor, Claude Code, or Codex's own model configuration.

Verify the results

Make one completion and confirm the audit event.

Prerequisites

For this tutorial, you will need:

  • The Dome CLI. Refer to Install for Homebrew and direct-download instructions.
  • A role that can provision a sandbox and deploy rules: admin, operator, or equivalent.
  • An API key for OpenAI, Anthropic, or both. Dome calls the provider on your behalf, so the spend lands on your provider account. A key for each provider lets you try swapping which model answers a given client, later in this tutorial.
  • Cursor, Claude Code, or Codex, each configurable with a custom model base URL and key.

Prepare your environment

Sign in and provision a throwaway sandbox:

dome auth login
dome sandbox provision --scope=workspace --workspace-name connect-assistant
dome context sync
dome context use sandbox-connect-assistant

If you already have sandbox-connect-assistant from Use Dome as an MCP gateway, reuse it. This tutorial does not touch that Gateway's tools.

Confirm the workspace before continuing:

dome context current

Add a model connection

A model connection is one upstream LLM endpoint and the credential Dome uses to reach it. The endpoint a client points at is a wire protocol, not a provider. Dome's Anthropic-shaped endpoint and its OpenAI-compatible endpoint can each resolve to any connection you name. The model behind a connection does not have to match the client calling it.

Add whichever provider you have a key for. Add both if you want to try the swap later in this tutorial:

dome models add claude-broker \
  --provider anthropic \
  --model claude-3-5-sonnet-20241022 \
  --api-key "$ANTHROPIC_API_KEY" \
  --gateway Default
dome models add openai-broker \
  --provider openai \
  --model gpt-4o \
  --api-key "$OPENAI_API_KEY" \
  --gateway Default

--gateway Default attaches it directly, without a pool. A pool buys you failover and weighted routing across several connections. Reach for one once you have more than one model to route across; a single connection does not need it.

Confirm the connection is registered:

dome models get claude-broker   # or openai-broker

Create the agent

Every call through a Gateway is authorized and audited against this agent identity, not against Cursor, Claude Code, or Codex as a product.

Register an agent for your assistant, then mint a credential:

dome agents register --name code-assistant --if-not-exists
dome agents create-key code-assistant --name model-client

The Token: dome_… value is shown once. Save it. You paste it into your client's model configuration in a few steps.

Use Dome as an MCP gateway uses a different identity path: interactive sign-in instead of a static key. The two tutorials are independent; running one does not create the agent the other expects.

Authorize inference

Grant access to the Gateway if you have not already:

dome gateways access grant Default code-assistant

llm:invoke is a separate action from mcp:call, so a tool-calling permit does not cover inference.

Create code-assistant-llm.cedar:

code-assistant-llm.cedar
permit(
  principal is Dome::Agent,
  action == Dome::Action::"llm:invoke",
  resource is Dome::LLMModel
);

resource is Dome::LLMModel scopes the permit to this workspace's model connections, not a specific one, so adding a second model later needs no rule change.

Deploy it scoped to this agent:

dome rules apply code-assistant-llm.cedar --agent code-assistant --name code-assistant-llm

Point your assistant at Dome

Each client reads its base URL and key differently.

One call resolves both base URLs, so there is nothing to assemble by hand:

dome gateways get Default --json

Copy endpoints.anthropic_base_url for Claude Code, or endpoints.openai_base_url for Cursor and Codex. {AGENT_API_KEY} is the dome_… token from the previous step.

The client and the model are independent. Every client below asks for a Dome connection by name, not a vendor model id. Claude Code can request openai-broker and run GPT through its native Anthropic-shaped interface. Codex or Cursor can request claude-broker and run Claude through their OpenAI-shaped one.

Codex speaks the OpenAI-compatible protocol Dome exposes at endpoints.openai_base_url. Its model setting names a Dome connection, not a vendor model id.

Use openai-broker for its native GPT connection, or claude-broker to have Codex run Claude instead.

Terminal. Export the agent token in the shell that launches codex, then add Dome as a provider in ~/.codex/config.toml:

export DOME_AGENT_TOKEN="AGENT_API_KEY"
~/.codex/config.toml
[model_providers.dome]
name = "Dome"
base_url = "OPENAI_BASE_URL"
env_key = "DOME_AGENT_TOKEN"
wire_api = "chat"

model_provider = "dome"
model = "openai-broker"   # or "claude-broker"

Desktop / IDE extension. A GUI-launched Codex does not inherit variables exported in a terminal session, so env_key needs the token available at the OS level.

Set it once, then restart the app so it picks up the change:

# macOS
launchctl setenv DOME_AGENT_TOKEN "AGENT_API_KEY"

On Windows or Linux, set it from your system's environment variable settings instead. The config.toml block above does not change. Only how the token reaches the process does.

Claude Code speaks the Anthropic protocol Dome exposes at endpoints.anthropic_base_url. ANTHROPIC_MODEL names a Dome connection the same way.

Set it to claude-broker for its native connection, or to openai-broker to have Claude Code run GPT instead.

Terminal. Export all three in the shell that launches claude:

export ANTHROPIC_BASE_URL="ANTHROPIC_BASE_URL_VALUE"
export ANTHROPIC_API_KEY="AGENT_API_KEY"
export ANTHROPIC_MODEL="claude-broker"   # or "openai-broker"

Desktop / IDE extension. A GUI-launched Claude Code does not inherit a terminal's exported variables.

Write the same three values into ~/.claude/settings.json instead, under env:

~/.claude/settings.json
{
  "env": {
    "ANTHROPIC_BASE_URL": "ANTHROPIC_BASE_URL_VALUE",
    "ANTHROPIC_API_KEY": "AGENT_API_KEY",
    "ANTHROPIC_MODEL": "claude-broker"
  }
}

Claude Code reads this file on launch, so it covers the IDE extension the same way the exports cover the terminal.

Open Cursor Settings → Models and add a custom OpenAI-compatible model for each connection you want to reach:

  • API key: AGENT_API_KEY
  • Override OpenAI Base URL: OPENAI_BASE_URL (endpoints.openai_base_url from the command above)
  • Model name: openai-broker or claude-broker

Add both as separate custom models and pick whichever one you want per chat. Cursor sends the name you typed as-is; Dome resolves it to that connection regardless of the underlying provider.

Verify the results

Restart your client, then ask it anything.

The response itself proves nothing about the path, so check audit instead:

dome audit query --limit 5

Expect a completed model.call event naming claude-broker or openai-broker, attributed to code-assistant, with token usage. If you set ANTHROPIC_MODEL=openai-broker or pointed Codex at claude-broker, that event is the proof. The client's native provider and the model that actually answered are different, and Dome is what bridged them.

Next steps

Your assistant's own inference (not just a demo script) now runs through Dome. Continue with:

On this page

Was this page helpful?