Hub files

Every file and folder a Hub can contain, the keys each one takes, and the runtime folders Hubzoid creates and keeps out of Git.

A Hub is one folder. Hubzoid reads the files below every time the Hub starts, and some on every call. Everything except the .env files and the runtime folders belongs in Git.

What hubzoid init writes

hubzoid init my-hub writes every folder Hubzoid reads and a small starter for Kestrel & Oak, a fictional home-goods shop. An empty folder holds a .gitkeep so it stays in Git.

AGENTS.md
.env
.gitignore
README.md
Starter fileWhat it holds
AGENTS.mdThe team assistant for Kestrel & Oak, with three suggestions. It answers from knowledge/ and names the file it used.
knowledge/house-rules.mdThree house rules: refunds within 30 days of delivery, orders over $500 need a manager's approval, support hours 09:00 to 18:00 UTC Monday to Friday.
evals/refund-window.mdOne check that the refund question follows the rule and names house-rules.md.
connectors/.mcp.jsonAn empty mcpServers list.
.envMODEL, a random BRIDGE_API_KEYS and commented examples, readable only by you.
.gitignore.env, output/, .hubzoid/ and Python caches.
README.mdWhat each folder is for.

In an empty parent folder it also writes requirements.txt, .gitignore and README.md there, so the parent becomes a repository of Hubs. See the CLI reference.

File index

PathRead byPurpose
AGENTS.mdevery surfaceRequired. The main agent's instructions and settings.
.envevery command that builds or serves the HubModel, keys and settings. See configuration.
agents/agent builder, work itemsSub-agents: skills, delegates or isolated stations.
skills/list_skills, load_skillPlaybooks the agent loads on demand.
knowledge/list_knowledge, read_knowledgeReference documents, read live from disk.
tools_local/tool registryPython tools.
restricted/tool registry, access guard, SettingsPython tools that need a capability, and their secrets in restricted/.env.
connectors/MCP loader, SettingsMCP servers: .mcp.json for shared servers, <id>.yaml for remote servers people sign in to.
channels/hubzoid runOne YAML file per channel.
schedule/schedulerMarkdown tasks run on a cron or by a webhook.
workflows/workflow enginePython code workflows, their settings and their access rules.
evals/hubzoid eval, scheduler, SettingsBehaviour checks.
identity/inbound surfaces, SettingsLive sender lookup and labels for restricted capabilities.
raw_data/grep_data, read_file, list_filesLarge source material to search rather than load.
branding/the web appThe agent's avatar, and the deployment's brand files.
prompts/the web appShared prompts, one Markdown file each.
hitl.yaml, budgets.yaml and otherstheir own loadersOptional rules: approvals, usage limits, work items, settings, cards and sandboxes.

Other files, such as a README.md or a .gitignore, are not loaded by Hubzoid, so they can live in the Hub too.

Folder name variants

Folder names match without regard to case, and these variants are accepted. When two variants exist in one Hub, the first alphabetically is used and a warning is logged.

CanonicalAlso accepted
agentsagent
skillsskill
tools_localtool_local, tools, local_tools
connectorsconnector
channelschannel
scheduleschedules, scheduled
workflowsworkflow
evalseval, evaluations
raw_dataraw-data, rawdata
outputoutputs

knowledge, restricted and identity have no variants.

AGENTS.md

The main agent. The body is the system prompt, used verbatim. Frontmatter is optional, so a plain Markdown file works. This is the starter's:

my-hub/AGENTS.md
---
description: A starter assistant for Kestrel & Oak, a fictional home-goods shop. Make it yours.
suggestions:
  - A customer wants a refund 40 days after delivery. What can we offer?
  - Who has to approve a $650 order?
  - When is support open?
---

You are the team assistant for Kestrel & Oak, a fictional home-goods shop
used as Hubzoid's starter. Answer from the files in `knowledge/` and name the
file you used. If they do not answer the question, say so instead of
guessing. Keep answers short.
KeyTypeDefaultEffect
namestringthe Hub folder nameThe agent's display name in the web app and Settings. Its slug is the model id in /v1/models unless MODEL_LABEL is set.
descriptionstringthe first non-heading line of the body, up to 200 charactersShort summary, shown in the agent switcher and on the empty new-chat screen.
modelmodel idnoneThe Hub's model when .env does not set MODEL. MODEL in .env wins.
suggestionslist of stringsnoneClick-to-send prompts on the empty new-chat screen. The Slack manifest also uses them.
mcp_instructionsstringthe bodyInstructions sent to MCP clients when they connect, in place of the body. Use it when the body holds internal guidance or is long.
auto_addendumbooleantruefalse stops Hubzoid from appending its runtime section (knowledge index, skills index, tool guidance) to the instructions.

