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.
Context takes effort to build. The Hub is where that effort lives: the instructions, knowledge, skills, agent definitions and authorized tools needed to do one product's, team's or company's work. You write it once as a folder in Git, and every surface that uses the Hub (chat, scheduled work, and assistants connected over MCP) builds on the same files.
"Provide context once" does not mean everyone sees everything. Each surface has its own history and its own access rules, and restricted tools run only for the people and workflows granted them.
What a Hub holds
Read as one agent, a Hub is a definition with two sides: what the agent knows and what it can reach. Hubzoid supplies the surfaces and services around it.
What it knows
Knowledge
knowledge/raw_data/Reference documents read on demand, and raw material searched as text.
Skills
skills/Procedures loaded when a request matches their description.
Definition
AGENTS.mdagents/
Who the agent serves, its job and its rules, plus any sub-agents.
What it can reach
Tools
tools_local/Your Python functions, beside the built-in tools.
Connections
connectors/restricted/Live systems through MCP servers, and restricted tools that run only with a permission.
What Hubzoid provides
- Surfaces
- Web chat
- Slack
- Telegram
- OpenAI-compatible API
- MCP
- Webhooks
- Services
- Built-in tools
- Workflow engine
- Sign-in and grants
- Activity log
- The Console
- Evals
| Part | Files | How it reaches the agent |
|---|---|---|
| Instructions | AGENTS.md | The body is the system prompt for every run. |
| Knowledge | knowledge/**/*.md | Listed by name and description in the system prompt. Read in full with read_knowledge when relevant. |
| Skills | skills/*.md, skills/<name>/SKILL.md | Listed in the system prompt. Loaded with load_skill when a request matches. |
| Agent definitions | agents/*.md, agents/<name>/AGENTS.md | Loaded as skills, or called as delegate agents on their own model. |
| Tools | Built-in tools, tools_local/*.py, connectors/.mcp.json | Offered to the model as callable tools. |
| Restricted tools | restricted/*.py | Offered only to callers with the matching permission. Checked again at call time. |
| Unstructured data | raw_data/ | Searched with grep_data and read with read_file. |
| Recurring work | schedule/*.md, workflows/<name>/*.py | Run on the workflow engine with the same context. |
| People and permissions | identity/ | Rosters for messaging surfaces and labels for permissions in the Console. |
| Quality checks | evals/*.md | Run against the same agent with hubzoid eval run. |
Project structure lists the exact file names and formats.
How context is assembled for a run
Chat uses the agent the bridge builds from the Hub folder when it starts. Scheduled tasks and hub.call_agent build it again for each run, so they pick up Hub edits without a restart.
- AGENTS.md body
- Runtime addendum
- Tool registry
- Access guard
- Model call
- Instructions. The
AGENTS.mdbody is the start of the system prompt. - Runtime addendum. Hubzoid appends a section with the Hub name, backend, model and date, the menu of knowledge documents and skills (name and description only), any delegate agents, guidance for searching
raw_data/when that folder exists, a reminder about restricted tools whenrestricted/exists, and rules for reading uploaded files. Setauto_addendum: falsein theAGENTS.mdfrontmatter to send the body alone. - Tool registry. Built-in tools, then your
tools_local/tools (a local tool with a built-in's name replaces it), then restricted tools, which win any name conflict. MCP servers fromconnectors/.mcp.jsonare added beside them. - Access guard. Each restricted tool is wrapped so that a caller without the permission is refused at call time, with the decision recorded. On every runtime the tool is also hidden from that caller.
- The turn itself. The conversation arrives as one prompt. With
claude-localandcodex-local, Hubzoid also adds a short note naming the signed-in person, so the model does not mistake the local CLI's login for the user.
Knowledge and skill bodies are not in the system prompt. The model sees the menus and loads what it needs, which keeps prompts small as a Hub grows. read_knowledge and list_knowledge read the folder from disk on every call, so an edited or newly learned document is available immediately. In chat, the menus in the system prompt refresh when the Hub restarts.
Instructions
AGENTS.md is written for the model: who it serves, what it is responsible for, how to use the Hub's knowledge and tools, and what to refuse. Keep facts that change in knowledge/ and procedures in skills/, and point to them by name from the instructions.
---
name: stock-desk
description: Answers stock questions for the operations team and flags drift between locations.
---
You help the operations team with stock across our four locations.
- For thresholds and definitions, read the drift-thresholds knowledge document.
- For the weekly review, load the weekly-drift-review skill and follow it.
- Answer with numbers and name the location. Say when data is older than a day.Knowledge
A knowledge document is Markdown with optional name and description frontmatter. The description is what the model sees in the menu, so write it as a statement of when the document is useful. Subfolders are fine: every *.md under knowledge/ is loaded, and the name defaults to the file name.
Use knowledge/ for reference material the agent should read and quote. Use raw_data/ for large or unedited material, such as exports and code checkouts, that the agent should search with grep_data rather than read whole.
Skills
A skill is a named procedure with a name and a description. The model loads it with load_skill(name) when a request matches the description, then follows it. Skills come from three places, and a name defined in an earlier place wins:
skills/in the Hub.- Sub-agents in
agents/that run as skills. - Skills shipped with Hubzoid. The
dashboardskill, which builds a single-file HTML dashboard and saves it withwrite_artifact, is available to every Hub's chat agent.
Tools
Every Hub has these built-in tools. tools_local/ adds your own Python tools, and connectors/.mcp.json adds MCP servers.
| Tools | Purpose |
|---|---|
read_file, list_files | Read and list files inside the Hub folder. Paths outside the Hub and under restricted/ are refused. |
grep_data | Search file contents, raw_data/ by default. |
list_knowledge, read_knowledge | The knowledge menu and documents. |
list_skills, load_skill | The skill menu and skill bodies. |
write_artifact, list_artifacts | Save a file for the person in this chat and return a signed download link. |
read_upload, read_upload_full | Read files attached in this chat. |
render_jinja | Render a Jinja2 template. |
http_get, web_search | Fetch a URL (limited to HTTP_ALLOWLIST hosts when set) and search the web. HUBZOID_DISABLE_HTTP_GET and HUBZOID_DISABLE_WEB_SEARCH remove them. |
current_time | The current time in an IANA time zone. |
remember | Save learned knowledge. Available only to callers with the Save shared knowledge (curator) capability. See memory and history. |
call_jev | Experimental typed decisions from TypeSafe's Jev. Available only to callers with the Call Jev (jev) capability, granted to nobody by default. |
The built-in tools reference lists every argument. Tools and connectors shows how to write a local tool and add an MCP server.
Whatever their source, tools are written once and join one registry. Each runtime and the Hub's own MCP server offer that same registry in their own form.
Where tools come from
Built-in tools
Files, knowledge, skills, search and the web.
Your tools
tools_local/*.pyA tool with the name of a built-in replaces it.
Restricted tools
restricted/*.pyWrapped in the access guard. They win any name conflict.
One tool registry
Name, description, arguments and code, written once.
How each caller sees it
OpenAI Agents SDK
Function tools on the agent.
Claude Agent SDK
mcp__hubzoid__<name>One in-process MCP server.
Local Codex
Dynamic tools that Hubzoid runs for Codex.
Connected assistants
/mcpThe same tools without the chat-only ones.
Beside the registry
connectors/.mcp.jsonHUBZOID_BROWSER
MCP servers and the shared browser, used by the Hub agent in chat, tasks, workflows and evals. They are not passed on to connected assistants.
The model only ever asks for a tool. Architecture follows one call through the bridge.
Restricted tools
Put a tool in restricted/ when only some people or workflows should run it. The file name is the permission: every tool in restricted/ledger.py needs the ledger permission. Hubzoid enforces this in code, outside the model:
- Every call is checked when it runs, on all three runtimes, and refused unless the caller holds the permission on a surface allowed to reach restricted tools.
- On every runtime and over MCP, the tool is also hidden from callers who lack the permission.
- Every allow and deny decision is recorded before the call runs. A call whose decision cannot be recorded does not run.
- Secrets for these tools go in
restricted/.env. They are loaded into the process environment, and the agent's file tools cannot read the folder.
Grants are made in the Console or with hubzoid grant. See restrict tools and identity and access.
The same Hub on every surface
| Surface | What it uses from the Hub |
|---|---|
| Chat (web, Slack, WhatsApp, Telegram, API) | The full agent: instructions, menus, all tools, delegates and the dashboard skill. |
| Markdown tasks | The same agent and model, plus tools that exist only for scheduled runs: run_git for Git checkouts inside the Hub, write_hub_file, which writes only under the paths the task declares, and publish_artifact and send_email when the task opts in. |
| Code workflows | hub.call_agent runs the full agent. hub.call_llm is one model call with no tools and no Hub instructions. |
| MCP clients | The built-in, local and restricted tools except those tied to a chat, including the knowledge and skill tools, plus the AGENTS.md body as server instructions. The client's own model does the reasoning. |
Scoping a Hub
A Hub can serve one product, one team or a whole company. Scope it by the context and access that belong together:
- One Hub per team or function when each team has its own knowledge, tools and people, for example finance and operations.
- One Hub per product when several teams need the same product knowledge and tools.
- One company Hub for shared questions such as policies and company figures, alongside team Hubs for sensitive work.
Each Hub is independent: its own .env and model, knowledge, tools, schedules and chat history. Its folder name is its access domain, so permissions granted in one Hub do not apply in another.
Many Hubs under a gateway
hubzoid gateway puts several Hubs behind one sign-in, one chat app and one Console:
hubzoid gateway ./finance ./operations ./company --data-dir ./gateway-dataEach Hub keeps its own instructions, tools, knowledge, schedules and model, and runs in its own bridge. People sign in once and see only the agents they are granted. Organization administrators manage every Hub from one Console, and an agent administrator (manage_access in one Hub) manages only that Hub. See gateway.
Next steps
Architecture
How a request moves through Hubzoid, from chat surfaces and the edge to the bridge, agent runtimes, models, the workflow engine, databases and the Console.
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.
