Atlas / MCP servers / bzdos / bzdos-hubd

bzdos-hubdCAUTION

mcp/bzdos/hubd

The project tracker for teams of humans and AI agents — in plain files. MCP server + CLI, zero dependencies.

Verdict
CAUTION
Grade
B
Trust score
81 /100
Exposed tools
33 26r · 7w · 0d
Transport
stdio
License
MIT
Stars
0
01

Overview

From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.

The project tracker for teams of humans and AI agents — in plain files.

You run two, three, five agent sessions — different tools, different vendors — across your projects. Each one is brilliant, and each one has no idea the others exist. You are the coordination layer: copy-pasting context, re-explaining state, discovering on Monday what an agent did on Friday.

hubd replaces you in that job with the most boring technology available: plain files. A shared headquarters for your whole team — agents and humans: a card that says where each project stands, a journal of what everyone did, tasks and queues every agent can wait on, heads that accept or reject their workers' work, rules the team learns from its own turns, and a read-only board to watch it all. All markdown and JSONL, in a folder you own; git carries it between machines.

`hub serve` on the demo hub. Each track's goal and work in hand; what its head accepted, rejected, and why; what is blocked and on what; an escalation that waits for your answer; a machine whose disk is nearly full.

Not a runner. Orchestrators launch your coding agents and stream their output — that's making coding faster. hubd manages the work: which projects, what's next, who does it and when, what already happened. An orchestrator can run your agents; hubd runs your projects. They compose.

Try it in a minute

npm i -g @bzdos/hubd
hub demo             # two tracks, six roles, three machines, a week of their work

hub demo writes an invented week of a small team into a folder of its own and prints the commands to look at it: the board on a port beside your own, hub board, hub agenda, the rules about to become laws, hub recall. Your own hub is not read or written. Run it again for a fr

Read from source at commit 6f661619d24dOBSERVED · 2026-10-10
02

Connect

Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.

claude-code (npm)
claude mcp add hubd -- npx -y @bzdos/[email protected]
03

Exposed tools (33)

26 read · 7 write · 0 destructive.