A file with frontmatter but no body fails to load. tools: on the main agent has no effect: the main agent always has the full tool registry. AGENTS.md, sub-agents and skills may use {{settings.KEY}} for a declared setting.

Agent definitions: agents/

Each sub-agent is either a folder, agents/<name>/AGENTS.md (or the first *.md in the folder), or a single file, agents/<name>.md. Hidden entries are skipped.

my-hub/agents/researcher.md
---
name: researcher
description: When the user wants a researched brief on a supplier or product.
model: claude-local/opus
tools: [web_search, http_get, read_knowledge]
---

Research the question with web_search and http_get, then write a short brief with sources.
KeyTypeDefaultEffect
namestringthe folder or file nameIdentifier, and the skill name when loaded as a skill.
descriptionstringthe first non-heading line of the bodyWhen the main agent should use this sub-agent. Write it as a "when" sentence.
modelmodel idnoneDecides skill or delegate. See below.
toolslist of tool namesall toolsDelegates and stations only. The tools it may call. Unknown names are dropped with a warning.

Skill or delegate. A sub-agent becomes a delegate only when its model: differs from the Hub's model on the same engine, for example claude-local/opus in a claude-local Hub, a different Codex model in a codex-local Hub, or a different LiteLLM id in a LiteLLM Hub. A delegate runs on its own model in its own context and returns its answer to the main agent, which stays in control. On the OpenAI Agents SDK and Codex runtimes the main agent calls it as a tool named handover_<name>. On claude-local it runs as a Claude subagent. Every other sub-agent (no model:, the same model, or a different engine) is loaded inline as a skill, and its tools: list is ignored with a warning. A delegate whose model is missing its provider key falls back to a skill so the Hub still starts.

Isolated agents (stations). isolated: true makes the sub-agent a station: an agent with one job that a work-item workflow calls for one stage. It gets only its own instructions and exactly the tools it lists, never the main agent's conversation, skills or knowledge.

Station keyEffect
isolatedtrue makes the agent a station.
engineclaude-local or codex-local. Default: the Hub's runtime.
modelOptional. The engine's signed-in default when left out.
toolsThe exact tools, including save_handoff and read_handoff. Empty or missing means none.
response_schemaA JSON Schema file in the agent's folder that the result is checked against.
inputforward (default) or never.
sandboxA sandbox profile (sandboxes/<id>.yaml) for the agent's own workspace. Without it the agent has no shell or files.
timeout_secondsOptional limit on active time across all attempts of a call.

Check stations with hubzoid stations validate. See the SDK guide stations (opens in a new tab).

Skills: skills/

Each skill is skills/<name>/SKILL.md (also skill.md, Skill.md or the first *.md in the folder) or a single file, skills/<name>.md.

my-hub/skills/weekly-summary/SKILL.md
---
name: weekly-summary
description: Three-bullet summary of the week's orders for the operations lead.
---

1. Call list_knowledge and read the house rules.
2. Pull the week's numbers with the order tools.
3. Reply with three bullets and one risk to watch.
KeyTypeDefaultEffect
namestringthe folder name (or file stem)Name passed to load_skill.
descriptionstringSkill loaded from <file>.Shown in the skills menu the agent sees.

The agent sees each skill's name and description and loads the body with load_skill only when it needs it. Other frontmatter keys are ignored. Supporting files in a skill folder are not loaded automatically. Name them by their path from the Hub root in the skill body, and the agent reads them with read_file.

Name collisions resolve in this order: skills/ first, then sub-agents loaded as skills, then Hubzoid's built-in dashboard skill (chat surfaces only). A skill file with no body or with frontmatter that cannot be parsed stops the Hub from building.

Knowledge: knowledge/

Every *.md under knowledge/, including subfolders, is one document. Hidden files and _index.md are skipped.

my-hub/knowledge/house-rules.md
# House rules

- **Refunds.** A customer can return an unused item within 30 days of
  delivery for a full refund. After 30 days we offer store credit or a
  repair, not a refund.
- **Large orders.** An order over $500 needs a manager's approval before it
  ships.
