Bring an existing agent
Move a Claude Code or similar agent project into a Hub file by file, or keep your assistant and connect it to a Hub through MCP.
You may already have an agent that works for you: a Claude Code project with a CLAUDE.md, a few skills, an MCP server and some scripts. There are two ways to take it to your team with Hubzoid, and they combine well.
| Route | What happens | Choose it when |
|---|---|---|
| Move it into a Hub | The instructions, skills, sub-agents, connectors and scripts become Hub files. The agent then runs in the web chat, Slack and other channels, on schedules and in workflows, for everyone you grant access. | Teammates who do not use your assistant should get the result, or the work should run unattended. |
| Keep your assistant, connect it | The Hub serves its tools, knowledge and skills over MCP. You and others keep using Claude Code, Cursor or another MCP client, with your own model. | People already work in an assistant and want shared context and tools inside it. |
The move is manual and quick for a typical project. Hubzoid has no converter, because most of the work is deciding what the shared agent should know and do.
How the pieces map
| In a Claude Code project | In a Hub | Notes |
|---|---|---|
CLAUDE.md or .claude/CLAUDE.md (or AGENTS.md) | AGENTS.md | The body is the system prompt. Keep the parts about the work, drop the parts about the coding environment. |
@path imports in CLAUDE.md | Inline text, or knowledge/*.md | Hubzoid does not expand imports. Reference material fits best in knowledge/. |
.claude/skills/<name>/SKILL.md | skills/<name>/SKILL.md | Same file. name and description are read, other keys are ignored. |
.claude/commands/<name>.md | skills/<name>.md or schedule/<name>.md | A reusable prompt becomes a skill. A prompt you run on a timer becomes a markdown task. |
.claude/agents/<name>.md | agents/<name>.md | Rewrite tools: as a YAML list of Hubzoid tool names, and model: as a Hubzoid model id. |
.mcp.json | connectors/.mcp.json | Same mcpServers map. HTTP servers need transport instead of type. |
| Scripts the agent runs | tools_local/*.py | A function decorated with @function_tool. A script that should run on a timer without the agent can be a run: task. |
| Data files the agent reads | knowledge/ or raw_data/ | Short curated documents go in knowledge/. Large source material to search goes in raw_data/. |
| Secrets in your shell | <hub>/.env | Secrets for restricted tools go in restricted/.env. |
Permission settings in .claude/settings.json | restricted/ tools and grants | Who may use a tool is decided in code and the Console, not by the model. |
A worked example
An operations lead has a Claude Code project that prepares a daily report for a home goods retailer with four stores: open supplier orders, stock alerts and anything that needs escalating.
ops-briefing/
├── CLAUDE.md
├── .mcp.json
├── .claude/
│ ├── skills/daily-reports/SKILL.md
│ ├── skills/daily-reports/template.md
│ ├── agents/supplier-research.md
│ └── commands/weekly-review.md
├── scripts/open_orders.py
├── data/orders.csv
└── docs/escalation-policy.mdAfter the move, the same project is a Hub:
Create the Hub
hubzoid init ops-briefingRun it in a new folder, outside your existing project. It writes a runnable Hub with one example of each file type and a .env with a random bridge key. Delete the examples you will not use, then copy your files in as below. See quickstart for installing Hubzoid and choosing a model.
Turn CLAUDE.md into AGENTS.md
Copy the parts of CLAUDE.md that describe the work: the goal, the rules, the tone, when to use what. Leave out build commands and coding conventions that only mattered to you in an editor. Add frontmatter for the name the team will see and a few starter prompts.
---
name: ops-briefing
description: Daily Reports and supplier follow-up for the operations lead.
suggestions:
- Prepare today's daily report
- Which supplier orders are late?
---
You prepare the operations lead's daily report for a home goods retailer
with four stores (north, south, east, west).
- Use the daily-reports skill for the daily briefing.
- Get open orders from the open_orders tool. Never estimate a quantity.
- Escalate according to the escalation-policy knowledge document.
- For questions about a supplier's record, use the supplier-research agent.Replace @docs/escalation-policy.md style imports with a sentence that names the knowledge document, and move the document to knowledge/escalation-policy.md. The agent sees a menu of knowledge documents and reads one with read_knowledge when it needs it.
Move skills and commands
Copy .claude/skills/daily-reports/ to skills/daily-reports/. The SKILL.md frontmatter works unchanged. Supporting files are not loaded with the skill, so point to them by their path from the Hub root:
---
name: daily-reports
description: Build the daily report for the operations lead.
---
1. Read the layout in skills/daily-reports/template.md with read_file.
2. Call open_orders and list orders due today or overdue, by store.
3. Apply the escalation policy and put anything that needs a decision first.A command such as .claude/commands/weekly-review.md becomes skills/weekly-review.md with name and description frontmatter. Hubzoid does not substitute $ARGUMENTS, so write the command as instructions that use whatever the person asked.
Move sub-agents
Copy .claude/agents/supplier-research.md to agents/supplier-research.md and adjust two keys:
---
name: supplier-research
description: When the user asks about a supplier's delivery record or recent news.
model: claude-local/opus
tools: [web_search, http_get, read_knowledge]
---
Research the supplier with web_search and http_get and reply with a short,
sourced summary of delivery issues and news from the last 90 days.tools:must be a YAML list of Hubzoid tool names. A comma-separated string such asRead, Grepstops the Hub from building, and Claude Code tool names do not exist in Hubzoid.model:must be a Hubzoid model id, or be removed. Claude Code aliases such assonnet,opusorinheritare not Hubzoid ids. A sub-agent whose model differs from the Hub's on the same engine runs on its own model as a delegate. Otherwise it is loaded into the main agent as a skill, and itstools:list is ignored.
Move MCP servers
Move .mcp.json to connectors/.mcp.json. Local (stdio) servers work as they are. For an HTTP server, replace "type": "http" with "transport": "streamable-http", because a server with a url and no transport is treated as SSE. Hubzoid expands ${NAME} but not ${NAME:-default}, so set every variable in the Hub's .env.
{
"mcpServers": {
"inventory": {
"type": "http",
"url": "${INVENTORY_MCP_URL:-https://mcp.example.com/mcp}",
"headers": { "Authorization": "Bearer ${INVENTORY_TOKEN}" }
}
}
}{
"mcpServers": {
"inventory": {
"transport": "streamable-http",
"url": "${INVENTORY_MCP_URL}",
"headers": { "Authorization": "Bearer ${INVENTORY_TOKEN}" }
}
}
}In a Hub, everyone who uses the agent shares the connector's credential. If each person should act with their own account, see per-user MCP servers.
Turn scripts into tools
In Claude Code the agent ran python scripts/open_orders.py in a shell. A Hub agent has no shell, so move the logic into a tool:
"""Open supplier orders, moved from scripts/open_orders.py."""
from __future__ import annotations
import csv
import json
from pathlib import Path
from agents import function_tool
ORDERS = Path(__file__).resolve().parent.parent / "raw_data" / "orders.csv"
@function_tool
def open_orders(supplier: str = "") -> str:
"""Open supplier orders with their store and due date.
Args:
supplier: Only this supplier. Leave empty for all suppliers.
Returns:
JSON list of open orders.
"""
with ORDERS.open(newline="", encoding="utf-8") as f:
rows = [r for r in csv.DictReader(f) if r["status"] == "open"]
if supplier:
rows = [r for r in rows if r["supplier"].lower() == supplier.lower()]
return json.dumps(rows)Tool files are loaded one by one rather than as a package, so a tool cannot import a sibling file from tools_local/. Keep each tool file self-contained, or install shared code as a package. See tools and connectors.
Schedule the briefing
What you started by hand each morning can now run on its own. Scheduled tasks are Markdown files:
---
schedule: "30 7 * * 1-6"
write: ["briefings/"]
---
Prepare today's daily report with the daily-reports skill and save it
to briefings/today.md.The task runs at 07:30 server time from Monday to Saturday with the same agent, skills and tools as chat. See markdown tasks.
Check it
Add an eval that proves the briefing uses real order data, then run the checks:
---
expect_tools: [open_orders]
---
## Prompt
Prepare today's daily report.
## Criteria
Lists overdue orders by store from the tool result. Does not invent quantities.hubzoid doctor ./ops-briefing
hubzoid test ./ops-briefing --prompt "Which supplier orders are late?"
hubzoid eval run ./ops-briefing
hubzoid run ./ops-briefingWhat changes when an agent moves
- No coding tools. On the
claude-localbackend, Claude Code's own tools (shell, file editing, its search and web fetch) are switched off. The agent has Hubzoid's built-in tools, such asread_file,list_files,grep_data,http_getandwrite_artifact, plus your own. Instructions that say "run this command" must name a tool instead. - Only Hub files count. Hubzoid reads
AGENTS.md, notCLAUDE.mdor anything under.claude/. Imports, hooks, permission settings and auto memory do not carry over. - Many people, one agent. In chat, each person has their own conversations and their own identity. Tools and connectors share the Hub's credentials unless you use restricted tools or per-user connections. Decide who may use what in the Console. See identity and access.
- Checks that must always run belong in code. A rule the model is only asked to follow can be missed. Put anything that must hold every time in a tool, a restricted tool or a code workflow step.
- Memory is explicit. Conversation history stays with each chat. Shared knowledge changes when you edit
knowledge/, or when a person with thecuratorpermission asks the agent to remember something. See memory and history.
Keep your assistant and connect it
If you and your teammates prefer to stay in Claude Code or Cursor, turn the Hub into an MCP server instead of, or as well as, moving the agent.
MCP_SERVER=trueEach person creates a personal API key in the web chat and adds the Hub to their assistant:
claude mcp add --transport http ops-briefing https://hub.example.com/mcp \
--header "Authorization: Bearer <your-api-key>"The assistant then receives the Hub's tools (including list_skills, load_skill, list_knowledge and read_knowledge) and, when it connects, the Hub's instructions from AGENTS.md or its mcp_instructions frontmatter. Restricted tools follow the same permissions as chat, and every restricted call is audited. The MCP server leaves out the chat-only tools, delegates and the Hub's own connectors, because the assistant brings its own model and environment. The full setup is in connect an assistant.
A common pattern uses both: builders keep working in their assistant against the Hub, and everyone else uses the same Hub in chat and on schedules.
Next steps
Tools and connectors
Give a Hub's agent new abilities with Python tools in tools_local/, external MCP servers, each person's own MCP connections and one shared browser.
Evals
Check that a Hub keeps doing its job with Markdown eval cases, free checks, a model judge, scheduled runs, CI gates and optional Langfuse history.
