Agents and models
How Hubzoid defines the main agent and sub-agents, when a sub-agent becomes a delegate on its own model, and how runtimes and providers are chosen.
Every Hub has one main agent, defined by AGENTS.md, and any number of sub-agents in agents/. The model id decides which of three runtimes runs them: the OpenAI Agents SDK with LiteLLM, the Claude Agent SDK with your claude CLI, or local Codex with your codex CLI. The Hub files are the same on each.
The main agent
AGENTS.md at the Hub root is the main agent. Its body is the system prompt, and its frontmatter sets the name, description, model and chat suggestions. Every surface talks to the main agent. It holds the full tool registry and decides when to load a skill or call a delegate.
---
name: ops-desk
description: Answers operations questions and prepares the weekly review.
model: claude-local
suggestions:
- What changed in stock this week
---
You help the operations team. Use the knowledge documents for thresholds,
and load the weekly-review skill when someone asks for the weekly review.The project structure page lists every frontmatter field.
Sub-agents
A sub-agent is a Markdown file in agents/, either agents/<name>.md or agents/<name>/AGENTS.md when it has supporting files. It uses the same frontmatter as the main agent, plus tools.
---
name: researcher
description: Writes a short, sourced brief when someone asks for research on a topic.
model: claude-local/opus
tools: [web_search, http_get, read_knowledge]
---
Research the topic you are given. Use at most five sources and cite each one.
Return a brief of no more than 300 words with the sources listed at the end.| Field | Purpose |
|---|---|
name | Identifier. Defaults to the file or folder name. |
description | When to use this sub-agent. The main agent sees it in its skill or delegate menu. |
model | Optional. Decides whether the sub-agent runs as a skill or as a delegate. |
tools | Optional list of tool names a delegate may call. Ignored when the sub-agent runs as a skill. |
Skill or delegate
Hubzoid classifies each sub-agent when it builds the agent. The rule depends only on the sub-agent's model: compared with the Hub's model.
Sub-agent model: | Runs as | Behavior |
|---|---|---|
| Not set | Skill | The main agent loads its body with load_skill and follows it in the same turn. |
| Same model as the Hub | Skill | As above. |
A different engine (for example a claude-local id on a LiteLLM or codex-local Hub) | Skill | As above. A sub-agent never switches runtime. |
| A different model on the same engine | Delegate | Runs on its own model in its own context and returns a result to the main agent. |
For example, on a Hub running claude-local (Sonnet), the researcher above has model: claude-local/opus, so it becomes a delegate that runs on Opus. On a Hub running openai/gpt-4o-mini, a sub-agent with model: openai/gpt-4o is a delegate, and one with model: claude-local/opus is a skill. On a Hub running codex-local, a sub-agent with model: codex-local/<model-id> is a delegate on that Codex model.
A skill-classified sub-agent is added to the skill menu. If a skill in skills/ has the same name, the one in skills/ wins and a warning is logged.
How delegation works
The main agent keeps control. It calls a delegate within the turn with a brief, the delegate works in isolation on its own model, and its final message comes back as the result. The runtime addendum lists each delegate with its model and tells the main agent to relay the answer faithfully.
| OpenAI Agents runtime | Claude Agent runtime | Codex runtime | |
|---|---|---|---|
| Mechanism | The delegate is a tool named handover_<name>, built with the Agents SDK's agent-as-tool pattern. | The delegate is a native Claude sub-agent on its tier (opus, sonnet, haiku or a full claude-* id), dispatched through Claude's sub-agent tool. | The delegate is a tool named handover_<name> that runs a separate Codex request on the delegate's model. |
| Tools | The tools: list, intersected with the Hub's tools. Unknown names are dropped with a warning. With no list, every Hub tool. | Same rule. | Same rule. |
| Restricted tools | Guarded exactly as for the main agent. | Same. | Same. |
| If its model cannot be built | Missing provider key or another build error: the sub-agent is loaded as a skill instead, and the Hub still starts. | Not applicable. The tier is passed to the CLI. | Not applicable. The model is passed to Codex. |
Delegates are not exposed over MCP, because an MCP caller brings its own model. There, every sub-agent is a skill. A delegate never receives the person's own personal MCP connections. Only the main agent does.
Runtimes
| OpenAI Agents SDK | Claude Agent SDK | Local Codex | |
|---|---|---|---|
| Chosen when | The model id does not start with claude-local or codex-local | The model id is claude-local or claude-local/<pin> | The model id is codex-local or codex-local/<model-id> |
| Model calls | Through LiteLLM | Through the claude CLI, started as a subprocess | Through the Codex CLI's app-server, pinned to Codex CLI 0.147.0. Each request gets its own short-lived thread and an isolated configuration folder. |
| Authentication | The provider key in .env | claude login on the machine, CLAUDE_CODE_OAUTH_TOKEN, or ANTHROPIC_API_KEY | A file-backed codex login by the account that runs the Hub, read from $CODEX_HOME/auth.json (by default ~/.codex/auth.json). Keychain-only logins are not supported. |
| Hub tools | Function tools on the agent | An in-process MCP server named hubzoid. Claude Code's own tools (Bash, Read, Edit and so on) are disabled, and Claude Code settings files are not read. | Offered to Codex as dynamic tools that Hubzoid runs. Codex's own shell, file, browser and web search tools are disabled, and the login's personal Codex settings, MCP servers, skills and hooks are not used. |
| MCP connectors | Connected when the bridge starts. A server that fails to connect is dropped with a warning. | Passed to the SDK, which manages the connections. Only the servers Hubzoid passes are used, never the connectors or MCP settings of the Claude account the machine is signed in to. | Connected by Hubzoid, which adds their tools to the ones it offers Codex. |
| Turn limit | 20 agent turns per chat turn | Set by the SDK unless a scheduled run passes its own limit | 20 tool calls per request by default, and five minutes per request |
All three runtimes stream text and tool activity in the same format, record token usage per turn, and use the same access guard. Each one shows the agent only the controlled tools (restricted/ tools, remember, call_jev) the person may use, and refuses any other call. The architecture page shows where the runtime sits in a request.
Choosing the model
The Hub's model is resolved in this order. The first one set wins.
- A per-run override: a markdown task's
model:frontmatter, orhubzoid schedule run --model. MODELin the Hub's.env.model:inAGENTS.md.claude-local.
On a claude-local Hub, an override of a bare tier (opus, sonnet, haiku) or a claude-* id stays on the Claude runtime, so model: opus in a task means claude-local/opus. A full id for another engine, such as openai/gpt-4o or codex-local, switches that run to it.
hubzoid init in an interactive terminal checks for a logged-in claude CLI and a logged-in Codex CLI. It writes the only one it finds into the new Hub's .env, or asks once when both are usable. hubzoid init my-hub --model codex-local sets the model without asking. Detection only reads the login status and makes no model call.
Providers
MODEL prefix | Provider | Required settings | Example |
|---|---|---|---|
openrouter/ | OpenRouter | OPENROUTER_API_KEY | openrouter/anthropic/claude-haiku-4.5 |
openai/ | OpenAI | OPENAI_API_KEY | openai/gpt-4o-mini |
anthropic/ | Anthropic | ANTHROPIC_API_KEY | anthropic/claude-haiku-4-5 |
azure/ | Azure OpenAI | AZURE_API_KEY, AZURE_API_BASE (https://<resource>.openai.azure.com), optional AZURE_API_VERSION | azure/<deployment-name> |
claude-local | Claude subscription through the claude CLI | A claude login, CLAUDE_CODE_OAUTH_TOKEN or ANTHROPIC_API_KEY | claude-local, claude-local/opus |
codex-local | Your Codex account through the Codex CLI 0.147.0 | A file-backed codex login | codex-local, codex-local/<model-id> |
For Azure, the part after azure/ is the deployment name you created in Azure, not the underlying model name. For the four key-based prefixes, a missing key stops the agent from building with an error naming the variable. Any other model id is passed to LiteLLM unchanged, and LiteLLM reads that provider's own environment variables.
Tiers for claude-local
MODEL | Runs on |
|---|---|
claude-local | Sonnet |
claude-local/sonnet | Sonnet |
claude-local/opus | Opus |
claude-local/haiku | Haiku, with lower latency |
claude-local/claude-<model-id> | That exact model id |
An unrecognized pin falls back to Sonnet with a warning in the log, so an unattended run never goes to the CLI with a typo. For a server without an interactive login, mint a subscription token with claude setup-token on a logged-in machine and set it as CLAUDE_CODE_OAUTH_TOKEN in the Hub's .env. The claude CLI must be installed and on the PATH of the user that runs the Hub. The Docker image has no claude CLI, so use a provider key there.
Codex models
codex-local uses the Codex CLI's default model. codex-local/<model-id> pins a model the logged-in account can use, and Codex is told not to fall back to another one. Install the pinned CLI and log in as the account that runs the Hub:
npm install -g @openai/codex@0.147.0
codex -c 'cli_auth_credentials_store="file"' loginOther CLI versions are refused until their tool isolation has been reviewed, so upgrade the CLI only with a Hubzoid release that supports it. hubzoid doctor reports the CLI and login as runtime.codex_login. Your Codex account's model access and usage limits still apply. Token counts are recorded, and the cost is an estimate only when the model's price is known. The Docker image has no Codex CLI.
Model settings
These .env keys apply to the whole Hub.
| Key | Values | Effect |
|---|---|---|
REASONING_EFFORT | low, medium, high | Reasoning models on OpenAI and Azure receive this effort. On Claude it sets an extended thinking budget. On Codex it is sent as the turn's effort. Unset leaves the model's default. |
SHOW_THINKING | off, indicator (default), full | Claude runtime only. indicator shows a thinking panel without the text, full streams the summarized reasoning. |
SHOW_TOOLS | off, compact (default), full | How tool calls appear in chat. compact is a collapsible entry per call in the web chat and is hidden in Slack. |
HUBZOID_VISION | true (default), false | Pass attached images to the model. HUBZOID_VISION_MAX_EDGE (default 1568 pixels) and HUBZOID_VISION_MAX_IMAGES (default 4) bound them. |
HUBZOID_DISABLE_PROMPT_CACHE | true to disable | Prompt caching that Hubzoid adds for Anthropic-family models on LiteLLM. HUBZOID_CACHE_TTL sets its lifetime, 1h by default. |
HUBZOID_OPENAI_TRACING | true to enable | Lets the OpenAI Agents SDK export runs to OpenAI's trace dashboard. Off by default. |
MODEL_LABEL | Any name | The model name the bridge reports on /v1/models. Defaults to the agent name. |
The configuration reference lists every key.
Models in workflows
Code workflows call the Hub's models in two ways. hub.call_agent(task) runs the full agent with its tools, skills and knowledge. hub.call_llm(prompt) is a single model call with no tools and no Hub instructions, returning text, JSON or a validated Pydantic object, on LiteLLM models, claude-local and codex-local. Both default to the Hub's model and record a usage row. The experimental hub.call_jev asks TypeSafe's Jev through OpenRouter for typed decisions with its own JEV_OPENROUTER_API_KEY, never the Hub's model key. See the workflow API.
Next steps
The Hub
The Hub is the shared foundation behind every Hubzoid agent. Learn what it holds, how context is assembled for each run, and how to scope one or many.
Memory and history
How a Hubzoid Hub keeps authored knowledge, conversation history per surface, workflow state per account and learned knowledge saved by the remember tool.
