ecbbb4dd8f
- Chat view: an attached image's path is pasted on its own after the text (promptForPane). claude turns a paste that is only an image path into [Image #n], but left a Windows path inside a paste of text as a plain path. Other files and @-mentions stay in the text as before. - Plugin bootstrap: depsHash covers only what npm installs (no release version), so a version bump no longer reinstalls runtime deps; the client's installed tree is kept while its manifests are unchanged (no npm ci per update); the user-side build runs vite only (tsc -b cost ~25 s / ~900 MB); clientBuild is recorded only after a build that did not fail, so a failed one is retried; npm output goes to runtime/npm-install.log. - Server: a port held by another program ends with a clear message and exit 1 instead of an uncaught 'error' stack trace. - Client: the onboarding wizard is lazy and rendered only before onboarding; usePrefersReducedMotion moved to hooks/ so PetSettings no longer pulls the Sagi chat/pane stack into the entry chunk (884 KB -> 431 KB, gzip 268 -> 133 KB).
772 lines
50 KiB
Markdown
772 lines
50 KiB
Markdown
# 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](./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](./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
|
||
|
||
```bash
|
||
claude plugin marketplace add https://git.smartgift.io.vn/Smartgift-AI/AgentHub.git
|
||
```
|
||
|
||
### Install the dashboard itself
|
||
|
||
```bash
|
||
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](#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`](https://git.smartgift.io.vn/Smartgift-AI/smartgift-claude-skills)
|
||
— its `source` still points at this repo's `main` branch, so the two entries
|
||
install identically:
|
||
|
||
```bash
|
||
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
|
||
|
||
```bash
|
||
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
|
||
|
||
```bash
|
||
# From the repo root, test a plugin locally
|
||
claude --plugin-dir plugins/agenthub-analytics
|
||
```
|
||
|
||
## Prerequisites
|
||
|
||
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) installed and authenticated
|
||
- Node **>= 22.5** when installing via the `agenthub` plugin. A plugin install has no
|
||
native `better-sqlite3`, so the server stores data through `node: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` — the `agenthub`
|
||
plugin starts it for you; a checkout starts it with `npm start` (see
|
||
[SETUP.md](../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:
|
||
|
||
1. **Fast path** — recorded state matches this plugin build and a server is live → exit. "Live" means a discovery entry whose pid answers AND whose `startedAt` is 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.
|
||
2. **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](#a-retired-build-never-acts)).
|
||
3. **Node gate** — refuse below 22.5 with one line (see Prerequisites).
|
||
4. **Lock** — atomic `mkdir` lock 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.
|
||
5. **Install** — only when the dependencies changed (`depsHash` covers what npm installs — the dependency lists and the lockfile's package tree — never the release's own `version`, so a plain version bump reinstalls nothing): `npm install --omit=dev --ignore-scripts` into the runtime dir, output in `runtime/npm-install.log`, run as the npm bundled with the node running the bootstrap (`npmCommand`: its `npm-cli.js` beside `process.execPath`, no shell, that node's directory first on PATH; `npm` on PATH only when that node ships none) — the update chain runs with the dashboard server's environment, whose PATH need not reach `npm.cmd` on 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-scripts` keeps the root `postinstall` from pulling the whole Vite client toolchain.
|
||
6. **Legacy hook cleanup** — see above.
|
||
7. **CLI** — write the `~/.local/bin/agenthub` launcher, never clobbering a `agenthub` the bootstrap did not write. It pins the node that ran the bootstrap and falls back to `node` on `PATH` when that binary is gone (a Homebrew Cellar or nvm path deleted by an upgrade).
|
||
8. **UI build** — `client/` is copied into the runtime dir and built there (`npm ci --include=dev --ignore-scripts`, falling back to `npm install` with the same flags — skipped while `client/package.json` and its lockfile are unchanged, because the installed tree in `runtime/client-src/node_modules` is kept with a `.agenthub-deps` stamp; a failed build drops the stamp so the next one installs from clean — then `vite build` run by the bootstrap's own `node`: the vite half of the client's `build` script without `npm run`. The `tsc -b` half is the release's job, not every user's: it emits nothing the bundle needs and cost ~25 s and ~900 MB per update), landing in `runtime/client-dist` — the same directory the server serves from. Nothing in it looks `node` up on PATH: on Windows an install script or a `.bin/*.cmd` shim runs through cmd.exe, and the server's PATH may have no `node` (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=dev` is required, not tidy: the entire build toolchain (`vite`, `typescript`, `@vitejs/plugin-react`, `tailwindcss`, `@types/*`) is a devDependency, and npm reads an inherited `NODE_ENV=production` as `--omit=dev`. Every bootstrap descended from the running server carries that env — the self-update chain, and any `SessionStart` fired by a `claude` inside a tmux pane the server started — so without the flag the install drops `vite` and the build dies on missing types. Skipped when a bundle for the current version already exists (`clientBuild` in `state.json`, recorded only after a build that did not fail, so the next session retries a failed one); a failure here does not fail the bootstrap (the API still works, and `/agenthub-open` can retry) but does mean `/run` 404s 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's `UI build vX (rebuild client to match)` line.
|
||
9. **Server** — when the user has turned **Start AgentHub automatically** on
|
||
(Settings → System; OFF by default), install/refresh the
|
||
`agenthub.service` unit on Linux — on macOS with a GUI login, the
|
||
`io.smartgift.agenthub` LaunchAgent (see [Auto-start on boot](#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), spawn `server/index.js` detached, with `NODE_PATH` at the
|
||
runtime `node_modules` and `DASHBOARD_CLIENT_DIST` at the runtime
|
||
`client-dist` — scoped to this session, same as before this fell back to
|
||
systemd.
|
||
10. **Record state** — `runtime/state.json`.
|
||
11. **Prune retired cache copies** — delete the plugin-cache directories earlier updates left behind (see [Pruning the plugin cache](#pruning-the-plugin-cache)). After step 10, so a prune that goes wrong cannot also cost the record of a bootstrap that went right.
|
||
12. **Hand over to systemd** — only when a unit of ours already owns the server
|
||
(see [Who may stop the server](#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`; npm's own output goes to
|
||
`npm-install.log` and the UI build's 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:
|
||
|
||
```bash
|
||
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` (a `kickstart` would 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](../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-failure` read 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 write
|
||
`runtime/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](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.service` systemd `--user` unit (Linux) — it
|
||
will keep restarting the old server on every reboot, since `systemctl`
|
||
knows nothing about `claude plugin uninstall`
|
||
- remove the cached source under `~/.claude/plugins/cache/.../agenthub/<version>/`
|
||
- remove the hook entries `claude plugin install` wrote 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/agenthub` or `~/.claude/agenthub/runtime/`
|
||
|
||
For a clean machine, do all of this yourself:
|
||
|
||
```bash
|
||
# 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/file` with `{ 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/analytics` totals are pre-summed)
|
||
|
||
### Cost Calculation
|
||
- Formula: `(tokens / 1,000,000) × rate_per_mtok` for each token type
|
||
- Model matching: longest `model_pattern` wins (e.g., `claude-sonnet-4-5%` beats `claude-sonnet-4%`)
|
||
- Pre-seeded rates for Opus, Sonnet, Haiku families
|
||
|
||
### Session Metadata (JSON)
|
||
- `thinking_blocks`: count of extended thinking blocks
|
||
- `turn_count`: number of conversation turns
|
||
- `total_turn_duration_ms`: cumulative turn processing time
|
||
- `usage_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](https://docs.anthropic.com/en/docs/claude-code/plugins).
|
||
|
||
### 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"`. `path` is not a source key the CLI accepts (`This plugin's marketplace entry is invalid: source: Invalid input`).
|
||
- A `plugin.json`'s **`repository` is 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
|
||
|
||
```bash
|
||
claude --plugin-dir /path/to/my-plugin # then use /my-plugin:my-skill some args
|
||
```
|
||
|
||
## Troubleshooting
|
||
|
||
### Dashboard not reachable
|
||
```bash
|
||
cd /path/to/AgentHub
|
||
npm start # or: npm run dev
|
||
```
|
||
|
||
### Hooks not installed
|
||
```bash
|
||
cd /path/to/AgentHub
|
||
npm run setup
|
||
```
|
||
|
||
### Plugin not found
|
||
```bash
|
||
claude plugin marketplace list
|
||
claude plugin marketplace add https://git.smartgift.io.vn/Smartgift-AI/AgentHub.git
|
||
```
|
||
|
||
## License
|
||
|
||
Internal SmartGift build — all rights reserved.
|