- Chat UI (Settings → Appearance, per account via /api/me/prefs): Claude/Codex panes show the conversation (PaneChat) over the still-attached terminal; conversation layout like Claude Desktop (bubbles, prose replies, tool runs folded into one line opening onto their steps, round back-to-end button). - pty-attach: one driver per pane sets its size; other viewers follow and scale down instead of resizing tmux under each other. - Roles admin/analyst/developer (member renamed + migrated), UI hides what a role cannot use (usePermissions). - Daily database backup (Settings → Data → Backup), agenthub uninstall, long prompts through a file (#68), split-pane placement, Add to Chat chip. Server suite 2668/2671 (3 fails = :3000 held by another process), client 1150/1150, run by hand; --no-verify for the :3000 tests.
49 KiB
AgentHub — Plugin Marketplace
Official Claude Code plugins for the Agent Monitor dashboard. The agenthub plugin is the dashboard — hooks, server and the agenthub CLI, no checkout required. (It ships a small read-only MCP server again — agenthub mcp, see MCP.md — but does not register it: run claude mcp add agenthub -- agenthub mcp to opt in. The same goes for the statusline, agenthub statusline install, see STATUSLINE.md.) On top of it, 10 focused plugins extend Claude Code with skills, agents, slash commands, hooks, and CLI tools for deep analytics, cost guardrails, productivity automation, developer tools, AI-powered insights, session forensics, workflow/fleet intelligence, reliability & SLOs, config & memory governance, and dashboard connectivity.
Every plugin is powered by the local Agent Monitor REST API at http://localhost:4820. They are read-only advisors unless a skill explicitly documents a mutating endpoint (and those preview + confirm before acting).
Quick Start
Add the marketplace
claude plugin marketplace add https://git.smartgift.io.vn/Smartgift-AI/AgentHub.git
Install the dashboard itself
claude plugin install agenthub@agenthub
That is the whole install: no clone, no npm run setup, no npm run install-hooks, no manual npm start. See The agenthub plugin below for what it does on first session start.
Or via the Smartgift skills marketplace
agenthub is also listed as a standalone entry in
smartgift-claude-skills
— its source still points at this repo's main branch, so the two entries
install identically:
claude plugin marketplace add https://git.smartgift.io.vn/Smartgift-AI/smartgift-claude-skills.git
claude plugin install agenthub@sg
Pick whichever marketplace you already have added; installing agenthub from both
at once is redundant but harmless (Claude Code treats it as one plugin per
marketplace name, not per source).
Install a focused plugin
claude plugin install agenthub-analytics@agenthub
claude plugin install agenthub-cost-guard@agenthub
claude plugin install agenthub-productivity@agenthub
claude plugin install agenthub-devtools@agenthub
claude plugin install agenthub-insights@agenthub
claude plugin install agenthub-sessions@agenthub
claude plugin install agenthub-workflows@agenthub
claude plugin install agenthub-quality@agenthub
claude plugin install agenthub-config@agenthub
claude plugin install agenthub-dashboard@agenthub
Or install locally during development
# From the repo root, test a plugin locally
claude --plugin-dir plugins/agenthub-analytics
Prerequisites
- Claude Code installed and authenticated
- Node >= 22.5 when installing via the
agenthubplugin. A plugin install has no nativebetter-sqlite3, so the server stores data throughnode:sqlite, which landed in 22.5. The bootstrap refuses with one line on anything older instead of letting the server crash. (A checkout install still works on Node >= 20.) - The Agent Monitor dashboard reachable at
http://localhost:4820— theagenthubplugin starts it for you; a checkout starts it withnpm start(see SETUP.md)
Skills and commands are invoked as /agenthub-<plugin>:<name>. Agents are dispatched automatically by Claude Code (or named explicitly).
The agenthub plugin
The marketplace's root entry ("source": "./") is the entire repository, so
server/, client/, scripts/ and bin/agenthub.js all land under
${CLAUDE_PLUGIN_ROOT} when Claude Code caches it. That is what makes a
checkout unnecessary.
What it installs
| Component | Where it comes from |
|---|---|
| The eight event hooks | inline hooks in .claude-plugin/plugin.json, each running scripts/hook-handler.js |
| The dashboard server | started detached by the bootstrap, from the plugin cache |
The agenthub CLI |
a launcher written to ~/.local/bin/agenthub |
The dashboard UI (/run and every other client route) |
built into the runtime dir by the bootstrap, so it works the moment claude starts |
/agenthub-doctor, /agenthub-update, /agenthub-open |
plugins/agenthub/commands/ |
The skills (update-project-docs, file-headers) |
skills/ at the repo root — which IS the plugin root, so they are auto-discovered as plugin skills |
Plugin skills are namespaced: they are invoked as /agenthub:<name>, with the bare
/<name> working as an alias unless another skill or command claims that name.
This is why skills/ sits at the repo root instead of .claude/skills/ — the
latter only loads for a session whose cwd is inside this checkout, which is
useless for a workspace working in a different repo.
That is the whole plugin: the hooks, the CLI, the dashboard, three commands and
four skills. It ships no subagents and no pipeline template, and it neither
depends on nor installs any other plugin (Superpowers included). The pipeline
slash commands, the ship-feature / ship-feature-lane skills and the
qc-local / senior-gate-reviewer / backend-reviewer / frontend-reviewer
agents were removed; the stage/pipeline machinery they drove stays in the
dashboard, dormant until you install a template (see docs/LANES.md §
"Pipeline stages and the five node states").
Because the plugin ships the hooks itself, npm run install-hooks is not needed
for plugin users — and must not be run alongside it. Events carry no id, so two
handlers mean every token and cost figure is counted twice. claude plugin install writes the plugin's own hook entries into ~/.claude/settings.json
too (${CLAUDE_PLUGIN_ROOT} resolved to the actual cache path) — confirmed
against a real install — so those entries also contain hook-handler.js, same
as a leftover checkout install. The bootstrap tells them apart by whether the
command resolves under ~/.claude/plugins/cache/: only genuine checkout paths
are removed (backing ~/.claude/settings.json up as settings.json.agenthub-bak
first), never the plugin's own. /agenthub-doctor reports the state using the same
check.
First session start
scripts/plugin-bootstrap.js runs from SessionStart. It returns within
milliseconds — the real work happens in a detached worker, so a session never
waits on an install:
- Fast path — recorded state matches this plugin build and a server is live → exit. "Live" means a discovery entry whose pid answers AND whose
startedAtis after this boot (60 s margin): an entry left over from before a reboot names a pid the OS may have handed to an unrelated process, and without systemd (macOS) nothing else clears it. - Superseded check — if Claude Code records a DIFFERENT build of this plugin as installed, this one logs a line and does nothing else (see A retired build never acts).
- Node gate — refuse below 22.5 with one line (see Prerequisites).
- Lock — atomic
mkdirlock holding the PID; reclaimed when the owner is dead or the lock is older than 10 minutes, so two sessions cannot race the install or spawn two servers. - Install —
npm install --omit=dev --ignore-scriptsinto the runtime dir, run as the npm bundled with the node running the bootstrap (npmCommand: itsnpm-cli.jsbesideprocess.execPath, no shell, that node's directory first on PATH;npmon PATH only when that node ships none) — the update chain runs with the dashboard server's environment, whose PATH need not reachnpm.cmdon Windows. The UI build below and the doctor's npm row use the same npm (never into the plugin cache, which is garbage-collected and replaced on every update).--ignore-scriptskeeps the rootpostinstallfrom pulling the whole Vite client toolchain. - Legacy hook cleanup — see above.
- CLI — write the
~/.local/bin/agenthublauncher, never clobbering aagenthubthe bootstrap did not write. It pins the node that ran the bootstrap and falls back tonodeonPATHwhen that binary is gone (a Homebrew Cellar or nvm path deleted by an upgrade). - UI build —
client/is copied into the runtime dir and built there (npm ci --include=dev --ignore-scripts, falling back tonpm installwith the same flags, thentsc -bandvite buildrun by the bootstrap's ownnode— the client'sbuildscript withoutnpm run), landing inruntime/client-dist— the same directory the server serves from. Nothing in it looksnodeup on PATH: on Windows an install script or a.bin/*.cmdshim runs through cmd.exe, and the server's PATH may have nonode(esbuild's postinstall failed there with "'node' is not recognized" and the update kept the old UI); esbuild, the only dependency with an install script, finds its binary without it.--include=devis required, not tidy: the entire build toolchain (vite,typescript,@vitejs/plugin-react,tailwindcss,@types/*) is a devDependency, and npm reads an inheritedNODE_ENV=productionas--omit=dev. Every bootstrap descended from the running server carries that env — the self-update chain, and anySessionStartfired by aclaudeinside a tmux pane the server started — so without the flag the install dropsviteand the build dies on missing types. Skipped when a bundle for the current version already exists; a failure here does not fail the bootstrap (the API still works, and/agenthub-opencan retry) but does mean/run404s until it's fixed — and when a bundle from the PREVIOUS version is still on disk the failure is quieter still: the dashboard keeps serving the old UI against the new API, visible only as the Settings page'sUI build vX (rebuild client to match)line. - Server — when the user has turned Start AgentHub automatically on
(Settings → System; OFF by default), install/refresh the
agenthub.serviceunit on Linux — on macOS with a GUI login, theio.smartgift.agenthubLaunchAgent (see Auto-start on boot) — instead of a bare spawn, so the server is supervised and comes back after a reboot with no Claude Code session involved. Everywhere else (Windows, no systemd, a Mac reached only over SSH), spawnserver/index.jsdetached, withNODE_PATHat the runtimenode_modulesandDASHBOARD_CLIENT_DISTat the runtimeclient-dist— scoped to this session, same as before this fell back to systemd. - Record state —
runtime/state.json. - Prune retired cache copies — delete the plugin-cache directories earlier updates left behind (see Pruning the plugin cache). After step 10, so a prune that goes wrong cannot also cost the record of a bootstrap that went right.
- Hand over to systemd — only when a unit of ours already owns the server (see Who may stop the server). Deliberately after step 10.
The first run takes a few minutes — most of it is the UI build, which is what
makes client-only routes (http://localhost:4820/run, and every other page)
work the moment claude starts, with no manual /agenthub-open step. Progress
goes to ~/.claude/agenthub/runtime/bootstrap.log; the UI build's own
output goes to client-build.log next to it; the server's own output goes to
server.log.
A retired build never acts
claude plugin update unpacks the new version into a new cache directory
and prints "Restart to apply changes". A Claude Code process that was already
running does not: it keeps loading the OLD directory — skills, commands and
hooks included — until it is restarted.
That used to be self-inflicting. Every session such a process opened ran the
OLD plugin-bootstrap.js, which saw a state.json naming a different root,
concluded the server had to be replaced, repointed agenthub.service at itself
and restarted the dashboard onto the version the user had just upgraded away
from. The dashboard then reported the old version and offered the update again
— once per session, forever, while installed_plugins.json and the cache both
said the new version was installed. A /agenthub-update from that session
"succeeded" and changed nothing.
So the bootstrap now asks first (supersededBy): if Claude Code's
~/.claude/plugins/installed_plugins.json records a sibling directory as
the installed build of this plugin, this build logs one line and returns
superseded without touching dependencies, the unit, or the server. --force
does not override it — the self-update chain and /agenthub-update run
--force from the NEW directory, which is never superseded, so the only --force this can refuse is
one that would deliberately downgrade.
It cannot hand over to the new build either: the process it would have to replace is the one loading it. Restarting Claude Code is the fix, and the log line says so.
Matching is by sibling directory rather than by the <plugin>@<marketplace>
key, which holds without parsing a cache path or trusting a name. An entry
pointing at a directory that no longer exists is ignored — a phantom must never
wedge a bootstrap shut.
A build installed while the server kept running
The same record answers the opposite case. claude plugin update run from a
terminal (or with only the Claude desktop app open) starts nothing: no
SessionStart fires, so no bootstrap hands the server over, and the dashboard
keeps running the old directory — across reboots too, since
agenthub.service still names it and it still exists. agenthub open only
opens the browser.
So getUpdatesStatus (server/lib/update-check.js) asks supersededBy for
its own root: when a sibling build is the installed one, the status carries
installed_not_running: {root, version} and update_available: true — with
no network needed, so an unreachable forge can no longer hide it. The sidebar
reads <version> installed, not running, and the update modal's Update
now runs the usual chain; scripts/plugin-update-helper.js hands over to the
recorded install first (supersededBy(oldRoot)), falling back to the newest
sibling directory only when there is no record.
Separately, a plugin install whose release lookup failed (release_check not
ok) now reads Could not check for updates in the connection details modal (opened from the status bar) instead of
Up to date — a plugin install has no commit count to fall back on.
To hand over by hand without the dashboard:
node "$(python3 -c 'import json,os;d=json.load(open(os.path.expanduser("~/.claude/plugins/installed_plugins.json")));print([e["installPath"] for k,v in d["plugins"].items() if k.startswith("agenthub@") for e in v][0])')/scripts/plugin-bootstrap.js" --force
Pruning the plugin cache
Claude Code unpacks every update beside the last one and does not reliably
remove the old. A machine that tracks releases closely accumulates a full copy
of this repo — node_modules and all — per release; a dozen of them is
gigabytes.
Step 11 of the bootstrap (pruneRetiredPluginRoots) deletes them. This is the
only place anything in the plugin touches the cache, and the rule it appears to
break ("never write into the plugin cache") is about the runtime living
outside it, not about keeping retired copies forever.
Four independent readings of "still in use" are protected, and nothing matching any of them is ever deleted:
| Protected | Why |
|---|---|
| This build | It is running. |
Every installPath in installed_plugins.json, at any scope |
Claude Code says it is installed. |
The directory agenthub.service names (unitRoot, foreign unit included) |
A service is executing from it. Not ours to rewrite is still not ours to delete. |
Any directory named in the user's settings.json hooks |
A Claude Code process that has not been restarted is still executing from there — this is the same directory the section above describes, seen from the other side. Deleting it would break that session's hooks mid-flight. |
Plus the newest KEEP_RETIRED_ROOTS (1) of whatever is left, as a rollback
cushion — one build deep, because a full copy of this repo is ~130 MB. Outside ~/.claude/plugins/cache/ the pruner does nothing at all — for
a git checkout the parent directory holds the user's own work. Best effort
throughout: a directory that will not delete is left alone, never an error.
Quit
Settings → System → Quit AgentHub or agenthub stop (issue #65,
server/lib/quit.js, POST /api/settings/quit) closes every workspace
terminal and stops the server, through the service manager when the unit runs
it. It writes <data dir>/runtime/stopped first: while that file exists
fastPathOk is true with no server and the worker starts none (--force, i.e.
/agenthub-update, overrides it; a stale unit is still repaired, not started).
Any server that starts clears it — agenthub start, which in a plugin install
runs this bootstrap, or a boot/login through an enabled autostart unit — so
autostart keeps working across a reboot.
Status-area icon
Like 9router's, AgentHub puts an icon beside the clock — GNOME's top bar, the
macOS menu bar, the Windows notification area (server/lib/tray.js,
scripts/tray.js). It is its own process, drawn by the systray2 package's
helper binary (installed with the other runtime dependencies), so a server
restart or a Quit never takes it away: after a Quit its Start AgentHub is
the way back. A production server starts it once it is listening and checks
every minute (a Linux server started at boot has no DISPLAY until someone
logs in; three quick deaths in a row and that server stops trying). It is on by
default; Hide this icon in its menu and Settings → System → Show AgentHub
icon in the status area write <data dir>/runtime/tray-off, and only that
switch removes it again. One icon per data dir: <data dir>/runtime/tray.json
holds its pid and install root and is touched every 5 s as a heartbeat — a
stale file is never trusted, so a pid reused after a reboot is never
signalled. A server replaces an icon from another install root (the previous
plugin build) once at start. Never in server mode, nor from a development
server. The icon starts at login only when the dashboard does (start at login
below); there is no separate autostart entry. Verified on Ubuntu GNOME (X11);
on macOS systray2 ships only an x86_64 helper (Apple Silicon runs it through
Rosetta 2, else no icon appears), and Windows is untested.
Auto-start on boot
Opt-in, and off by default: Settings → System → Start AgentHub automatically
(GET/PUT /api/settings/autostart, server/lib/autostart.js). The switch IS
the unit's enabled state — on writes a unit for the running server when none
exists and enables it, off disables it; neither starts or stops the server. A
bootstrap only installs or starts a unit that is enabled, never changes that
state (writeUserService({ enable }) keeps it on a rewrite), and with it off
the server is the detached spawn below. An install that already had the unit
enabled before this switch existed keeps it on.
While it is on, every plugin bootstrap (not just the first) installs/refreshes a
systemd --user service (~/.config/systemd/user/agenthub.service, managed via
scripts/systemd-service.js — shared with the checkout path's
agenthub service install, see the README). Its ExecStart/WorkingDirectory
point at the current plugin cache path, so a plugin update that moves the
cache directory rewrites and restarts the unit on the next session start, the
same self-healing pattern the CLI launcher already uses. The bootstrap also
tries loginctl enable-linger so the service starts on a cold boot before
anyone logs in; when that needs elevated rights, it's skipped silently (check
~/.claude/agenthub/runtime/bootstrap.log, or run
sudo loginctl enable-linger <user> once by hand). A pre-existing
agenthub.service unit not written by this bootstrap is left untouched, and the
server falls back to the old per-session detached spawn instead.
On macOS the same steps write a LaunchAgent instead
(~/Library/LaunchAgents/io.smartgift.agenthub.plist, scripts/launchd-service.js;
scripts/service-manager.js picks the one for the platform, and both export the
same API). KeepAlive plays Restart=always, AbandonProcessGroup keeps the
workspace panes' tmux server alive across a restart, output goes to
~/Library/Logs/agenthub.log, and the hand-over restart is launchctl bootout
bootstrap(akickstartwould keep the old plist). If that bootstrap fails and no server is left running, the bootstrap starts one detached. A LaunchAgent needs the user's GUI login; without one (SSH only)launchctl print gui/<uid>fails and the server falls back to the detached spawn below.
On Windows, a Linux box without systemd, or a Mac with no GUI login, the
server is a detached spawn started fresh on the next SessionStart after a
reboot, same as always. That spawn inherits the Claude Code session's env, so
server/index.js deletes the parent-session variables (CLAUDECODE,
CLAUDE_CODE_SESSION_ID, CLAUDE_CODE_MESSAGING_*, CLAUDE_PLUGIN_ROOT, …)
before anything else runs — otherwise tmux hands them to every workspace pane. It is
a denylist: user configuration such as CLAUDE_CONFIG_DIR,
CLAUDE_CODE_USE_BEDROCK and ANTHROPIC_* passes through. See
INSTALL.md § macOS.
Who may stop the server
When a agenthub.service unit of ours exists, nothing else may stop the
dashboard. The bootstrap that performs a self-update is spawned by the
running server, so it lives inside that server's systemd cgroup. SIGTERM-ing
the server from there breaks two ways at once:
- the server exits 0, and the unit's old
Restart=on-failureread a clean exit as "meant to stop" — so systemd did not bring it back; KillMode=control-group(systemd's default) reaps every process in the cgroup when the main process exits, including the bootstrap itself — mid-run, before it could repoint the unit at the new plugin root or writeruntime/state.json.
The result was a dashboard that went down on every self-update and stayed down
until some later Claude Code session happened to bootstrap again, leaving a
stale .bootstrap.lock and a state.json still naming the previous version.
So the order is fixed, and scripts/systemd-service.js splits its API to
enforce it:
| Situation | What the bootstrap does |
|---|---|
A unit of ours owns the server (unitIsOurs) |
Never stops it. writeUserService repoints the unit at the new plugin root without starting anything, the rest of the bootstrap runs, state is written, the lock is released — and only then restartUserService asks systemd to restart, with --no-block so being killed by its own request costs nothing. |
| No unit, or a foreign one | Unchanged: stop the old server, then installUserService (or a detached spawn where there is no systemd). Nothing here is inside a unit's cgroup, so the stop is safe. |
The unit is written with Restart=always, not on-failure: a graceful
SIGTERM from anything at all would otherwise leave the dashboard down for good.
An explicit systemctl stop — which is what agenthub service uninstall and
the Settings panel do — still stops it.
The unit also sets KillMode=process: a stop or an update's restart ends
the server process alone. tmux forks its server from whichever process first
asks for a session — the dashboard itself after a boot with autostart on — so
it can live in the unit's cgroup, and control-group would kill it and every
lane pane on each update. An update never closes a pane; only Quit does
(it kills the agenthub-lane-* sessions itself). Existing units pick this up
when the next update rewrites them; a checkout's unit on agenthub service install. The launchd twin is AbandonProcessGroup.
Belt and braces on Linux: the session that STARTS the tmux server (no server
running yet) is created through systemd-run --user --scope
(server/lib/tmux.js), so the server lives in a transient scope of its own —
not in agenthub.service, and not in the terminal or IDE scope a dev server
was started from. Stopping either, systemd-oomd reaping either, or an old unit
still on control-group leaves the panes alone. With no user manager to ask
(SSH without linger, no systemd) it falls back to a plain start. On macOS tmux
daemonizes into its own session and the plist abandons its process group. On
Windows (psmux) whether the server outlives the dashboard has not been
verified yet.
agenthub service install (the checkout path) keeps using installUserService:
it runs from your own shell, outside the unit's cgroup, so it may block and
start in one step.
A unit pointing at a retired plugin root repairs itself on the next session.
This is the residue an interrupted update leaves behind, and it is invisible
while the dashboard is up: the server runs fine, every doctor row reads OK, and
then a reboot starts a cache directory Claude Code deleted during the update —
so the dashboard never comes back, for a reason nothing recorded. The fast path
therefore checks it (unitIsStale, pure fs — it may not spawn a process on
every SessionStart) and refuses to short-circuit, and the bootstrap rewrites
the unit.
Repairing the unit is not restarting the server: when the running server is
current and healthy, the corrected unit is simply left to take effect at the
next start (pendingSystemdRestart = systemdOwned && needsServer). Restarting
a working dashboard to fix a file that only matters at boot would be churn the
user feels for nothing. For the same reason the detached-spawn fallback is
guarded by needsServer — entering that branch for a stale unit alone would
start a second server onto a port the live one already holds.
systemdOwned requires the unit to be active, not merely present: an
installed-but-stopped unit owns nothing, and treating it as the owner would
skip the stop and then ask systemd to bind an occupied port — a crash loop,
courtesy of Restart=always.
Commands
| Command | Does |
|---|---|
/agenthub-doctor |
Node version, bootstrap state, runtime deps, server liveness, duplicate hooks, CLI launcher + PATH, systemd (WARN when the unit names a retired plugin root — the dashboard will not survive a reboot — or when it is installed but stopped; no unit at all is fine), tmux (WARN when absent — only the run console, agenthub workspace shell and session reloads need it), UI bundle. On any FAIL/WARN it asks whether to fix them, then lists the exact steps (one plugin-bootstrap.js --force from the installed build for deps/server/hooks/CLI launcher/stale unit, Node ≥ 22.5 through the user's version manager, the tmux package, the PATH line, …) and runs them only after a second yes; disk, a foreign unit, tmux built from source and an older running tmux server are reported, never touched. plugin-doctor.js itself stays read-only |
/agenthub-update |
Pull the latest agenthub release via claude plugin marketplace update + claude plugin update agenthub@<marketplace> -y, then reinstall dependencies and restart the server with plugin-bootstrap.js --force run from the build that is INSTALLED now (supersededBy() of this session's root, else that root — the old root's bootstrap would refuse as superseded), and run the doctor. The dashboard is on the new version at once; only this session's own commands and skills wait for /reload-plugins or a new session. |
/agenthub-open |
Rebuild the UI bundle and print the dashboard URL. Re-runs the bootstrap first when the server is down or still executing a plugin root that a mid-session /plugin update retired, so a fresh bundle never talks to an older server's routes. plugin-open.js exits 1 when the build fails or that bootstrap does not answer ok, and the command then runs the /agenthub-doctor flow and retries the build once after the approved fixes |
Where things live
| Thing | Location | Survives a plugin update |
|---|---|---|
| SQLite DB, transcripts | ~/.claude/agenthub/ |
yes |
node_modules, client-dist, logs, lock, state.json |
~/.claude/agenthub/runtime/ |
yes (re-verified on every session start) |
| Source, hooks | the plugin cache version directory | no — re-bootstrapped |
The bootstrap deliberately does not set DASHBOARD_DATA_DIR: leaving the
default keeps a plugin-run server and a developer's npm run dev server on one
data directory, where ingestGroupKey already deduplicates hook ingest to a
single port.
Settings the dashboard saves (CLAUDE_HOME, CODEX_HOME, and the data dir that a
CLAUDE_HOME change pins) go to ~/.config/agenthub/settings.env
($XDG_CONFIG_HOME/agenthub/settings.env, or AGENTHUB_SETTINGS_FILE), never
to a .env inside the plugin cache, which every update replaces. The server
reads it at startup. Precedence is real environment, then the checkout's own
.env, then that file — a dev checkout whose .env names its own
DASHBOARD_DATA_DIR must not be pointed at the live database by a pin saved
from the plugin dashboard. A variable the real environment or that .env sets
(a systemd unit's Environment=, say) wins at every start, and the settings
page warns about it.
Uninstalling
Run agenthub uninstall --yes (or Settings → System → Uninstall AgentHub):
it does everything below, and more, in the right order — see
CLI.md for the exact list and what it keeps. Without --yes it only
lists what it would remove. The rest of this section is what that command
automates, for a machine where the CLI no longer runs.
claude plugin uninstall agenthub@agenthub only removes
the plugin from the enabled list — verified against a real install/uninstall,
not assumed. It does not:
- stop the running server (it keeps serving from the now-uninstalled cache dir)
- disable or remove the
agenthub.servicesystemd--userunit (Linux) — it will keep restarting the old server on every reboot, sincesystemctlknows nothing aboutclaude plugin uninstall - remove the cached source under
~/.claude/plugins/cache/.../agenthub/<version>/ - remove the hook entries
claude plugin installwrote into~/.claude/settings.json(still pointing at that cache dir — they keep firing, and keep working, until the cache directory is eventually GC'd by Claude Code, at which point they silently start failing) - remove
~/.local/bin/agenthubor~/.claude/agenthub/runtime/
For a clean machine, do all of this yourself:
# 1. Stop the server. On Linux, disable the systemd unit FIRST — the unit is
# Restart=always, so a bare `kill` is always undone by systemd.
systemctl --user disable --now agenthub.service 2>/dev/null
rm -f ~/.config/systemd/user/agenthub.service && systemctl --user daemon-reload 2>/dev/null
# Fallback for a detached (non-systemd) server, or if the unit above was absent:
kill "$(node -e 'console.log(JSON.parse(require("fs").readFileSync(require("os").homedir()+"/.claude/.agenthub.json","utf8")).pid)')" 2>/dev/null
# 2. Runtime state and the CLI launcher
rm -rf ~/.claude/agenthub/runtime # deps, UI bundle, logs, state
rm -f ~/.local/bin/agenthub
# 3. The hook entries claude plugin install wrote (settings.json is not
# ours to fully own — back it up first and only drop entries mentioning
# hook-handler.js)
node -e '
const fs = require("fs");
const p = require("os").homedir() + "/.claude/settings.json";
const d = JSON.parse(fs.readFileSync(p, "utf8"));
fs.copyFileSync(p, p + ".agenthub-bak2");
for (const [type, entries] of Object.entries(d.hooks || {})) {
const kept = entries.filter((e) => !JSON.stringify(e).includes("hook-handler.js"));
if (kept.length) d.hooks[type] = kept; else delete d.hooks[type];
}
fs.writeFileSync(p, JSON.stringify(d, null, 2) + "\n");
'
~/.claude/agenthub/ still holds the SQLite database after all of the
above — delete that directory too only if you want the recorded history gone.
Available Plugins
1. agenthub-analytics — Analytics & Monitoring
Deep analytics on sessions, token usage, costs, cache efficiency, model mix, and productivity.
| Skill | Command | Purpose |
|---|---|---|
| Session Report | /agenthub-analytics:session-report |
Per-model tokens (input/output/cache_read/cache_write + baselines), cost, agent hierarchy, tool activity, timeline |
| Cost Breakdown | /agenthub-analytics:cost-breakdown |
Per-model cost via the pricing engine, daily trends, cache efficiency, optimization opportunities |
| Usage Trends | /agenthub-analytics:usage-trends |
365-day session/event trends, token volume, tool rankings, model distribution, event-type ratios |
| Productivity Score | /agenthub-analytics:productivity-score |
Weighted scorecard: completion, token efficiency, tool effectiveness, velocity, cost efficiency |
| Cache Efficiency | /agenthub-analytics:cache-efficiency |
Cache hit rate, write-vs-read reuse, sessions with poor cache reuse |
| Model Mix | /agenthub-analytics:model-mix |
Share of tokens and cost per model family; expensive models doing cheap work |
Commands: /agenthub-analytics:cost-today · /agenthub-analytics:top-spenders · /agenthub-analytics:burn-rate
Agents: analytics-advisor (full advisor incl. workflow intelligence) · token-economist (token economics & reduction tactics)
Hooks: Logs Stop / SubagentStop events. CLI: agenthub-stats — terminal stats (sessions, cost, tokens).
2. agenthub-cost-guard — Budget Guardrails
Spend limits, forecasting, cost alerts, and model-routing savings.
| Skill | Command | Purpose |
|---|---|---|
| Budget Set | /agenthub-cost-guard:budget-set |
Define a budget and (optionally) arm a token_threshold alert rule; explains the $→token conversion |
| Spend Forecast | /agenthub-cost-guard:spend-forecast |
Project week/month-end spend from the daily trend (moving average × remaining days) |
| Cost Alert | /agenthub-cost-guard:cost-alert |
Review alert rules and fired alerts; explain exactly what tripped |
| Model Savings | /agenthub-cost-guard:model-savings |
Estimate $ saved by routing eligible work to a cheaper model family |
| Daily Budget Check | /agenthub-cost-guard:daily-budget-check |
Today's spend vs a daily budget, pace vs target, projected overage |
Commands: /agenthub-cost-guard:budget · /agenthub-cost-guard:forecast · /agenthub-cost-guard:overspend
Agent: budget-sentinel — watches spend vs target, projects month-end, recommends cuts. Hooks: fail-safe Stop event POST so budget tracking sees session ends.
3. agenthub-productivity — Productivity & Workflows
Standups, weekly/monthly reviews, sprint tracking, focus analysis, and workflow optimization.
| Skill | Command | Purpose |
|---|---|---|
| Daily Standup | /agenthub-productivity:daily-standup |
Standup from recent sessions — work by project (cwd), costs, tools, errors, velocity |
| Weekly Report | /agenthub-productivity:weekly-report |
Daily session/event trends, per-session costs, token volumes, tool top-20, completion rates |
| Sprint Summary | /agenthub-productivity:sprint-summary |
Per-project + per-model costs, token efficiency, subagent effectiveness, retrospective data |
| Workflow Optimizer | /agenthub-productivity:workflow-optimizer |
Tool-flow transitions, effectiveness, delegation, error propagation, concurrency, compaction |
| Monthly Review | /agenthub-productivity:monthly-review |
Month-over-month sessions, cost, tokens, completion, top projects, notable shifts |
| Time of Day | /agenthub-productivity:time-of-day |
Activity/productivity bucketed by hour and day-of-week; peak vs low-output windows |
Commands: /agenthub-productivity:standup · /agenthub-productivity:whats-next · /agenthub-productivity:focus-report
Agents: productivity-coach (work-pattern review) · focus-analyst (deep-work / focus blocks). Hooks: session start/end timing.
4. agenthub-devtools — Developer Tools
Debugging, data-integrity inspection, event tracing, transcript search, diagnostics, export, and health checks.
| Skill | Command | Purpose |
|---|---|---|
| Session Debug | /agenthub-devtools:session-debug |
Full event chain, agent hierarchy, token usage with baselines, workflow intelligence |
| Hook Diagnostics | /agenthub-devtools:hook-diagnostics |
Hook install, connectivity, handler validation, event delivery, data freshness |
| Data Export | /agenthub-devtools:data-export |
Export sessions/events/analytics/costs as JSON/CSV/Markdown |
| Health Check | /agenthub-devtools:health-check |
API, SQLite (WAL), WebSocket, endpoints, hooks, disk, data freshness |
| Event Trace | /agenthub-devtools:event-trace |
Ordered event timeline for a session, highlighting gaps/failures |
| Transcript Grep | /agenthub-devtools:transcript-grep |
Search a session transcript for a string/pattern with context |
Commands: /agenthub-devtools:doctor · /agenthub-devtools:export · /agenthub-devtools:tail-events
Agents: issue-triager (cross-component triage) · db-inspector (data-integrity inspection). CLI: agenthub-doctor, agenthub-export.
5. agenthub-insights — AI-Powered Insights
Pattern detection, anomaly alerting, forecasting, regression watch, benchmarking, optimization, and comparison.
| Skill | Command | Purpose |
|---|---|---|
| Pattern Detect | /agenthub-insights:pattern-detect |
Tool-flow transitions, recurring sequences, agent co-occurrence, delegation habits |
| Anomaly Alert | /agenthub-insights:anomaly-alert |
Cost/token/event-ratio/complexity outliers (statistical) |
| Optimization Suggest | /agenthub-insights:optimization-suggest |
Model downgrades, cache optimization, compaction reduction, tool reliability |
| Session Compare | /agenthub-insights:session-compare |
Side-by-side tokens, costs, complexity, tool-flow, metadata deltas |
| Regression Watch | /agenthub-insights:regression-watch |
Rising error rate, falling cache hits, growing compaction, climbing cost/session |
| Benchmark | /agenthub-insights:benchmark |
Benchmark a session vs the rolling average; show percentile |
Commands: /agenthub-insights:insights · /agenthub-insights:compare · /agenthub-insights:anomalies
Agents: insights-advisor (strategic analysis) · trend-forecaster (near-future cost/usage projection).
6. agenthub-sessions — Session Forensics
Search, timeline, transcript replay, per-project rollups, and lifecycle management.
| Skill | Command | Purpose |
|---|---|---|
| Session Search | /agenthub-sessions:session-search |
Find sessions by project/model/status/date; rank by cost or recency |
| Session Timeline | /agenthub-sessions:session-timeline |
Ordered timeline of one session's events with durations and tool names |
| Transcript Replay | /agenthub-sessions:transcript-replay |
Walk a transcript turn-by-turn, summarizing each message |
| CWD Rollup | /agenthub-sessions:cwd-rollup |
Roll up sessions by working directory: counts, cost, tokens, last-active |
| Session Cleanup | /agenthub-sessions:session-cleanup |
Identify stale/empty sessions; preview before the cleanup endpoint deletes (confirm required) |
Commands: /agenthub-sessions:find-session · /agenthub-sessions:replay · /agenthub-sessions:recent
Agent: session-investigator — end-to-end investigation of a single session.
7. agenthub-workflows — Orchestration & Fleet Intelligence
Multi-agent structure analysis using the workflow intelligence API and Workflow-tool run journals.
| Skill | Command | Purpose |
|---|---|---|
| DAG Map | /agenthub-workflows:dag-map |
Orchestration DAG: parent→child subagent edges, depth, fan-out |
| Delegation Audit | /agenthub-workflows:delegation-audit |
Model delegation + subagent effectiveness; wasted delegations |
| Concurrency Report | /agenthub-workflows:concurrency-report |
Concurrency lanes, parallelism, serialization bottlenecks |
| Error Propagation | /agenthub-workflows:error-propagation |
Trace failures by depth and how they cascade across subagents |
| Fleet Runs | /agenthub-workflows:fleet-runs |
Summarize Workflow-tool fleet runs (no-hook fleets ingested from run journals) |
Commands: /agenthub-workflows:workflow · /agenthub-workflows:dag · /agenthub-workflows:runs
Agent: orchestration-analyst — analyzes the 11 workflow datasets + fleet runs.
8. agenthub-quality — Reliability & SLOs
Error monitoring, hook-delivery health, SLO tracking with error budgets, and regression alerts.
| Skill | Command | Purpose |
|---|---|---|
| Error Scan | /agenthub-quality:error-scan |
Scan events for APIError + failure signals; group by tool/model; rank by frequency |
| API Error Report | /agenthub-quality:api-error-report |
APIError detail: counts over time, affected sessions/models, likely causes |
| Hook Failure Audit | /agenthub-quality:hook-failure-audit |
PreToolUse/PostToolUse balance, missing terminators, stale ingestion |
| SLO Check | /agenthub-quality:slo-check |
Completion rate, tool success rate, error rate; error budget remaining |
| Regression Alert | /agenthub-quality:regression-alert |
Compare this period's error/failure rates to the prior period; optional alert rule |
Commands: /agenthub-quality:errors · /agenthub-quality:slo · /agenthub-quality:health
Agent: reliability-engineer — treats Claude Code usage as a service with an error budget.
9. agenthub-config — Config & Memory Governance
Audit your Claude Code configuration and curate the file-based memory store via the Config Explorer API.
| Skill | Command | Purpose |
|---|---|---|
| Config Audit | /agenthub-config:config-audit |
Counts per surface (user vs project), duplicate skills/agents, shell-running hooks |
| Memory Review | /agenthub-config:memory-review |
CLAUDE.md + per-project auto-memory files grouped by project; flag stale/oversized facts |
| Skill Inventory | /agenthub-config:skill-inventory |
Installed skills + contributing plugins; overlap with your own skills |
| MCP Audit | /agenthub-config:mcp-audit |
MCP servers (user + project): transport, command/args/env names, source file |
| Hook Inventory | /agenthub-config:hook-inventory |
Hooks across settings + the hooks scripts dir; flag network/arbitrary-command hooks |
Commands: /agenthub-config:audit-config · /agenthub-config:memory · /agenthub-config:inventory
Agent: config-auditor — audits config sprawl, duplication, risky hooks, and stale memory.
Memory Review can also edit the per-project memory store: auto-memory files are mutable via
PUT/DELETE /api/cc-config/filewith{ scope: "auto-memory", type: "auto-memory", project, name }(always backed up first).
10. agenthub-dashboard — Dashboard Connector
Quick status, live watch, and endpoint probing.
| Skill | Command | Purpose |
|---|---|---|
| Dashboard Status | /agenthub-dashboard:dashboard-status |
Health: API connectivity, session/event counts, hook status, data freshness |
| Quick Stats | /agenthub-dashboard:quick-stats |
One-line metrics: active sessions, total cost, events, top tool, cache efficiency |
| Live Watch | /agenthub-dashboard:live-watch |
Poll a few times to show live deltas (active sessions/agents, events, ws connections) |
| Endpoint Probe | /agenthub-dashboard:endpoint-probe |
Probe each major API route and report reachability/shape |
Commands: /agenthub-dashboard:status · /agenthub-dashboard:ping · /agenthub-dashboard:open-dashboard
Agent: dashboard-operator — verifies the dashboard is up and guides start/restart/import. Access: direct tool access to the Agent Monitor API. Settings: default agent model.
Data Model Reference
These plugins query the Agent Monitor API at http://localhost:4820. Key data shapes:
Token Tracking
- 4 token types:
input_tokens,output_tokens,cache_read_input_tokens,cache_creation_input_tokens - 4 baselines:
baseline_input,baseline_output,baseline_cache_read,baseline_cache_write(preserve pre-compaction tokens) - Effective total = current + baseline (the
/api/analyticstotals are pre-summed)
Cost Calculation
- Formula:
(tokens / 1,000,000) × rate_per_mtokfor each token type - Model matching: longest
model_patternwins (e.g.,claude-sonnet-4-5%beatsclaude-sonnet-4%) - Pre-seeded rates for Opus, Sonnet, Haiku families
Session Metadata (JSON)
thinking_blocks: count of extended thinking blocksturn_count: number of conversation turnstotal_turn_duration_ms: cumulative turn processing timeusage_extras:{ service_tiers[], speeds[], inference_geos[] }
Event Types
PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, Notification, Compaction, APIError, TurnDuration, ToolError, Interrupted
Workflow Intelligence API (/api/workflows/{sessionId})
11 datasets: stats, orchestration (DAG), toolFlow (transitions), effectiveness (subagent success), patterns (recurring sequences), modelDelegation, errorPropagation (by depth), concurrency (lanes), complexity (score), compaction (impact), cooccurrence (agent pairs)
Alert Rules (/api/alerts/rules)
Rule types: budget ({ period: day|week|month, limit_usd, thresholds: [80, 100], tool?, lane?, tz_offset? } — a spend limit in dollars, each threshold firing once per period; GET /api/budgets/status reports the current period), cost_threshold ({ usd } per session), token_threshold ({ total_tokens }), event_pattern, inactivity, status_duration. POST /api/alerts/rules/preview dry-runs any of them over recorded history.
Config Explorer (/api/cc-config/*)
Read every Claude Code surface (skills, agents, commands, output-styles, plugins, marketplaces, mcp, hooks, settings, keybindings, statusline, memory). A plugin card's contribution chips are clickable: each one expands to name the skills / subagents / commands / output styles that plugin ships (from contributes.items), so the plugin's contents are readable without opening its install directory. memory includes the per-project file-based store with scope: "auto-memory" (carrying project, name, isIndex, frontmatter); those files plus CLAUDE.md are mutable via PUT/DELETE /api/cc-config/file with always-on timestamped backups. The page also manages plugins and marketplaces: paste a GitHub owner/repo, URL or local path to register a marketplace, then install / enable / disable / update / uninstall its plugins — each button runs the corresponding claude plugin … command on the dashboard host (argv array, never a shell string). Hooks and settings.json keys are editable per layer (user / project / project-local) through PATCH /api/cc-config/settings, a per-key merge that leaves every untouched key — including redacted secrets — exactly as it was.
Plugin Development
To create your own plugins for the Agent Monitor, see the Claude Code plugin documentation.
Plugin structure
my-plugin/
├── .claude-plugin/
│ └── plugin.json # Required: name (== dir name), description, version
├── skills/
│ └── my-skill/
│ └── SKILL.md # Skill (description-only frontmatter; uses $ARGUMENTS)
├── agents/
│ └── my-agent.md # Agent (name == filename, model, tools, instructions)
├── commands/
│ └── my-command.md # Slash command (description, optional argument-hint)
├── hooks/
│ └── hooks.json # Event hooks (fail-safe, non-blocking)
├── bin/
│ └── my-cli-tool # CLI scripts (added to PATH)
└── settings.json # Plugin settings
Structure is validated by server/__tests__/plugins-marketplace.test.js, which enforces the marketplace↔directory bijection, plugin.json shape, name/dir agreement, and required frontmatter on every agent / skill / command.
Two of those shape rules exist because getting them wrong makes a plugin listed but uninstallable, with no other symptom — the marketplace loads fine and only claude plugin install fails:
- A subdirectory entry declares
"source": "./plugins/<name>", never"path".pathis not a source key the CLI accepts (This plugin's marketplace entry is invalid: source: Invalid input). - A
plugin.json'srepositoryis a string, not npm's{ "type", "url" }object (Validation errors: repository: Invalid input).
server/__tests__/repo-links.test.js guards the link side: no GitHub owner/repo marketplace shorthand (it resolves to github.com only — this repo is on Gitea, so the shorthand cannot work and no GH_HOST-style env var redirects it), no raw.githubusercontent.com / *.github.io / GitHub /blob/<branch>/ URLs, no retired repository name, and no stale committed openapi.yaml.
Testing locally
claude --plugin-dir /path/to/my-plugin # then use /my-plugin:my-skill some args
Troubleshooting
Dashboard not reachable
cd /path/to/AgentHub
npm start # or: npm run dev
Hooks not installed
cd /path/to/AgentHub
npm run setup
Plugin not found
claude plugin marketplace list
claude plugin marketplace add https://git.smartgift.io.vn/Smartgift-AI/AgentHub.git
License
Internal SmartGift build — all rights reserved.