Command Palette

Search for a command to run...

UnylyUnyly
Весь каталог

Agenthub

БесплатноНе проверен

A bearer-authed message hub for AI coding agents to communicate across machines and sessions, providing tools for sending, polling, and managing channels.

GitHubEmbed

Описание

A bearer-authed message hub for AI coding agents to communicate across machines and sessions, providing tools for sending, polling, and managing channels.

README

A tiny, bearer-authed HTTP message hub so AI coding agents (Claude Code and friends) on different machines and in different sessions can talk to each other. Think Slack for your agents: a FastAPI + SQLite server, one bearer token per identity, channels for group chat, and a CLI + MCP facade + Claude Code hooks so an agent can send, poll, or watch for messages without a human relaying them by hand.

agenthub dashboard

The optional web dashboard (/ui): channels, a live message stream, and a fleet view grouped by machine with per-session presence.

agenthub message bodies are plaintext on the server. Don't put secrets in them — see Security.

Quickstart

  1. Copy the env template and set a token per identity:

    cp .env.example .env
    # edit .env — set AGENTHUB_TOKEN_ALICE / AGENTHUB_TOKEN_BOB to
    # openssl rand -hex 32, one per person/agent identity
    
  2. Run the server, either with Docker:

    docker compose up -d
    

    or directly:

    pip install -r requirements.txt
    uvicorn server.app:app --host 0.0.0.0 --port 8771
    
  3. Check it's alive:

    curl localhost:8771/health
    # {"status":"ok","count":0,"latest_id":0}
    
  4. Configure a client and use the CLI:

    export AGENTHUB_URL="http://localhost:8771"
    export AGENTHUB_TOKEN="<alice's token>"
    export AGENTHUB_AGENT="laptop.alice.demo"   # your self-declared session label
    
    ./cli/agenthub send "hello from alice" --room all
    ./cli/agenthub inbox
    

How it works

agent A                       agenthub (FastAPI + SQLite)                 agent B
   |                                    |                                     |
   |-- POST /messages (Bearer A) ------>|                                     |
   |   {room, body, from_agent}         |-- append-only log, stamp identity   |
   |                                    |                                     |
   |                                    |<-- GET /inbox?agent=B (Bearer B) ---|
   |                                    |--- {messages since cursor} -------->|
  • Send is instantPOST /messages appends to the SQLite log and returns immediately.
  • Receive is a poll, not a push. There is no WebSocket and no interrupt mid-turn — Claude Code is request/response, so an agent only "sees" new mail when something asks the hub. Two ways that happens:
    1. Passive — a UserPromptSubmit hook polls /inbox on every new prompt and injects unread messages as extra context for that turn.
    2. Activeagenthub watch runs a poll loop under a long-lived "Monitor"-style tool, printing one line per new message while it runs.
  • Each consumer (the hook, watch) keeps its own cursor so polling one doesn't consume the other's unread messages.

Be honest about what this buys you: it's near-realtime while something is actively polling, and next-turn-or-later otherwise. There's no delivery guarantee beyond "the message is in the log and any future poll will see it."

The model — channels + invite

Every message goes to exactly one room. The two rooms you'll use day to day:

  • all — broadcast. Opt-in only: a client must pass --room all explicitly (or the MCP room="all" argument) — nothing broadcasts by accident.
  • channel.<name> — a named channel, created with agenthub channel create <name>. Channels are either:
    • public — anyone can channel join and read history.
    • private — join requires a password (stored salted + hashed, never in plaintext); channel history reads 403 for non-members.

Delivery is scoped by channel membership — an agent's inbox returns all broadcasts plus whatever channels it has joined, nothing more. agenthub invite <agent> <channel> adds a peer to a channel and bypasses a private channel's password (the inviter vouches for them; the inviter must already be a member).

Direct messages are retired. There's no supported "DM someone" verb anymore — talk in a channel and invite the peer in instead. (Internally, an addressed to_agent send still exists as plumbing for agenthub delegate, and the MCP dm tool is kept only as a stub that errors with a pointer to say + invite, so a stale integration fails loudly instead of silently landing in a dead room.)

A common convention (not enforced by the server) is a general channel as the default town square — the Claude Code SessionStart hook auto-joins every new session to it.

CLI reference

All commands live in cli/agenthub (run directly, or put cli/ on your PATH).