ToolRiskDescription
harvestreadHarvest this dialog into the hub — projects, tasks, decisions, links, open questions (the Harvest Protocol). No need to fetch HARVEST.md.
hub_agendareadThe day split by WHO CAN ACT: agent work ready now, the owner\
hub_card_setwriteCreate or update a project card from just a name and a digest — no folder needed (unlike hub_sync). Use it to capture a project that is not a local git checkout, e.g. when harvesting a dialog. Preserves any hand-written frontmatter and Facts. To fix ONE stale line without touching the owner\
hub_claimreadSoft-lock a work area so other agents see it. Not enforced — informational. Write
hub_claim_checkreadBefore editing a file: is it inside somebody\
hub_contextreadWhere am I — the first call of a session and the first call after a context compaction. Resolves which hub project YOUR working directory belongs to, most to least certain: a .hubd marker file (repo root, first line = project slug) · a project card\
hub_getreadONE project in depth: its card, its recent journal entries and any active soft-locks. Compact by default — the card
hub_graphreadThe typed relationship graph across projects AND resources: who runs where, what depends on / deploys to / exposes what. Edges are frontmatter [[links]] keyed by relation (runs_on, depends_on, deploys_to, exposes, part_of, ...). Returns nodes, edges, and dangling links. Filter by project or type.
hub_heartbeatreadRecord that an agent is alive — call it each work cycle (right after hub_report, before the next hub_queue_wait) so MCP/headless agents show up in hub_presence the same way screen-scraped ones do, no human bridge needed. Overwrites this agent\
hub_lawreadA head\
hub_nextreadThe ONE task to do now, and why it won — not a list. Picking from a list is work, and a session that has to pick tends to pick the easy one. A task whose dependencies are still open is never eligible, however loud it is. Says explicitly when the chosen one is the owner\
hub_onboardingreadOrientation for an agent that has never worked with this hub before: which channel to use for what (claim vs task vs report vs queue — the #1 mistake), the author rule, the session ritual, how to recover after a compaction. Call this FIRST the first time you connect. Default mode
hub_presencereadThe fleet roster as far as it can honestly be seen from here: this node\
hub_queue_ackreadConfirm that a delivered queue block was processed, not just read. Without this, a zombie session that reads a block and dies looks exactly like a processed one — the sender sees pending=0 but gets no reply. Ack moves the block from
hub_queue_sendwriteAppend a message to a role\
hub_queue_waitreadBlock until new content lands in <role>\
hub_queue_wait_allreadSubscribe to EVERY role\
hub_recallreadWhat do we know about X — ranked across project cards, their sections, decisions, the journal and tasks, instead of hub_search\
hub_reflectreadThe reflection digest of one project, what a head reads instead of its workers\
hub_releasewriteRelease a soft-lock. Pass id, or project+area+agent, or task+agent (give a started task back to the work queue).
hub_reportreadAppend a session report to the shared journal: what was done / broken / blocked. Lines are routed by prefix: DECIDE: (what | why), FACT:, HYPO:, COMM:, NEXT:, DONE: <id>, TASK:, NOTE:, TO:, HANDOFF:. HANDOFF: lines replace your own
hub_resource_getreadOne resource card plus its inbound and outbound typed relationships.
hub_resource_listreadList resource cards (hosts, vms, services, endpoints, providers). Optionally filter by type.
hub_resource_setwriteCreate or update a resource — an infrastructure/topology entity: host, vm, service, endpoint, or provider. Structured attributes (type, address, os, provider, status) and typed relationships go in fields, NOT prose. Use this instead of describing infra inside a card digest.
hub_statsreadWhat the sessions cost and what came of it, per task, model, role or day. Tokens are READ from the clients\
hub_syncwriteSync a project folder into the hub. Collects git facts automatically; pass digest (your own summary of state/next steps) and the card is rewritten.
hub_task_addwriteAdd a task to the shared cross-project backlog.
hub_task_getreadONE task by id, plus what it is blocked by and what it blocks, and, once the hub holds sessions (hub sessions ingest),
hub_task_listreadList backlog tasks. Filter by project and/or status; page with limit/offset.
hub_task_updatewriteUpdate a task: close it (status=done), reassign, reprioritise, edit text/deadline/cat.
hub_trajectoryreadDeterministic dependency-graph plan over tasks\
hub_usagereadWhat the work cost, over a window, per project and per agent — with a hard line between SUPPLIED (seconds/tokens/money, reported by clients through hub_usage_add: what the hub can neither measure nor read; a session\
hub_whatsnewreadPersonalized
04

Trust audit

CAUTIONgrade B · trust 81/100 Install with care. The audit found things worth knowing before you trust its output.

LayerWhat it checksResult
L0Provenance & inventoryPASS
L1Static analysis of the codeWARN
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfacePASS
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
declared (10 observation(s))
Network
declared (6 observation(s))
Shell
declared (5 observation(s))
Dependencies
pinned
Secrets in source
found

Findings (22)

MEDIUMInformation disclosure · disclose.log_secret · CWE-209, CWE-532
hub/cli.mjs:1362
console.log(removeSecret(name, { teamRoot }) ? `removed ${name}` : `no secret named ${name}`);
MEDIUMHard-coded secrets · secret.private_key · CWE-798, CWE-321
tests/logic/queue.mjs:963
ok(refused('-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaA\n-----END OPENSSH PRIVATE KEY-----', /carries a PEM block/), 'cargo: a PEM block is refused');
LOWInventory / provenance · inv.hidden_file · CWE-1104
.hubd
.hubd
Why it matters. hidden member outside the usual dotfiles
Fix. review its purpose
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
hub/lib/core.mjs:2142
for (const [k, v] of Object.entries(secs)) out[k] = crypto.createHash('sha1').update(v).digest('hex').slice(0, 10);
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
hub/lib/reflect.mjs:229
export const ruleId = (s) => createHash('sha1').update(ruleKey(s)).digest('hex').slice(0, 6);
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
hub/lib/sense.mjs:124
export const entryHash = (e) => crypto.createHash('sha1').update(String(e.text || '')).digest('hex').slice(0, 10);
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
hub/lib/sessions.mjs:57
const hash = (s) => crypto.createHash('sha1').update(s).digest('hex').slice(0, 16);
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
hub/lib/watch.mjs:42
const hashOf = (family, line) => crypto.createHash('sha1').update(family + '\n' + line).digest('hex').slice(0, 12);
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
hub/lib/core.mjs:13
try { return JSON.parse(fs.readFileSync(new URL('../../package.json', import.meta.url), 'utf8')).version; }
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
hub/lib/core.mjs:2147
try { return fs.readFileSync(new URL('../../prompts/protocol.md', import.meta.url), 'utf8'); }
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
hub/lib/core.mjs:2429
try { md = fs.readFileSync(new URL('../../HARVEST.md', import.meta.url), 'utf8'); }
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
hub/lib/prompts.mjs:16
export const META_DIR = fileURLToPath(new URL('../../prompts/meta/', import.meta.url));
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
scripts/gen-reference.mjs:547
const fragRows = names.map(n => [`[${n}](../../prompts/meta/${n}.md)`, docs.templates[n] || '',
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
docs/scenarios/03-track-with-a-head.md:218
hubd kanban  http://127.0.0.1:7790
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
docs/scenarios/04-fleet-on-three-machines.md:183
hubd kanban  http://127.0.0.1:7790
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
docs/scenarios/08-notifications.md:50
export MATRIX_HS=http://127.0.0.1:7808 MATRIX_ROOM='!team:example.org' MATRIX_TOKEN=stand-in
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
docs/scenarios/08-notifications.md:51
export SLACK_WEBHOOK=http://127.0.0.1:7808/services/T000/B000/stand-in
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
docs/scenarios/08-notifications.md:52
export NTFY_URL=http://127.0.0.1:7808/hubd-oak-k7q2m9
INFOInventory / provenance · inv.oversize · CWE-1104
docs/media/kanban.gif
docs/media/kanban.gif
Why it matters. 2777093 bytes not read
INFOPrompt injection · prompt.authority_framing · CWE-94, CWE-1427
docs/self-hosting.md:212
- **One token = full access** (single-tenant) or **one token = one workspace**
INFOPrompt injection · prompt.authority_framing · CWE-94, CWE-1427
site/index.html:85
<div class="hint"><b>Share this exact line</b> to bring your team into the same hub — same token, same workspace. Anyone who has it gets full access, so treat it like a key. Need a separate space? <bu
INFOPrompt injection · prompt.credential_read · CWE-94, CWE-1427
docs/start/4-second-machine.md:243
cat >> ~/.ssh/config <<'EOF'
Why it matters. asks the agent to read credentials

Gates applied: no_behavioural_pass.

Audited 2026-10-10 · audit v0.4.1 · source sha 6f661619d24dfull audit observations/trust-audit/mcp-server/bzdos__hubd.json · Report an issue / request a re-scan
05

Audit history

Every audit this server has had. A grade with a past is a grade somebody is still checking.

DateSourceVerdictGradeScoreChange
2026-10-106f661619d24dCAUTIONB81first audit
06

Questions

What is the bzdos-hubd MCP server?

The project tracker for teams of humans and AI agents — in plain files. MCP server + CLI, zero dependencies.

What tools does bzdos-hubd expose?

33 in total: 26 read-only, 7 that write, and 0 that can delete or overwrite. Every one is listed on this page with its risk.

Is bzdos-hubd safe to connect to an agent?

With care. The audit graded it B (81/100) and found 22 things worth knowing before you trust this server, listed below with the exact line each was found on.

What credentials does bzdos-hubd need?

It reads HUBD_SECRETS_DIR and HUBD_TOKEN from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.

How does bzdos-hubd run?

It speaks stdio, so it runs as a local process your client starts. It is published on npm as @bzdos/hubd at 0.9.68.

How current is this page?

The grade is for one exact copy of the source (6f661619d24d), read on 2026-10-10. The repository is watched and re-audited when it changes.

Advertisement