- **Support hours.** Support answers from 09:00 to 18:00 UTC, Monday to Friday.
KeyTypeDefaultEffect
namestringthe file stemName passed to read_knowledge.
descriptionstringKnowledge document: <stem>.Shown in the knowledge menu.
keywordslist of stringsnoneSearch hints. A single string is accepted.

Frontmatter is optional. The knowledge tools read the folder live, so an edited or added document is visible on the next call without a restart. A file with broken frontmatter is skipped with a warning and the rest still load.

knowledge/_learned/<topic>.md holds what the remember tool saved for everyone. remember is a proposal that a Hub manager applies, and it is offered only when browser editing is on. See memory and history.

Tools: tools_local/ and restricted/

Every *.py file in these folders is imported when the Hub builds, and every module-level FunctionTool (a function decorated with @function_tool from the agents package) becomes a tool. Files whose names start with _ are skipped.

  • A tools_local/ tool with the same name as a built-in tool replaces the built-in.
  • A restricted/<capability>.py tool requires the capability named by the file stem. Every tool in the file shares it, and Settings lists it under restricted tools so you can grant it. It wins over any tool of the same name and is guarded before every call. identity/permissions.yaml can label it.
  • restricted/.env holds the secrets those tools read. File tools refuse every path under restricted/.

See tools and connectors and restrict tools.

Connectors: connectors/

connectors/.mcp.json

MCP servers that serve everyone who uses the agent, in the mcpServers shape. connectors/mcp.json (no leading dot) is read when .mcp.json is absent. Settings lists these servers read-only under the agent's Connectors, with their names and any missing settings, never values.

my-hub/connectors/.mcp.json
{
  "mcpServers": {
    "tickets": {
      "transport": "streamable-http",
      "url": "https://mcp.example.com/mcp",
      "headers": { "Authorization": "Bearer ${TICKETS_TOKEN}" }
    }
  }
}
KeyApplies toEffect
command, args, envstdio serversProcess to start and its arguments and environment.
urlHTTP serversServer endpoint.
transportHTTP serverssse or streamable-http (also written http). A server with a url and no transport uses SSE. A server with no url uses stdio.
headersHTTP serversRequest headers, such as an authorization token.
client_session_timeout_secondsany serverSeconds one tool call may take on the OpenAI Agents SDK and Codex runtimes. Without it, HUBZOID_MCP_TIMEOUT applies, else 30 seconds.

${NAME} in any string is replaced with that environment variable after .env is loaded. Names use uppercase letters, digits and underscores. With HUBZOID_BROWSER=true, a playwright server is added automatically, and an entry of your own with that name replaces it. Invalid JSON stops the Hub from building.

Remote connectors

Remote MCP servers that each person signs in to, or that use one company key. They live in the deployment folder (the Hub folder for a deployment of one). Settings reads them, and writes them only when browser editing is on. Each person connects their own account in Settings.

connectors/tickets.yaml
version: 1
name: Tickets
url: https://mcp.example.com/mcp
sign_in: oauth
scopes: [tickets.read]
tools: [list_tickets, get_ticket]
hubs: [my-hub]
enabled: true
KeyEffect
name, urlDisplay name and server endpoint.
sign_inoauth (each person with their own account), shared (one company key sent as a header) or none.
client_id, client_secretOptional client registered in advance. The secret is a reference such as env:TICKETS_CLIENT_SECRET, never the value.
scopesScopes to request.
toolsOptional allow-list of tools.
hubsThe agents that offer it.
enabledfalse turns it off.

Channels: channels/

One YAML file per channel connection, channels/<id>.yaml. Slack (provider: slack_assistant), WhatsApp (whatsapp_inbound), Telegram (telegram) and generic webhooks (webhook) each turn on with a file of four keys: version: 1, id, provider and enabled: true. Their secrets stay in .env. Check a file with hubzoid channels validate and see its status with hubzoid channels list. See Slack and WhatsApp and Telegram.

Scheduled tasks: schedule/

One Markdown file per task. The file name (letters, digits, ., _ and -, starting with a letter or digit) is the task name. The body is the agent's instructions, or optional notes for a run: script task.

schedule/daily-reports.md
---
schedule: "7 6 * * 1-5"
write: ["output/reports"]
publish_artifacts: true
---