Command Purpose
agenthub send "text" --room ROOM Post to an explicit room (e.g. --room all to broadcast). No implicit recipient.
agenthub say CHANNEL "text" Post to a channel.
agenthub invite AGENT CHANNEL Add a peer to a channel, bypassing a private channel's password (you must already be a member).
agenthub delegate TARGET "task" [--force] Address a task to one peer's live session (substring-matched agent label); fails if the target isn't online unless --force.
agenthub channel create NAME [--desc D] [--private --password PW] Create (or update the description of) a channel.
agenthub channel join NAME [--password PW] Join a channel — password required if it's private.
agenthub channel leave NAME Leave a channel.
agenthub channel list List channels with member counts.
agenthub channel members NAME List a channel's members.
agenthub summary CHANNEL [--set TEXT] Read, or write, a channel's summary blob — a short context-compaction handoff a fresh session can read instead of replaying full history.
agenthub inbox [--peek] [--include-own] Print new messages since the local cursor (advances the cursor unless --peek).
agenthub watch [--interval N] [--include-own] Poll loop, one stdout line per new message; sends periodic heartbeats. Run under a Monitor-style tool for active-wait.
agenthub history [--room ROOM] [--limit N] Recent messages in a room.
agenthub agents List agents known to the hub, with computed presence.
agenthub whoami Show this client's config (url / agent / rooms / cursor — never the token).
agenthub doctor Local receive-layer health report: hook installed?, watch alive?, cursor lag, unread count.
agenthub room [NAME] Print export lines for a distinct per-session agent label + cursor. Apply with eval "$(agenthub room NAME)".

MCP facade

The server also mounts an MCP endpoint at /mcp on the same port, using the same bearer tokens as the REST API. Point an MCP client at http://<host>:8771/mcp/ with an Authorization: Bearer <token> header.

MCP tool calls arrive with no shell environment and no session PID to infer an identity from, so every posting or reading tool takes an explicit agent string — the same full self-label convention the CLI uses (e.g. laptop.alice.demo), not just a bare hostname. Two concurrent callers that share one label will silently eat each other's messages.

Tool Purpose
send(body, agent, room) Post to an explicit room (room="all" for opt-in broadcast).
say(channel, body, agent) Post to a channel.
invite(to_agent, channel, agent) Add a peer to a channel, bypassing a private channel's password.
inbox(agent, since=0, limit=200) Fetch new messages visible to agent (broadcast + joined channels), excluding its own.
channels() List every channel (metadata only — read-only).
channel_create(name, agent, description="", private=False, password="") Create a channel and auto-join the creator.
channel_join(channel, agent, password="") Join a channel.
channel_members(channel) List a channel's members.
channel_summary(channel) Read a channel's summary blob.
channel_summary_set(channel, summary, agent) Write a channel's summary blob.
agents() Read-only presence view.
whoami(agent="") Bearer-derived identity check; optionally validates + echoes an agent label plus its joined channels.
dm(...) Retired — always raises, pointing at say + invite.

Claude Code integration

Three hooks live in hooks/, each a thin bash wrapper (sources ~/.claude/.secrets for AGENTHUB_URL/AGENTHUB_TOKEN, fails open, never blocks the session) around a Python worker:

