---
title: The Hub
description: 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.
canonical_url: https://hubzoid.com/docs/concepts/hub
last_updated: 2026-09-27
---

# 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.

| 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](https://hubzoid.com/docs/getting-started/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

What the model receives, in order.

1. **Instructions.** The `AGENTS.md` body is the start of the system prompt.
2. **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 when `restricted/` exists, and rules for reading uploaded files. Set `auto_addendum: false` in the `AGENTS.md` frontmatter to send the body alone.
3. **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 from `connectors/.mcp.json` are added beside them.
4. **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.
5. **The turn itself.** The conversation arrives as one prompt. With `claude-local` and `codex-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.

```markdown title="AGENTS.md"
---
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:

1. `skills/` in the Hub.
2. Sub-agents in `agents/` that run as skills.
3. Skills shipped with Hubzoid. The `dashboard` skill, which builds a single-file HTML dashboard and saves it with `write_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](https://hubzoid.com/docs/concepts/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](https://hubzoid.com/docs/reference/built-in-tools) lists every argument. [Tools and connectors](https://hubzoid.com/docs/guides/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.

The model only ever asks for a tool. [Architecture](https://hubzoid.com/docs/concepts/architecture#a-turn-that-calls-a-tool) 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](https://hubzoid.com/docs/guides/restrict-tools) and [identity and access](https://hubzoid.com/docs/concepts/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:

```bash
hubzoid gateway ./finance ./operations ./company --data-dir ./gateway-data
```

Each 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](https://hubzoid.com/docs/deploy/gateway).

## Next steps

- [Agents and models](https://hubzoid.com/docs/concepts/agents-and-models): Sub-agents, delegation, runtimes and model configuration.
- [Memory and history](https://hubzoid.com/docs/concepts/memory-and-history): Knowledge, conversation history, workflow state and learned knowledge.
- [Tools and connectors](https://hubzoid.com/docs/guides/tools-and-connectors): Add Python tools and MCP servers to a Hub.