Write yesterday's order summary to output/reports/<date>.md and publish it as a report.
KeyTypeDefaultEffect
schedule5-field cronnoneWhen the task runs, in the server's local time.
on_webhookstring or truenoneRun when events arrive at this generic webhook inbox instead of on a cron. The value matches the receiver's WEBHOOK_INBOUND_NAME, and true means webhook. Use schedule or on_webhook, not both.
runstring or listnoneRun a command instead of the agent. A string runs in a shell, a list runs as arguments without one.
modelmodel idthe Hub's modelModel for this task.
timeoutseconds1800Time limit per round.
max_roundsinteger10Fresh-context rounds per run.
max_turnsinteger40Agent turns within one round.
writepath or listnoneExtra Hub paths the task may write, not committed.
commitpath or listnoneHub paths the task may write and Hubzoid commits after the run.
pushbooleanfalsePush the commit. Needs commit.
run_asaccount emailHUBZOID_WORKFLOW_USER, else the owner recorded at setupThe account the run acts as, with that account's access.
publish_artifactsbooleanfalseGive the agent the publish_artifact tool, to publish a private report for the run's account. Not for run: tasks.
send_emailbooleanfalseGive the agent the send_email tool, to email the run's account only. Not for run: tasks.
alert_tolist of destinationsthe Hub's alerts.toWhere this task's alerts go, in the same form as alerts.to in workflows/settings.yaml.
enabledbooleantruefalse keeps the file but stops it firing.

The full behaviour, including rounds, catch-up and webhook inboxes, is in markdown tasks.

Workflows: workflows/

Each code workflow lives in workflows/<name>/. Every *.py file directly in that folder whose name does not start with _ is imported, and each function decorated with @workflow is registered under its function name. Subfolders, such as a package of helper modules, are not imported as workflows. hubzoid new workflow scaffolds one. The API is in the workflow API reference.

workflows/settings.yaml

Optional. Workflows read any top-level key with hub.setting("<key>"), and the keys below configure the engine, webhooks, alerts, reports and email.

workflows/settings.yaml
agent_max_attempts: 1          # tries for a failed hub.call_agent step. 1 means no retry.
max_concurrent_workflows: 2    # cap on code workflows on the shared queue
workflow_timeout: 30m          # default run deadline

webhooks:
  ticket-updated:
    verify: header
    header: X-Webhook-Secret
    event_key: "{ticket.id}:{ticket.modifiedTime}"

alerts:
  to:
    - webhook: ALERT_WEBHOOK_URL   # an environment variable that holds the URL
    - email: ops@example.com
  cooldown: 1h

series_keep: 50
email_lists:
  leads: [asha@example.com, ravi@example.com]

personal_schedules:
  min_interval: 1h
  per_person: 10

stock_drift:                   # your own key, read with hub.setting("stock_drift")
  threshold_pct: 5
KeyDefaultEffect
agent_max_attempts1Tries for a failed hub.call_agent call. A retry can repeat a message or a write.
max_concurrent_workflowsno capCap on code workflows running at once on the Hub's shared queue. A workflow with its own concurrency or concurrency_key has a separate queue and is not counted.
max_executor_threads32Worker threads for the Hub's workflow runs.
workflow_timeoutnone, 15m for webhook runsDefault deadline for a run, in seconds or a string such as 30m. @workflow(timeout=...) overrides it.
webhooksnoneNamed webhooks that start code workflows. See below.
webhook_retry_delays[60, 300]Seconds before each retry of a failed webhook event, at most nine. The default gives three attempts.
alerts.tononeAlert destinations: webhook: ENV_VAR or slack: ENV_VAR (an environment variable that holds the URL), or email: address. HUBZOID_ALERT_URL is the deployment fallback.
alerts.cooldown1hQuiet period for repeated alerts. Suppressed occurrences are counted in the next alert.
alerts.failures_in_a_row3Failed runs in a row that raise a failure streak alert.
alerts.pause_after_failures20Failed scheduled runs in a row that pause the schedule. 0 turns it off.
series_keepkeep allCopies kept of each live report (publish_artifact(key=...)).
email_listsnoneNamed lists of addresses for hub.send_email(..., email_list=...), from team runs only. At most 50 addresses each, and every address must have an account or be at a share domain.
notify_by_emailfalseEmail people about their own schedules and long Run for me runs, when email delivery is set up.
personal_schedulesmin_interval: 1h, per_person: 10, pause_after_failures: 3Limits for the schedules people save for themselves: the shortest cadence, schedules per person per agent, and failures in a row before one pauses.

