{
  "markdown": "# hubd\n\n**The project tracker for teams of humans and AI agents — in plain files.**\n\nA tool for agents rarely fails by crashing. It fails by *answering* —\nconfidently, and wrong. A list that ended early without saying so. A count that\nturns out to be mostly duplicates. A task close that lands on somebody else's\nid. A person would stop at \"wait, fifteen hundred tasks? I didn't create\nfifteen hundred tasks.\" An agent has no such prior: it takes the number and\nbuilds on it, and every view downstream inherits the mistake, still sounding\nsure.\n\nhubd is built against that failure mode, and it shows in the boring parts. The\nlogs are append-only and attributed, so a wrong view stays recoverable from data\nthat was always right. Every truncation announces itself. Anything the hub\ncannot observe is reported as unobserved rather than estimated. Much of this\ncodebase is not features — it is refusals to sound certain.\n\nYou run two, three, five agent sessions — different tools, different vendors —\nacross your projects. Each one is brilliant, and each one has no idea the\nothers exist. You are the coordination layer: copy-pasting context,\nre-explaining state, discovering on Monday what an agent did on Friday.\n\nhubd replaces you in that job with the most boring technology available:\n**plain files**. A shared headquarters for your whole team — agents *and*\nhumans: a journal of what everyone did, task queues every agent can wait on,\ncross-project tasks, and a read-only kanban to watch it all. All markdown and\nJSONL, in a folder you own.\n\n![the hubd kanban: agents pick up, finish and file work while the activity log fills in](https://raw.githubusercontent.com/bzdOS/hubd/main/docs/media/kanban.gif)\n\n*`hub serve` — the board is read-only and has exactly one button (**⚙ Rules**, it opens\nAGENTS.md). Cards move because agents move them; the page just re-reads the files.*\n\n**Not a runner.** Orchestrators launch your coding agents and stream their\noutput — that's making coding faster. hubd manages the *work*: which projects,\nwhat's next, who does it and when, what already happened. An orchestrator can\nrun your agents; hubd runs your projects. They compose.\n\n## The Unix pair\n\n- **`hubd`** — the daemon: an MCP server (stdio, JSON-RPC 2.0) that agents talk to.\n- **`hub`** — the CLI: the same data for humans, no LLM required.\n\nLike `sshd` and `ssh`. The daemon serves agents; the CLI serves you.\n\n## Quick start\n\n**Option A — start a company (copy the folder).** One command drops\n[`hubd-company/`](hubd-company/) into a folder of your own:\n\n```bash\nnpx degit bzdOS/hubd/hubd-company my-company   # then: cd my-company && git init\n```\n\nOr clone this repo and copy the folder — it doesn't have to be your repo root.\nYou get a ready org structure:\nconstitution (AGENTS.md), role onboardings, project cards, an operator card,\nqueues, recipes, and a weekly agent-written `chronicle/`\n([the narrative layer](docs/narrative-layer.md)).\nHiring an agent = a fresh session reads a role file. This template is NOT\nincluded in the npm package; it comes from the repo.\n\n**Option B — add the binaries to what you have:**\n\n```bash\nnpm i -g @bzdos/hubd   # installs both binaries: hubd (MCP server) + hub (CLI)\nhub init             # scaffold a team folder: AGENTS.md, INBOX.md, queues/\nhub version          # which hubd, and which copy of it is answering\nhub doctor           # hub base, team root, locks, queues, ghost queues, writer versions\nhub status           # every project at a glance (⚠ marks a card behind its journal)\nhub brief            # morning brief: tasks, journal, locks\nhub queue gc         # list queues nobody ever consumed (--apply archives them)\n                     # (doctor flags work dispatched to a role with nobody home)\nhub now              # the ONE task to do next, and why it won\nhub agenda           # the day split by who can act: agent work vs owner buttons\nhub recall \"<q>\"     # ranked memory, every hit dated and flagged if stale\nhub usage --days 7   # what the work cost: supplied vs measured, never mixed\nhub audit            # what the cards declare vs what happened (--apply files incidents)\nhub lint             # which of your rules are checks, not just prose\nhub serve            # read-only kanban on localhost\n# one-off, without install: npx -p @bzdos/hubd hub status\n```\n\nThe npm package ships: `hub/` (binaries + lib), `prompts/`, `docs/`, `README.md`,\n`LICENSE`, and `HARVEST.md`. It does NOT include `hubd-company/`.\n\nNew here? Two guides: the [quick start](docs/quickstart.md) walks the whole\npath — install → team folder → first agent → queues — and\n[recipes](docs/recipes.md) gives complete scenarios (a standing worker, an\norchestrator fleet, owner buttons, harvesting a chat, infra topology).\n\nConnect your agent (any MCP client):\n\n```bash\nclaude mcp add --scope user hubd --env HUBD_AGENT=dev-<yourproject> -- npx -y @bzdos/hubd\n```\n\n`HUBD_AGENT` is worth setting on day one. Every write names its author —\njournal entries, tasks, queue messages — and the field is required: an\nappend-only log with an unattributed write in it stays unattributable forever. `HUBD_AGENT` is the floor: when a caller does\nnot say who it is, the write is attributed to that name plus a short per-session\nsuffix, instead of failing. Name the **function**, not the model — `dev-hubd`,\n`reviewer-bsdos` — because which model you are is already in your client's own\ntranscript, while many sessions share it. Model and client names (`claude`,\n`gpt`, `cursor`) and placeholders (`unknown`, `cli`, `root`) are refused for\nthat reason. A caller that knows its own function can always be more specific\nthan the floor.\n\nNo MCP? No problem — every model that can read and write files can join:\npaste the matching block from [`prompts/`](prompts/) (Claude Code, Cursor,\nCodex/AGENTS.md, or an MCP chat) — it wires hubd in and points at `HUBD.md`,\nthe always-current protocol.\n\n**Running it for a team?** hubd also speaks MCP over HTTP — one shared hub all\nyour agents point at, token-gated and multi-tenant. See\n[self-hosting](docs/self-hosting.md).\n\n## Updating, and where your data lives\n\nhubd is a tool, like `git` or `node`: you install the **code**, and your **data**\nis a folder you own. They are two separate things — and that is the whole point.\n\n- **Code** — the npm package. Update like any global CLI:\n  `npm i -g @bzdos/hubd@latest` (or run one-off with `npx -y @bzdos/hubd`). A new\n  version ships the engine ([changelog](CHANGELOG.md)); it never touches your data.\n- **Data** — `HUBD_DIR` (default `~/.hubd`): plain markdown + JSONL, yours to keep.\n- **Who wrote it** — `HUBD_AGENT`: the default author for calls that omit one, per\n  server config. Set it in every client and on every host; a required field with no\n  floor turns a forgotten argument into a failed call.\n- **Is the mesh actually syncing?** `hub doctor` counts how many commits this hub\n  is behind `origin`, because a sync loop that keeps retrying looks exactly like one\n  that works: one node here went 228 commits without receiving anyone else's work\n  while every report called the hub healthy. It also names tracked paths that differ\n  only by case — on macOS or Windows those are one file for two index entries, which\n  no commit can ever clean, and they stop a merge permanently. Since 0.9.6 hubd will\n  not create such a pair in the first place, and doctor flags any card still holding\n  conflict markers, since a reader serves those as content rather than as an error.\n- **When a card does conflict** — the only shared file that can, being the one\n  mutable one — `hub card resolve` unions the bullet-list hunks (two nodes appending\n  facts have not disagreed) and leaves prose hunks for you, named by section. It\n  exits non-zero while anything is left.\n- **Several machines?** Make `HUBD_DIR` a git repo and sync it however you like —\n  a private remote over SSH works, no GitHub needed. Each machine installs the\n  code from npm; your data travels in your own git. Two separate tracks: code from\n  the package, data in your folder. Upgrading the code never migrates or deletes\n  your data — the event logs are append-only and richer than any one version's schema.\n- **Which version is actually running** — `hub version` prints the number *and the path\n  of the copy that printed it*, because on a real machine those are one question: a stale\n  global install and a live source checkout are both called `hub`. From 0.9.4 each journal\n  line also carries the version that appended it, so `hub doctor` reports the whole mesh —\n  which node is behind, whether **this** copy is the stale one, and whether two installs\n  are writing into the same node. This exists because the machine that develops hubd ran a\n  CLI nine releases old for weeks and nothing anywhere could have said so.\n- **What an upgrade needs from you** — sometimes a new version wants something outside\n  the code: a variable in a client's config, a role declared in the hub, a protocol\n  section worth re-reading. hubd works that out and tells the agents itself:\n  `hub_whatsnew` returns an `environment` list, every item saying what is wrong, what\n  fixes it, and **who can** — the agent, the agent plus a client restart, or you. A\n  protocol change names the sections that actually moved, so nobody re-reads the whole\n  manual. `hub doctor` shows the same list to a human. Nothing blocks a call, nothing\n  needs acknowledging: an item disappears when the condition does. Per-node state in\n  `.env-state.json`, never mesh-synced — three machines have three environments.\n\n## How it works\n\n- **Journal & structured reports** — append-only team log (INBOX.md) you read\n  with your eyes. At session end an agent files a `hub report` of prefix-tagged\n  lines (`DECIDE: … | why`, `FACT:`, `COMM:`, `NEXT:`, `DONE: ids`) that fan into\n  the project card's sections — structure in fields, not one prose blob. \"What\n  changed\" is read from git, not retyped. The card's section headings (in any\n  language) come from one file, `HUB/sections.json`, which drives both the card\n  scaffold and the report router — so they never drift.\n- **Queues** — per-role message queues. Send work; an agent blocks on `wait`\n  until something arrives, then goes back to waiting. No polling you, no\n  prodding them. A queue has one live consumer by default — run a single waiting\n  session per role. Roles listed in `<team>/subscriber-roles.json` fan out instead:\n  every waiting session gets its own cursor and sees every message. Crossing\n  machines is a separate, replaceable concern: `scripts/mesh-sync.sh` moves the\n  folder over git+ssh, and [mrgd](https://github.com/bzdOS/mrgd) can carry the\n  same queues as Matrix room traffic — concurrently, on the same directory. See\n  [docs/interop.md → Transport](docs/interop.md#transport-how-a-queue-crosses-machines),\n  including how to check which of the two is actually enabled on a given node.\n- **Projects & tasks** — one card per project; cross-project tasks with\n  owners (agent or human) and claims as soft locks, so two agents don't\n  clobber each other.\n- **Resources & relationships** — infra is a card too: hosts, vms, services,\n  endpoints, providers under `resources/`, with structured frontmatter\n  (type, address, os, provider, status) and **typed `[[wikilink]]` edges**\n  (`runs_on`, `depends_on`, `deploys_to`, `exposes`, `part_of`, ...). The same\n  edge mechanism reads project cards, so `hub graph` renders one topology\n  across projects ↔ resources; a task links to what it touches with\n  `--resource`. Facts go in fields, not prose.\n- **Kanban (read-only)** — cards move because agents move them. The only\n  button is **⚙ Rules**, and it opens AGENTS.md. You don't manage the\n  agents — you manage the rules.\n- **Harvest** — one prompt turns any working dialog into project digests, tasks\n  and logged decisions. Served as an MCP prompt (`harvest`) and `hub harvest`, so\n  you invoke it straight from your client — no fetching the file. See\n  [HARVEST.md](HARVEST.md).\n- **MCP + files, two levels of compatibility** — smart clients connect over\n  MCP; everything else uses the files directly. If hubd is down, your data\n  is still just markdown.\n- **Instructions that stay current** — your team rules live in `AGENTS.md` (yours\n  to write); hubd's own mechanics live in `HUBD.md`, regenerated per node from the\n  installed version (gitignored, never synced). Update the code → the next `hub`\n  run (or `hub upgrade`) refreshes `HUBD.md`, so even agents that only read the\n  files never follow stale instructions.\n\n## Principles (violating these = not this product)\n\nFiles first. Dumb server, smart agents — **no AI inside**: hubd stores and\nserves, intelligence comes from your agents. **Never sound more certain than the\ndata**: a tool that misleads its reader is broken even when nothing errored, so\na truncated answer says it was truncated and a number the hub cannot observe is\nnever estimated. Human-readable everything. Zero dependencies. Read-only for\nthe human; write access flows through rules.\nGraceful degradation: no MCP → files; no hubd → files still readable as-is — in\nany editor, `grep`, or a Markdown app like Obsidian. See\n[Reading your hub with any tool](docs/interop.md).\n\n## About that recording\n\nThe board at the top is the real thing on invented data:\n`node scripts/capture-kanban.mjs --gif` stands up a throwaway hub in a temp\ndirectory, serves it, then edits it mid-capture — assigns a card, closes one,\nfiles a task, records a decision — and lets the page notice by itself. Nothing is\nstaged and nobody's actual hub is ever filmed. Six board updates, and only one of\nthem is a card sliding right: agents also *add* work, and most of what lands in a\ncoordination log moves no card at all.\n\n## What hubd is not\n\nNot an orchestrator (doesn't launch agents or stream output). Not vector\nmemory (the journal stores facts you can read, not embeddings). Not a Jira\nfor humans (the human here is a spectator and a legislator, not an assignee).\nNot another chat (talk to hubd through *your* agent; hands — CLI; eyes —\nkanban).\n\n## Built by the team it coordinates\n\nhubd's own development runs through hubd: one human and a few agents on\nmodels from different vendors, coordinating through nothing but the files\nabove. It's our daily dogfood — and the most honest illustration we can offer\nof the protocol under real use, including the evening a tooling failure forced\neverything back to plain files and the work simply kept moving. One team's\nstory, lightly anonymized and self-reported, not a benchmark: twelve weeks of\nit in [field notes](docs/field-notes.md) — every mechanism that broke, and the\nbug that had every dashboard confidently agreeing on a number that was 72%\ninvented — and one evening hour by hour in [the case study](docs/case-study.md).\n\nThe human's main job was editing the rules.\n\n## Pricing\n\nThe core is MIT, forever. Personal use is free, forever. If a hosted team\nplan ever exists, the line is simple: **agents are free, humans are billed.**\n\n## Roadmap\n\nShipped: multi-machine sync (per-host append-only logs, conflict-free); remote\naccess over HTTP (token-gated, multi-tenant, see [self-hosting](docs/self-hosting.md));\na typed **relationship graph** (`[[wikilink]]` edges across projects and resources,\n`hub graph`); **resources** as first-class cards (hosts / services / endpoints);\n**structured reports** that fan into card sections; one-file section **i18n**\n(`sections.json`); a per-node **`HUBD.md`** protocol that regenerates to match the\ninstalled version; **harvest** as an MCP prompt; cwd → project auto-bootstrap\n(`hub_context`: marker file / recorded sync path / folder-name guess, no manual\n`hub_get` needed); a **presence registry** (`hub_heartbeat`/`hub_presence`,\nTTL freshness like claims) so MCP/headless agents show up next to screen-scraped\nones, with queue depth surfaced in `hub_brief`; and **buttons** — owner-decision\nqueue items rolled up in `hub_brief` as \"N buttons waiting (oldest X days)\"\n(`HUB/owner-roles.json` names the human roles).\n\nNext: task kinds with their own lifecycles (a *communicative* task knows it's\nwaiting on a reply); an end-to-end remote mode (the server never reads your\nwork); a gateway that proxies your personal MCP servers; and the\n**narrative layer** promoted into the server — `hub_chronicle` / `hub_probe`\nplus mood/check-in journal kinds, once the file-first version proves itself\n([design](docs/narrative-layer.md), templates in `hubd-company/`). The file\nformat is the stable contract; everything else is negotiable.\n\n## Where this was used, and what it actually prevented\n\nThe case hubd was built against, and the one worth describing because it is the\nawkward shape real work has:\n\n**Bringing up a from-scratch EL2 hypervisor on a Banana Pi M64** — a bare-metal\ntype-1 hypervisor running FreeBSD 15.1 arm64 as its guest, plus a Mali-400 GPU\ndriver ported to FreeBSD along the way. Three separate repositories came out of\nit: **[bzdk](https://github.com/bzdOS/bzdk)** (the hypervisor),\n**[lima-freebsd](https://github.com/bzdOS/lima-freebsd)** (the GPU driver,\nextracted so it is useful without the rest), and\n**[bsdos](https://github.com/bzdOS/bsdos)** (the operating system this is all\nfor).\n\n**The build machine and the board were never the same machine.** The\ncross-compiler, the FreeBSD and drm-kmod source trees and the Mesa build lived on\none host. The board arrived at another, on a different network, with the serial\nconsole and the debug Ethernet physically attached *there*. So the work was\nsplit: compile in one place, flash and observe in another. Several agents worked\nit in parallel — one on clocks, one chasing DMA coherency, one writing tests.\n\nWhat that costs without a shared journal is specific, not abstract:\n\n- **Two agents driving one board.** The serial port takes one reader; two make a\n  healthy channel look dead. \"Who has the board\" has to be a fact somebody wrote\n  down, not an assumption.\n- **Re-deriving the same finding.** A hardware bug diagnosed on Tuesday gets\n  re-diagnosed on Thursday by someone who never saw the first conclusion. Several\n  of the ten upstream patches that came out of this project took a full day to\n  find; finding one twice is a day thrown away.\n- **Claims with no number behind them.** \"The fix works\" is not portable between\n  machines. \"512 MiB of reads, zero errors, previously died after 27 MiB\" is.\n  hubd's reports are where those numbers went, which is why the release notes\n  could be written from records instead of memory.\n- **Stale conclusions outliving their evidence.** Half a day of this project was\n  spent finding documents that confidently stated things the code had since\n  disproved. An append-only journal does not stop that, but it does let you see\n  when a claim was made and what was true then.\n\nNone of that needs a server, and none of it left the machines involved: the data\nis markdown and JSONL in a folder, synced through a private git remote over SSH.\nThat is the whole reason it was built this way.\n\n## License\n\nMIT.\n",
  "bytes": 19037,
  "sha": "4cfac15dd873a4d37c1596438afc3663a6bc43e5fb136366ca419bacae9c04f4",
  "repo_slug": "bzdos/hubd",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_bzdos_hubd_0936166c/readme"
}