Fleetgraph is the Hermes plugin; Fleet Command is its operator-facing control surface for building and running the organization.
Build an actual organization of Hermes agents, not just a list of profiles.
Running multiple agents creates a coordination problem: who owns a task, who can help, who has authority to make a decision, and when work should move up or down the chain. Fleet Command gives that system a persistent structure.
Create or adopt bot profiles, assign their supervisors, attach reports, define peer relationships, and configure each member's SOUL, model, skills, and toolsets. The plugin writes those relationships into the fleet graph, so the command structure becomes part of how the agents operate rather than a diagram someone has to keep in their head.
Use the fleet as a Deck for day-to-day operations or a Graph for understanding the full topology. See which bots are working, which are idle, which are interrupted, which have unread inboxes, and where recent inter-agent traffic is moving. Select any bot to inspect its live transcript, inbox, configuration, capability summary, and SOUL.
Fleet Command also gives agents the context they need to operate inside the organization. Each bot receives its current position in the chain, its supervisor, its reports, its peers, and a roster describing what other members are equipped to handle. Capability matching helps identify the right specialist for a task instead of forcing every agent to absorb work outside its role.
Communication follows the structure:
- Delegate work down to reports.
- Escalate decisions up to supervisors.
- Coordinate laterally through declared peers.
- Reject messages that violate the permitted relationships.
That gives you a fleet with visible ownership and bounded authority instead of a collection of agents messaging each other arbitrarily.
- Specialist teams where each bot owns a defined domain, toolset, or type of work.
- Hierarchical production pipelines with supervisors coordinating research, execution, review, and delivery.
- Operations desks where a lead agent assigns incoming work to specialists and escalates blockers.
- Project teams with a manager, functional reports, and explicit peer collaboration.
- Routing networks where agents inspect the fleet roster and hand tasks to the member best equipped to handle them.
- Persistent command centers where the operator can watch activity, inspect conversations, intervene, rewire the organization, and add new members without editing files by hand.
Fleet Command is useful when agents need more than parallel execution. It gives them roles, reporting lines, communication boundaries, specialist discovery, and an operator-facing place to build and run the whole system.
- Graph canvas — layered DAG of supervisor/subordinate relations with peer edges drawn dashed. A fresh graph auto-fits all nodes; use Fit to recover after panning or zooming. Pan (drag), zoom (wheel, 0.4×–2× around the cursor), and click any bot to open its live transcript drawer. A valid operator viewport persists across sessions and is never overwritten by the mount default.
- Deck view (v0.8.0 Fleet Command) — team-grouped card deck: NEEDS
ATTENTION triage pile, TEAMS (one header per supervisor with capability),
UNASSIGNED with "attach under…" selects. Cards carry identity + capability
line (from the roster), a status chip (
conversing/ready 2h/interrupted/idle) and the unread pill. Clicking a card opens the docked inspector (slide-over on the graph canvas) with five tabs: Live (4s-polling transcript), Inbox (messages + mark-all-read), Message (framed composer — see below), Configure (supervisor/reports/peer editors), SOUL (editor). Search filters by name/title/capability keeping ancestor chains; status chips filter All / Conversing / Idle / Needs attention. Deck and Graph share the same live topology draft, so an unsaved rewire is visible in both views immediately. The bottom save bar commits all draft edits as one atomic PUT. - Message composer (v0.8.0) — open a framed conversation with any bot from
its inspector:
talk(bot → a peer; when it has several peers, pick the recipient — validated server-side against the peer list, so edges can't be faked),delegate(orchestrator → bot; the receiving bot splits work downward itself per the initiative ladder),supervisor(bot → its supervisor). Recipients resolve server-side from the live graph; empty text and unknown frames are refused (422). UI sends queue the recipient's Bot Chat turn asynchronously and always retain a durable inbox audit copy; a failed live start is reported explicitly rather than faked as completion. - Live activity — status dot per bot (
complete/ in-progress /interrupted) from its latest session, plus gateway-event pulses while a bot is actively working. Completed gateway turns invalidate the selected transcript immediately; the tail drawer still polls every 4 s as a fallback. - Built-in profile deletion sync — the Hermes Bots/Profiles inventory is authoritative. If a profile is deleted there, the next overview refresh removes its graph node, hierarchy edges, supervisor/attach/start-from options, and deck card. Existing reports are retained and become roots; stale open-tab saves cannot resurrect the deleted profile.
- Inbox read-state — unread badges computed against a per-profile watermark; click a badge or "Mark all read" to clear. New messages after marking correctly re-light the badge.
- Rewire inline — change supervisors, attach/detach reports, add/remove peer relations; draft edits save atomically via one PUT. In Configure, remove from hierarchy removes a leaf/root graph node while retaining its profile folder for later adoption or manual reattachment; members with first, and demote to root remains available through the supervisor picker.
- Create and adopt members — full dialog mirroring Bots "New Agent":
SOUL.md, description, model, skills + toolsets at birth. New members can
clone any existing Hermes profile from the canonical profile inventory;
cloning passes
clone_fromthroughprofiles.createso the source config, skills, and persona are copied by Hermes itself. If a profile already exists but is not wired into Fleetgraph, Adopt & wire in attaches it without recreating it and applies only the explicit edits made in the dialog. - Import existing profiles — the create dialog can explicitly scan the configured Hermes profiles directory, seed lightweight metadata from each SOUL.md, and wire selected unregistered profiles into the graph. Aliases, collisions, reserved directories, and unknown names are handled without overwriting existing nodes.
- SOUL editing — per-bot SOUL.md editor (default profile protected).
- Semantic routing —
GET /api/plugins/fleet-graph/match?q=<task>&top=Nranks the fleet by capability similarity (local fastembed embeddings, zero API cost).GET /rosterexposes every bot's derived capability doc (title/summary/keywords/toolsets from profile.yaml + SOUL.md + config). - Fleet workflows — Review advisor shows bounded coarse local signals and review-only recommendations; Build hierarchy previews a validated graph diff, then requires a separate Approve & apply hierarchy action. Neither workflow sends raw transcripts or credentials, and neither creates profiles automatically.
- Discussion glow — edges between bots that exchanged inbox messages in
the last 5 minutes animate with flowing accent dashes (
/trafficfeed, polled every 5 s), in both graph and tree views.
The plugin's prompt section tells each agent where it sits in the chain and
gives it a 6-step initiative ladder: report done → escalate after >15 min
blocked → hand off out-of-domain requests upward with /match evidence →
route info/action needs by roster owner → update peers on urgent needs →
otherwise stay silent.
- Profile deletion does not prune inboxes or read watermarks — graph nodes, hierarchy edges, and relation choices are reconciled automatically; stale inbox/watermark files remain for manual retention or cleanup.
- Concurrent graph PUTs are serialized by a cross-process file lock and
merge over the stored topology: nodes absent from the payload keep
their state, removals require an explicit
remove: [name]list, andsupervisor: nullexplicitly clears (demote to root). A stale client can no longer wipe nodes, and external scripts no longer need a re-GET dance — though re-GET before write is still good hygiene. - Backend edits (
plugin_api.py) require an app restart; only the desktop frontend hot-reloads. The serve backend's port can change across restarts — resolve it from the process, don't hardcode it. - SDK popup/portal components resolve the desktop app's
--color-*token namespace; plugin-owned canvas and text styles resolve--ui-*. Custom host themes must expose both namespaces, as the desktop does. - Semantic-match quality tracks SOUL.md specificity; canvas perf tested to 23–26 nodes (~700ms mount), untested beyond.
/sendframes are an enum (talk/delegate/supervisor); the recipient for talk must be one of the target's declared peers.
Fleetgraph is a unified Hermes plugin package with two runtime pieces:
- Python dashboard backend:
dashboard/manifest.json+dashboard/plugin_api.py. - Raw ESM desktop UI:
desktop-plugin/plugin.js.
The runtime package is already supplied by Hermes. Plugin users do not need
Node, npm, npm ci, pytest, Ruff, ty, or a development Python environment.
Do not install tests/ dependencies.
Use Hermes to install the plugin instead of copying an archive by hand. This keeps the plugin under the correct Hermes home, runs Hermes' install-time security scan, records the source/revision, and enables the backend explicitly.
# Pin the verified Fleetgraph v0.8.0 tree for reproducible installation.
FLEET_GRAPH_REF="52a288a"
hermes plugins install asmodaydoescoding/fleetgraph \\
--ref "$FLEET_GRAPH_REF" \\
--enable
HERMES_HOME="${HERMES_HOME:-$HOME/.hermes}"
PLUGIN_DIR="$HERMES_HOME/plugins/fleet-graph"
# Fail closed if the repository was installed at the wrong level.
test -f "$PLUGIN_DIR/plugin.yaml"
test -f "$PLUGIN_DIR/dashboard/manifest.json"
test -f "$PLUGIN_DIR/dashboard/plugin_api.py"
test -f "$PLUGIN_DIR/desktop-plugin/plugin.js"
DESKTOP_DIR="${HERMES_HOME}/desktop-plugins/fleet-graph"
mkdir -p "$DESKTOP_DIR"
ln -sfn "$PLUGIN_DIR/desktop-plugin/plugin.js" "$DESKTOP_DIR/plugin.js"
hermes plugins list --user --enabled --plainThe desktop-plugin/plugin.js symlink is intentional: this release stores its
UI entry under desktop-plugin/, while Hermes' standalone desktop loader
expects $HERMES_HOME/desktop-plugins/<id>/plugin.js. Do not copy the entire
repository into $HERMES_HOME/desktop-plugins/; that produces the wrong
layout. The symlink is safe to repeat.
If installing the moving branch instead of the verified tree, omit --ref:
hermes plugins install asmodaydoescoding/fleetgraph --enableIf an agent has only a downloaded Fleetgraph archive, extract it first and set
SOURCE_DIR to the directory that directly contains plugin.yaml and
dashboard/manifest.json (GitHub source archives normally add one outer
fleetgraph-<ref>/ directory). Then run:
HERMES_HOME="${HERMES_HOME:-$HOME/.hermes}"
PLUGIN_DIR="$HERMES_HOME/plugins/fleet-graph"
mkdir -p "$PLUGIN_DIR"
cp -a "$SOURCE_DIR/." "$PLUGIN_DIR/"
hermes plugins enable fleet-graph
mkdir -p "$HERMES_HOME/desktop-plugins/fleet-graph"
ln -sfn "$PLUGIN_DIR/desktop-plugin/plugin.js" \\
"$HERMES_HOME/desktop-plugins/fleet-graph/plugin.js"Verify the same four test -f checks from the preferred install before
starting Hermes. Do not point Hermes at the outer archive directory.
- In Hermes Desktop, run Reload desktop plugins from the command palette.
- If Fleetgraph reports that routes are not mounted, click Remount routes. Hermes with route-remount protocol v1 applies the change without a backend restart.
- On older Hermes versions without that RPC, restart the dashboard once (for
example
systemctl --user restart hermes-dashboard.serviceon Linux), then press Retry.
Backend enablement and desktop loading are separate gates: plugins.enabled
allows the Python API to import, while the desktop reload loads the raw UI
entry. Both are required for the full plugin.
Fresh installs start with an empty topology. Discovered profiles appear as unassigned until the operator wires them; no developer fleet names or peer relations are seeded.
The release includes the inert starter-packs/starfleet-complement/ pack. It
is optional and never installs profiles silently. Preview its manifest,
license, attribution, profile names, and topology first; selected new profiles
must be created through Hermes profiles.create with an explicit clone_from,
while profiles already present are adopted and wired rather than recreated.
The pack contains no executable installer or arbitrary code.
Two optional Hermes skills ship under skills/:
fleet-bot-advisor— local, coarse activity recommendations using the sequence observe → summarize → recommend → ask → create.fleet-hierarchy-builder— an on-demand draft, graph diff, validation, and explicit apply flow for existing profiles.
Both skills are approval-gated and topology/profile-lifecycle changes are verified by readback.
Operator metadata lives beside the topology in fleet_graph.yaml and is not
returned as a graph node:
_meta:
profile_aliases:
public-node-name: canonical-runtime-profile
root_owner_label: OperatorDeployment and test environments may override the default runtime locations:
| Variable | Purpose |
|---|---|
FLEET_HOME |
Base Hermes/fleet home |
FLEET_GRAPH_PATH |
Topology YAML path |
FLEET_DEFAULT_PROFILE |
Canonical protected/default profile |
FLEET_INBOX_DIR |
Fleet inbox and watermark directory |
FLEET_PROFILES_DIR |
Hermes profiles directory |
FLEET_HERMES_BIN |
Hermes CLI executable |
Read-only access to each profile's state.db (session titles/previews/
status via hermes_state.SessionDB), read/write to:
fleet_graph.yaml— topology, peer relations, and operator metadata~/.hermes/fleet-inbox/— fleet message inbox and.read/watermarksprofiles/<name>/SOUL.md— only when you edit a soul in the UI
No credentials are read, no network calls leave the machine.
| Piece | Path | Role |
|---|---|---|
| UI | desktop-plugins/fleet-graph/plugin.js |
Single-page plugin (Deck/Graph views, inspector, dialogs) |
| Backend | dashboard/plugin_api.py |
FastAPI router mounted at /api/plugins/fleet-graph/ |
| Core | fleet_graph_core.py |
Topology SSOT: load/save/describe/simulate |
| Messaging | fleet_msg.py |
CLI for inter-bot messages (powers the inbox) |
| Tests | tests/public_integration_test.py, tests/ |
Hermetic end-to-end integration suite plus static, configurability, adversarial backend, and nine frontend harnesses |
| Route | Purpose |
|---|---|
GET /overview[?light=1] |
Full paint payload; light=1 skips session DB reads |
GET /graph/summary |
Node/edge counts + status histogram (header strip) |
PUT /graph |
Replace topology + relations from editor drafts |
GET /relations |
Peer map |
GET /inbox/{p} · POST /inbox/{p}/read |
Inbox + watermark mark-read (supports {ts} / {count}) |
GET /soul/{n} · PUT /soul/{n} |
SOUL.md read/write (default profile blocked) |
GET /avatar/{n} |
Profile avatar as data URL |
GET /sessions/tail[?profile=p] |
Per-bot latest-session snapshot |
GET /sessions/{n}/messages?limit= |
Transcript tail for the live drawer |
POST /simulate |
Chain-of-command permission simulation |
GET /traffic?window= |
Recent inter-agent traffic for animated edge glow |
GET /roster · GET /match?q=&top= |
Capability roster and semantic routing |
GET /starter-packs |
List validated optional inert starter packs |
GET /starter-packs/{id} |
Read-only pack preview with adoption/create state |
POST /starter-packs/{id}/selection |
Validate selected profile actions without mutation |
GET /workflows · GET /advisor/preview |
Shipped workflow descriptors and coarse advisor review |
POST /hierarchy/preview |
Validate a staged hierarchy and return a read-only diff |
PUT /hierarchy/apply |
Apply a hierarchy only with explicit confirm: true |
POST /send |
Validated talk / delegate / supervisor delivery; live: true queues recipient Bot Chat while preserving the inbox copy |
GET /profiles/discover |
List unregistered on-disk Hermes profiles with seeded metadata |
POST /profiles/import |
Explicitly wire selected existing profiles into the graph |
Render harnesses (real React + stubbed SDK, drive every UI branch):
cd tests
[ -d node_modules ] || npm ci
node drive-harness.mjs # expect: ALL BRANCHES DRIVEN
node hostile-harness.mjs # expect: ALL HOSTILE BRANCHES DRIVEN
node loop2-harness.mjs # create-dialog guards (6 passed)
node loop5-harness.mjs # optimistic-UI rollback (4 passed)
node loop6-harness.mjs # deck v2 (17 passed)
node loop7-harness.mjs # composer recipient contract (19 passed)
node loop8-harness.mjs # release adversarial/state seams (33 passed)
node render-harness.mjs # full render sweep (ALL BRANCHES DRIVEN)
node boundary-harness.mjs # error boundary (caught + reload present)Integration and backend suites:
python3 tests/public_integration_test.py # hermetic end-to-end suite; expect INTEGRATION SUMMARY with 0 failed
python3 tests/backend_loop8_test.py # expect BACKEND LOOP8 SUMMARY: 23 passed, 0 failed
python3 tests/communication_live_test.py # expect COMMUNICATION LIVE SUMMARY: 12 passed, 0 failed
python3 tests/configurability_test.py # expect CONFIGURABILITY SUMMARY: 21 passed, 0 failedStatic audit (parse, loader-import count, token/key hygiene):
python3 tests/a1_audit.py
# expect: PARSE OK · loader imports: 3 · token/key findings: 0Design tokens live in one block (TOKENS_CSS) at the top of plugin.js,
derived from host theme tokens (semantic color vars, 150 ms fast / 300 ms
medium motion bands). Runtime literals are rejected by the configurability
gate.
- Whether profile deletion should automatically prune topology, inboxes, and read watermarks.
- Whether graph writes should gain optimistic concurrency/ETags instead of the documented last-write-wins contract.
- Whether to optimize or virtualize the graph beyond the verified 26-node range.
The published Hermes Desktop loader uses a syntax-anchored matcher for static, side-effect, and dynamic ESM imports; it is not a full JavaScript parser. Keep module imports limited to the host-supported SDK and React surfaces, and avoid placing import-declaration-shaped examples in plugin comments or strings. Verify after edits:
node --check desktop-plugins/fleet-graph/plugin.js
python3 tests/a1_audit.py
# Expected: PARSE OK, loader imports: 3, token/key findings: 0