Each entry under webhooks: is served by the Hub's bridge at /webhooks/<hub>/<name>, and its secret is the environment variable WEBHOOK_SECRET_<NAME>, with the name upper-cased and hyphens turned into underscores. Names use lowercase letters, digits, - and _, up to 64 characters. whatsapp, telegram and the Hub's WEBHOOK_INBOUND_NAME (default webhook) are taken by the inbound receiver and refused.

Webhook keyEffect
verifyheader (the default) compares a shared secret sent in a header. hmac checks a timestamped HMAC-SHA256 signature. github checks GitHub's X-Hub-Signature-256.
headerThe header that carries the secret for verify: header. Default X-Hook-Secret.
signature_headerThe header that carries the signature for verify: hmac. Default the header value.
timestamp_headerThe header with the Unix timestamp the signature covers. Required with verify: hmac, and it must be within five minutes.
event_keyA template of body fields, such as {ticket.id}:{ticket.modifiedTime}, that identifies one event so repeats are recognized. Without it, delivery-id headers are used, then a hash of the body.

The file is validated when the bridge starts. A mistake, such as invalid YAML, an unknown verification or an empty alert destination, turns the workflow engine off for that Hub and records the error in workflow health, which hubzoid doctor reports as scheduler.health. Chat keeps running, and the Hub's webhook URLs answer 503 until the file is fixed and the bridge restarts. See code workflows and webhooks.

workflows/access.yaml

Optional. Who may run, schedule, edit, approve and see each workflow. Check it with hubzoid workflow-access validate, preview the change with hubzoid workflow-access diff and apply it with hubzoid workflow-access apply. See the CLI reference.

Evals: evals/

One Markdown file per case. The case id is its path under evals/ without .md. Files and folders starting with _ or ., and evals/fixtures/, are skipped.

my-hub/evals/refund-window.md
---
contains: ["house-rules"]
---
## Prompt
A customer wants a refund 40 days after delivery. What can we offer?

## Criteria
Follows the refund rule in knowledge/house-rules.md for that many days,
and names house-rules.md as its source.

