refactor!: rebrand CCAM to AgentHub
Clean break, no compatibility alias. Renames the product name, the CLI binary (`ccam` -> `agenthub`), the env var prefix (`CCAM_` -> `AGENTHUB_`), the Prometheus metric namespace (`ccam_*` -> `agenthub_*`), the tmux session prefix (`ccam-lane-<id>` -> `agenthub-lane-<id>`), the per-repo runtime profile directory (`.ccam/profile` -> `.agenthub/profile`), the lanes state root (`~/.claude/ccam-lanes` -> `~/.claude/agenthub-lanes`), the bundled plugins (`plugins/ccam*` -> `plugins/agenthub*`) and their slash commands (`/ccam-doctor` -> `/agenthub-doctor`, `/ccam:*` -> `/agenthub:*`). Because there is no alias, an existing install has to be updated by hand: rename its `.ccam/profile` directory and any `CCAM_*` variables, and reinstall the plugin under its new name. Two other name families are deliberately left alone here, since they are not just strings: the `Claude-Code-Monitor` repository/marketplace name, and the `agent-dashboard` npm package plus its `~/.claude/agent-dashboard` runtime directory, which holds the live database and needs a migration rather than a rename. Verified: server 1406/1406, client 459/459, `grep -i ccam` clean across tracked files, `openapi.yaml` regenerated (95 paths, unchanged count).
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# Plugin-first install — CCAM usable straight from a Claude Code plugin install
|
||||
# Plugin-first install — AgentHub usable straight from a Claude Code plugin install
|
||||
|
||||
Date: 2026-08-10
|
||||
Status: approved (design)
|
||||
@@ -6,12 +6,12 @@ Status: approved (design)
|
||||
## Goal
|
||||
|
||||
On a machine with nothing but Claude Code installed, these two commands must
|
||||
leave the user with a working CCAM — hooks flowing, server up, dashboard
|
||||
reachable, `ccam` CLI on PATH, MCP tools connected:
|
||||
leave the user with a working AgentHub — hooks flowing, server up, dashboard
|
||||
reachable, `agenthub` CLI on PATH, MCP tools connected:
|
||||
|
||||
```
|
||||
/plugin marketplace add <ccam repo>
|
||||
/plugin install ccam@claude-code-agent-monitor-plugins
|
||||
/plugin marketplace add <agenthub repo>
|
||||
/plugin install agenthub@claude-code-agent-monitor-plugins
|
||||
```
|
||||
|
||||
No repo clone, no `npm run setup`, no `npm run install-hooks`, no manual
|
||||
@@ -19,8 +19,8 @@ No repo clone, no `npm run setup`, no `npm run install-hooks`, no manual
|
||||
|
||||
## Why the current state does not do this
|
||||
|
||||
- The only plugin with a server connection, `ccam-dashboard`, declares its MCP
|
||||
server as `../../mcp/build/index.js` (`plugins/ccam-dashboard/.mcp.json`).
|
||||
- The only plugin with a server connection, `agenthub-dashboard`, declares its MCP
|
||||
server as `../../mcp/build/index.js` (`plugins/agenthub-dashboard/.mcp.json`).
|
||||
Plugins installed from a marketplace subdir are cached as **that subdir
|
||||
only** — verified against `~/.claude/plugins/cache/claude-plugins-official/superpowers/6.2.0/`,
|
||||
which contains the plugin directory's contents and nothing above it. The
|
||||
@@ -32,14 +32,14 @@ No repo clone, no `npm run setup`, no `npm run install-hooks`, no manual
|
||||
|
||||
## Approach: declare the whole repo as one plugin
|
||||
|
||||
Add a **root-level** plugin named `ccam` with `"source": "."` in
|
||||
Add a **root-level** plugin named `agenthub` with `"source": "."` in
|
||||
`.claude-plugin/marketplace.json`. Claude Code then caches the *entire repo*
|
||||
into `~/.claude/plugins/cache/<marketplace>/ccam/<version>/` — verified against
|
||||
into `~/.claude/plugins/cache/<marketplace>/agenthub/<version>/` — verified against
|
||||
`~/.claude/plugins/cache/caveman/`, whose cached tree contains the full source
|
||||
repo (`src/`, `tests/`, `benchmarks/`), because that marketplace declares its
|
||||
plugin with `"source": "./"`.
|
||||
|
||||
So `server/`, `client/`, `mcp/`, `scripts/` and `bin/ccam.js` are all present
|
||||
So `server/`, `client/`, `mcp/`, `scripts/` and `bin/agenthub.js` are all present
|
||||
under `${CLAUDE_PLUGIN_ROOT}` the moment the plugin is installed. No second
|
||||
clone, no credentials beyond the marketplace add itself, no committed copy of
|
||||
the server, no dependency on undocumented cache internals beyond the documented
|
||||
@@ -61,7 +61,7 @@ gains no new top-level directories.
|
||||
`.claude-plugin/marketplace.json` gains one entry:
|
||||
|
||||
```json
|
||||
{ "name": "ccam", "source": ".", "description": "...", "tags": [...] }
|
||||
{ "name": "agenthub", "source": ".", "description": "...", "tags": [...] }
|
||||
```
|
||||
|
||||
### 2. Hooks — inline in `plugin.json`
|
||||
@@ -95,7 +95,7 @@ Runs from the `SessionStart` hook. Never blocks a session.
|
||||
|
||||
Runtime state lives under `~/.claude/agent-dashboard/runtime/`, reusing the
|
||||
existing data-dir convention (`server/lib/claude-home.js:37`, where the SQLite
|
||||
DB already lives) rather than inventing a new directory. `/.ccam/` at the repo
|
||||
DB already lives) rather than inventing a new directory. `/.agenthub/` at the repo
|
||||
root is an unrelated lane profile and must not be confused with it.
|
||||
|
||||
Sequence:
|
||||
@@ -118,13 +118,13 @@ Sequence:
|
||||
fresh version directory, discarding anything installed into the old one.
|
||||
`--ignore-scripts` is required because `scripts/postinstall.js` otherwise
|
||||
runs a full `client/` install, pulling the whole Vite dev toolchain.
|
||||
5. **Legacy hook cleanup.** If `~/.claude/settings.json` still carries CCAM hook
|
||||
5. **Legacy hook cleanup.** If `~/.claude/settings.json` still carries AgentHub hook
|
||||
entries from a previous `npm run install-hooks`, remove them and print one
|
||||
line. Without this, every event is POSTed twice and token/cost figures
|
||||
double. Detection reuses `isOurEntry()` from `scripts/install-hooks.js`.
|
||||
6. **CLI on PATH.** Symlink `bin/ccam.js` to `~/.local/bin/ccam`. Skills and
|
||||
commands throughout the repo (`ccam stage`, `ship-feature-lane`) shell out
|
||||
to `ccam` and fail without it.
|
||||
6. **CLI on PATH.** Symlink `bin/agenthub.js` to `~/.local/bin/agenthub`. Skills and
|
||||
commands throughout the repo (`agenthub stage`, `ship-feature-lane`) shell out
|
||||
to `agenthub` and fail without it.
|
||||
7. **Start server.** Spawn `server/index.js` detached, `stdio: "ignore"`,
|
||||
`unref()`, with `NODE_PATH` pointed at `runtime/node_modules`. The hook
|
||||
returns immediately; the first install (1–3 minutes) proceeds in the
|
||||
@@ -132,7 +132,7 @@ Sequence:
|
||||
8. **Record state.** Write `runtime/state.json`.
|
||||
|
||||
The client UI bundle is *not* built here. Hooks, the API and MCP do not need
|
||||
it; it is built lazily by `/ccam-open`.
|
||||
it; it is built lazily by `/agenthub-open`.
|
||||
|
||||
### 4. Client dist relocation — `server/index.js`
|
||||
|
||||
@@ -143,7 +143,7 @@ checkout behavior is unchanged.
|
||||
|
||||
The bootstrap always starts the server with `DASHBOARD_CLIENT_DIST` set to
|
||||
`runtime/client-dist/`, whether or not a bundle is there yet — a missing
|
||||
directory serves the API fine and only the UI route 404s. `/ccam-open` builds
|
||||
directory serves the API fine and only the UI route 404s. `/agenthub-open` builds
|
||||
into that same directory, so no server restart is needed to pick the bundle up.
|
||||
|
||||
### 5. MCP — commit `mcp/build/`
|
||||
@@ -152,27 +152,27 @@ Claude Code starts a plugin's MCP servers as the session opens and offers no
|
||||
"not ready yet, retry" state, so an async bootstrap cannot win that race.
|
||||
`mcp/build/` is therefore committed (removed from `.gitignore` and `mcp/.gitignore`)
|
||||
and the root `.mcp.json` points at `${CLAUDE_PLUGIN_ROOT}/mcp/build/index.js`
|
||||
with `CCAM_DASHBOARD_URL` defaulted to `http://localhost:4820`.
|
||||
with `AGENTHUB_DASHBOARD_URL` defaulted to `http://localhost:4820`.
|
||||
|
||||
Cost: the build artifact must stay in sync with `mcp/src`. A pre-commit check
|
||||
fails when `mcp/src` is newer than `mcp/build`.
|
||||
|
||||
The existing `plugins/ccam-dashboard/.mcp.json` keeps its broken relative path
|
||||
The existing `plugins/agenthub-dashboard/.mcp.json` keeps its broken relative path
|
||||
fixed to `${CLAUDE_PLUGIN_ROOT}` form as part of this work, so the subdir plugin
|
||||
is not left in a knowingly broken state.
|
||||
|
||||
### 6. Commands — `plugins/ccam/commands/`
|
||||
### 6. Commands — `plugins/agenthub/commands/`
|
||||
|
||||
The plugin root is the repo root, so `plugin.json` declares an explicit
|
||||
`"commands": "./plugins/ccam/commands"` path. This keeps the new command files
|
||||
`"commands": "./plugins/agenthub/commands"` path. This keeps the new command files
|
||||
inside `plugins/`, next to the ten existing plugins, instead of adding a
|
||||
top-level `commands/` directory to the repo root.
|
||||
|
||||
- `/ccam-doctor` — bootstrap state, Node version, server liveness, DB path,
|
||||
- `/agenthub-doctor` — bootstrap state, Node version, server liveness, DB path,
|
||||
duplicate-hook detection, CLI symlink, MCP build freshness.
|
||||
- `/ccam-update` — refresh dependencies and restart the server after a plugin
|
||||
- `/agenthub-update` — refresh dependencies and restart the server after a plugin
|
||||
update.
|
||||
- `/ccam-open` — lazily build the client bundle if missing, then open the
|
||||
- `/agenthub-open` — lazily build the client bundle if missing, then open the
|
||||
dashboard.
|
||||
|
||||
## Data and lifecycle
|
||||
@@ -196,7 +196,7 @@ deduplicates hook ingest to a single port.
|
||||
by full detachment (`detached`, `stdio: "ignore"`, `unref()`) and an
|
||||
immediate hook return. Verified by timing the hook on a cold `HOME`.
|
||||
- *Duplicate hooks double-count cost.* Events carry no id, so ingest cannot
|
||||
deduplicate. Mitigated by step 5 of the bootstrap plus a `/ccam-doctor` check.
|
||||
deduplicate. Mitigated by step 5 of the bootstrap plus a `/agenthub-doctor` check.
|
||||
- *MCP unavailable at session start.* Resolved by committing `mcp/build/`.
|
||||
|
||||
**Medium severity**
|
||||
@@ -204,8 +204,8 @@ deduplicates hook ingest to a single port.
|
||||
- *Two sessions spawn two servers* → `EADDRINUSE`. Mitigated by the lock, with
|
||||
a stale-lock timeout so a crashed bootstrap does not wedge every later
|
||||
session.
|
||||
- *`ccam` not on PATH* when `~/.local/bin` is absent from the user's PATH.
|
||||
`/ccam-doctor` reports it and prints the line to add.
|
||||
- *`agenthub` not on PATH* when `~/.local/bin` is absent from the user's PATH.
|
||||
`/agenthub-doctor` reports it and prints the line to add.
|
||||
- *Windows.* `npm.cmd` resolution (already handled in `scripts/postinstall.js`
|
||||
via `shell: true`), detached spawn semantics, and `mkdir` locking are the
|
||||
least-tested paths.
|
||||
@@ -222,7 +222,7 @@ deduplicates hook ingest to a single port.
|
||||
## Verification
|
||||
|
||||
1. Install the local marketplace and confirm
|
||||
`~/.claude/plugins/cache/<mp>/ccam/*/server/` exists — this gates everything
|
||||
`~/.claude/plugins/cache/<mp>/agenthub/*/server/` exists — this gates everything
|
||||
else.
|
||||
2. `npm run test:server` for the `DASHBOARD_CLIENT_DIST` override.
|
||||
3. Unit tests for bootstrap: fast path, stale-lock reclaim, Node version gate,
|
||||
|
||||
Reference in New Issue
Block a user