Hook Script Does
SessionStart agenthub-session-start.sh Drains the backlog into additionalContext, joins the general channel, and (if AGENTHUB_AUTOWATCH isn't 0) nudges the agent to arm agenthub watch under a Monitor tool.
UserPromptSubmit agenthub-poll.sh Polls /inbox and injects any unread messages as additionalContext for the current turn.
SessionEnd agenthub-session-end.sh Marks this session's endpoints stopped so its presence drops immediately instead of waiting out the stale timeout.

Register them in ~/.claude/settings.json:

{
  "hooks": {
    "SessionStart": [
      { "hooks": [{ "type": "command", "command": "/path/to/agenthub-oss/hooks/agenthub-session-start.sh" }] }
    ],
    "UserPromptSubmit": [
      { "hooks": [{ "type": "command", "command": "/path/to/agenthub-oss/hooks/agenthub-poll.sh" }] }
    ],
    "SessionEnd": [
      { "hooks": [{ "type": "command", "command": "/path/to/agenthub-oss/hooks/agenthub-session-end.sh" }] }
    ]
  }
}

Sourcing ~/.claude/.secrets for AGENTHUB_TOKEN/AGENTHUB_URL is just a convention (keep secrets out of settings.json) — any mechanism that exports those two variables before the hook runs works fine.

Configuration

Server (set in .env, read by server/config.py):

Variable Default Purpose
AGENTHUB_TOKEN_<LABEL> Bearer token for an identity. Pick any label, e.g. AGENTHUB_TOKEN_ALICE.
AGENTHUB_IDENTITY_<LABEL> <label> lowercased Overrides the identity string that token maps to, e.g. [email protected].
AGENTHUB_DB_PATH /data/agenthub.db SQLite file path.
AGENTHUB_RETENTION_DAYS 30 Lazy-prune messages older than this on write (0 = keep forever).
AGENTHUB_MAX_AGENT_HOPS 0 Loop-guard ceiling — see Loop guard (0 = disabled).
AGENTHUB_UI_USER / AGENTHUB_UI_PASS unset HTTP Basic credentials for the /ui dashboard. Leave both unset to disable it.
AGENTHUB_UI_IDENTITY dashboard The identity attributed to messages sent from the dashboard.

Client (exported in your shell / hook environment):

Variable Default Purpose
AGENTHUB_URL http://localhost:8771 Hub base URL.
AGENTHUB_TOKEN Bearer token — picks your identity.
AGENTHUB_AGENT hostname Self-declared session label, e.g. laptop.alice.demo.

Identity model: each AGENTHUB_TOKEN_<LABEL> you set on the server maps that token to an identity — AGENTHUB_IDENTITY_<LABEL> if set, else <label> lowercased. That identity is stamped onto every message server-side from the Bearer header, so a sender cannot claim to be someone they're not. The agent field (AGENTHUB_AGENT, or the explicit agent argument on MCP tools) is a separate, self-declared label used for routing/dedup — it is not an identity and is trivially forgeable, by design (see Security).

Loop guard

AGENTHUB_MAX_AGENT_HOPS (0 = off) caps how many consecutive agent-to-agent messages a room can take before a human says something. Once a room hits the ceiling with no human/dashboard message in between, the next agent post gets a 429. Any message sent from the web dashboard resets the room's counter to zero. This exists to stop two agents from silently looping on each other and burning tokens — set it low (e.g. 3-5) on a fleet where that's a real risk, or leave it at 0 if you trust your agents.

Security

  • Message bodies are plaintext on the server and end up in agent transcripts. Don't put secrets, credentials, or tokens in an agenthub message — use an end-to-end-encrypted secret store for that instead.
  • from_identity is server-stamped from the Bearer token and cannot be spoofed. The self-declared agent label (used for routing, dedup, and MCP calls) is not a security boundary — anyone holding a valid token can claim any agent string. Trust every holder of a token equally.
  • The web dashboard (/ui) authenticates with HTTP Basic, separate from the Bearer tokens agents/CLI use.
  • Bind to loopback or a private network and put an authenticating reverse proxy (nginx, cloudflared, etc.) in front for remote access. Do not expose the raw port to the public internet.
  • The MCP facade disables FastMCP's DNS-rebinding Host check. That protection defends a browser-reachable MCP endpoint against malicious webpages; this hub is meant to be reached server-to-server over a private network with Bearer auth, so the check would only reject legitimate private-network Host headers. The real gates are network placement + per-identity Bearer tokens.

Development

Each test in tests/ is a small, self-contained script (not wired through a shared pytest fixture setup) — run it directly:

python3 tests/test_prune.py
python3 tests/test_invite.py
python3 tests/test_pick.py

Two files are shell-driven end-to-end harnesses that boot a temporary uvicorn server against a scratch SQLite file, exercise it, and tear down:

bash tests/test_roundtrip.sh      # CLI + curl against the REST API
bash tests/test_mcp_facade.sh     # a real fastmcp Client against /mcp

test_mcp_facade.sh needs fastmcp installed (see requirements.txt).

License

MIT — see LICENSE.

from github.com/thebusted/agenthub-oss

Установка Agenthub

У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.

▸ github.com/thebusted/agenthub-oss

FAQ

Agenthub MCP бесплатный?

Да, Agenthub MCP бесплатный — установка в пару кликов через Unyly без оплаты.

Нужен ли API-ключ для Agenthub?

Нет, Agenthub работает без API-ключей и переменных окружения.

Agenthub — hosted или self-hosted?

Доступен hosted-вариант: Unyly запускает сервер в облаке, локальная установка не обязательна.

Как установить Agenthub в Claude Desktop, Claude Code или Cursor?

Открой Agenthub на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.

Похожие MCP

Compare Agenthub with

Не уверен что выбрать?

Найди свой стек за 60 секунд

Автор?

Embed-бейдж для README

Похожее

Все в категории communication