Every frontmatter key is optional: schedule, tags, expect_tools, forbid_tools, expect_tool_args, contains, not_contains, timeout (1 to 3600 seconds, default 120), threshold (the judge's pass mark out of 10, default 7), enabled, run_as, and fake_tools, real_tools and allow_real_mcp for fake tool results. Any other key is an error.

The body holds a ## Prompt section and an optional ## Criteria section, which turns the judge on. A conversation uses ## Turn 1, ## Turn 2 and so on instead of ## Prompt. A body with no headings is the prompt. See evals.

Identity: identity/

Who a WhatsApp or Telegram sender is comes first from the phone number recorded on a person in Settings. A Hub can add its own live lookup, for example in a CRM. A lookup only says who someone is. What they may do is decided by their grants in Settings.

identity/access.csv is no longer read. Put phone numbers on people in Settings, and grant who may use a channel there. A Hub that still has the file gets a warning.

identity/access.py

A function-backed lookup, such as a CRM.

my-hub/identity/access.py
def resolve(surface: str, handle: str) -> dict | None:
    """Return {"email": ..., "groups": [...]} for a phone or chat handle, or None."""
    ...

def groups_for_email(email: str) -> list[str]:
    """Optional. Group labels for a web or MCP caller, looked up by email."""
    ...

groups_for_email is optional, and without it the file never receives email lookups. Groups are labels the agent can see as context, and they grant nothing. Results are cached for 60 seconds. An exception in either function resolves to no one and no groups rather than failing the request. On WhatsApp and Telegram, a sender whose number neither Settings nor the lookup knows is refused.

identity/permissions.yaml

Labels for the capabilities of restricted/*.py files in Settings, read without running any tool code. An entry that names a built-in capability, such as use_hub, manage_access or curator, is ignored with a warning.

my-hub/identity/permissions.yaml
finance:
  label: Finance reports
  description: Read margins and receivables from the accounting system.
  sensitive: true
KeyTypeDefaultEffect
labelstringthe name in title caseName shown in Settings.
descriptionstringUse the restricted tools assigned to this capability.Explanation shown with the capability.
sensitivebooleanfalseTags the capability as Sensitive in Settings, and the review step warns before it is granted.

Access concepts are covered in identity and access.

Branding: branding/

The agent's avatar. A Hub's branding/logo.svg, logo.png or logo.webp, then favicon.svg or favicon.png, is its agent's avatar in the web app. The first file present wins. Names match without regard to case.

The deployment's brand (name, logos, favicon, sign-in text, links, terms) is the brand: section of hubzoid.yaml, with its files under branding/ next to it. Colours, fonts and corner radius go in branding/theme.json. Until a deployment has a brand: section, a branding.yaml there is read instead. Check the brand with hubzoid branding validate, and turn an older branding/ folder into branding.yaml with hubzoid branding import-legacy.

custom.css is no longer served. The brand's presentation.decorative_css can style three brand slots only. See the SDK guide branding (opens in a new tab).

Other files at the Hub root

All optional. A Hub without them behaves as before.

FileWhat it setsCheck or change it with
hitl.yamlWhen the agent asks a person first: per tool, connector or agent, ask: never, once, always or auto, and whether it may ask questions.hubzoid hitl
budgets.yamlUsage limits in tokens, turns or dollars, per run, per work item and per month.hubzoid budgets
work-items.yamlLimits for durable work and the write mode of each external action (off, draft or approve).hubzoid work-items validate
settings.yamlThe settings the Hub declares: name, type, default, whether required or secret.hubzoid hub settings
hub.settings.yamlValues for those settings, and secret references such as env:NAME.hubzoid hub configure
hub.manifest.yamlThe Hub's own setup checks, run by hubzoid doctor.hubzoid hub doctor
mcp-apps.yaml, cards/*.yamlWhich tool results show as cards in chat.hubzoid apps validate
sandbox.yaml, sandboxes/<id>.yamlSandbox providers and limits, and one profile per kind of workspace. In the deployment folder.hubzoid sandbox doctor
prompts/<id>.mdShared prompts people pick in chat.hubzoid workspace prompts

A value from hub.settings.yaml gives way to the environment variable a setting names in env:, and a missing value falls back to the default. See the SDK guides for approvals (opens in a new tab), usage limits (opens in a new tab), work items (opens in a new tab), Hub settings (opens in a new tab), cards (opens in a new tab) and sandboxes (opens in a new tab).

Runtime folders

Hubzoid creates these while it runs, under the Hub folder or under HUBZOID_DATA_DIR when set. Keep them out of Git and include them in backups with hubzoid backup.

PathContents
.hubzoid/hub.dbThe Hub's own tables when SQLite is used, and on a single Hub also the operational store: accounts, sessions, conversations, access, audit and usage.
.hubzoid/dbos.dbThe workflow engine's run history, when SQLite is used.
.hubzoid/secret.keyThe deployment key of a single Hub (mode 0600), unless HUBZOID_SECRET_KEY is set. A deployment of several Hubs keeps it next to its manifest, in its data folder. Back it up apart from the data.
.hubzoid/deployment.jsonA pointer to the deployment's manifest, for a Hub that runs with others.
.hubzoid/artifact_secretSecret that signs download links (mode 0600).
.hubzoid/chats/<chat>/uploads/, .hubzoid/chats/<chat>/artifacts/Files people attached, and files the agent saved with write_artifact.
.hubzoid/artifacts/Published artifacts and live reports.
.hubzoid/runs/<workflow>/<run>/A run's private folder, hub.run_dir.
.hubzoid/data/The Hub's private data folder, hub.data_dir.
.hubzoid/outbox/, .hubzoid/alert-preview/Emails and email alerts written instead of sent, with HUBZOID_EMAIL_DELIVERY=preview.
.hubzoid/evals/One results file per eval run. The last 200 are kept (HUBZOID_EVAL_KEEP_RUNS).
.hubzoid/backups/Scheduled backups, unless HUBZOID_BACKUP_DIR says otherwise.
.hubzoid/schedule-state.jsonFire times and last results of markdown tasks and scheduled evals.
.hubzoid/schedule/<task>@<person>/A markdown task's scratch folder for the account it runs as, always writable by that run.
.inbound/webhooks/<name>/Generic webhook events waiting for a task. Handled events move to .processed/.
.inbound/Delivery dedup records and Telegram bindings.
output/<session>/Fallback folder for tool output when no chat is in scope, such as hubzoid test.
logs/The shared browser's log, when HUBZOID_BROWSER=true.

Next steps

Choose which cookies Hubzoid can use. You can change this at any time from Cookie settings in the footer. Read the Cookie Policy for details.