Two leftovers from the rebrand, done together because they touch the same
docs and manifests.
**Data directory.** `agent-dashboard` could not simply be renamed in the
source: it names a real directory holding the live SQLite database. Startup
now moves it once, via `migrateLegacyDataDir()` in `server/lib/claude-home.js`
— a same-filesystem rename, so it is instant even at multiple gigabytes and
cannot leave two divergent copies. `getDataDir()` stays PURE and resolves to
the legacy path until the move happens; the first version of this put the
rename inside the getter, which meant `npm run test:server` relocated the
developer's real database as a side effect. The call sits behind
`require.main === module` and ahead of the router requires, because those pull
in db.js, which opens SQLite at module load. A failed rename is silent and the
old directory keeps being used: an unfashionable directory name beats a blank
database beside an unreachable one. Same treatment for the port-discovery file
(`.agent-dashboard.json` → `.agenthub.json`, old one dropped on write).
Not renamed on purpose: the Sagi localStorage keys (renaming silently resets
everyone's prefs) and the PWA manifest `id` (changing it orphans an installed
app).
**MCP server.** 4 tool calls in 46 days across 577,132 events, against 4,556
lines of TypeScript, a 2 MB committed build artifact, and a pre-commit guard
that had already blocked commits twice. Deleted: `mcp/`, the maintainer skills
and `mcp-reviewer` agent, the build check, `plugins/agenthub/.mcp.json`,
`docs/MCP.md`, 12 npm scripts, 5 Makefile targets, and every doc section
describing it.
Kept, because they are unrelated things sharing the name: the Config
Explorer's MCP tab and its API, per-lane Playwright MCP, the agenthub-config
plugin's MCP audit, and the historical `mcp__plugin_agenthub_*` events that
analytics must keep attributing.
Verified: server 1432/1432, client 459/459, tsc clean, prettier clean. Both
directions of the migration proven — a sandbox-HOME test run leaves the legacy
directory untouched, and a real boot moves it with its contents intact.
The seven per-mood `transform-origin: 640px 720px` rules were written in
mascot.svg's 1280-unit space but applied to the root <svg>, where CSS
resolves a length against the 68px CSS box. The pivot landed ~9x the
element away, so `scale(1.035)` ("gentle breathing") swung the whole
mascot ~20px up-left every 4s - and the speech bubble, positioned from
the untransformed box, stayed put while Sagi visibly moved.
- One `transform-origin: 50% 92%` on `.sagi-avatar` (feet pivot); a
percentage so it cannot be misresolved against either reference box.
- Eye-blink and sparkle origins rebased onto `transform-box: view-box`,
whose 0,0 is the viewBox min (253.5 106) - the eyelids were closing
off-target and the sparkle twinkled around a point outside itself.
- `sagi-rock` returns to 0deg; it used to park `thinking` at a
permanent -6deg tilt.
- `.sagi-flyout` gets the avatar button's exact left/top easing so the
bubble glides with the snap instead of teleporting, and the bubble no
longer unmounts mid-drag (the panel still does - dragging a 320px
panel around is jank).
- Reduced motion now also covers `.sagi-bubble-enter` and both
transitions; dropped a `~ *` selector that never matched.
Gives watching/thinking real animations (previously static), adds
character to happy/worried/stuck moods, and adds mount-in/press/error-pulse
motion to the avatar button - all gated by prefers-reduced-motion.
fix(test): pin NODE_ENV=production in client-dist-override.test.js
The suite exercises server/index.js's production-only static-serving
gate but never set NODE_ENV itself, so it silently depended on the
ambient shell's NODE_ENV - failing whenever that wasn't "production".
Unmatched Ask questions now adopt a dedicated "Sagi" lane (POST
/api/lanes/ensure, cwd defaults to $HOME) and spawn a tmux-backed claude
run there instead of just prefilling the Run page composer.
The repo root already IS the `ccam` plugin root (`"source": "./"`), so the
conventional `skills/` dir at the root is the plugin's skills dir — while
`.claude/skills/` only loaded for a session whose cwd was inside this
checkout. That is useless for a lane working in another repo, which is why
`ccam skills install` existed at all.
Move all seven skills to `skills/`: they now reach every plugin user as
`/ccam:<name>` (bare `/<name>` as an alias). `ccam skills install` stays as
the fallback for a plain checkout without the plugin, sourcing from the new
path.
Agents deliberately do NOT move. A plugin agent is addressed as
`ccam:qc-local`, which would break the `subagent_type: qc-local` references
in ship-feature-lane; `ccam lanes agents install` keeps writing them into the
lane's own `.claude/agents/`, the highest-priority agent source. MCP was
already plugin-shipped via `plugins/ccam/.mcp.json`.
Mechanical fallout: ~115 source files carry a doc-comment pointer to
`.claude/skills/file-headers/`, repointed to `skills/file-headers/`. The
generic Claude Code config-surface examples in openapi/cc-config (`.claude/
skills/code-reviewer`) describe any user's layout and are left alone.
Also fixes the two file-headers scripts, whose `ROOT=` climbed four levels
from `.claude/skills/file-headers/scripts/` and would have escaped the repo
from the new depth — it scanned sibling projects until corrected to three.
npm run test:server (1160 pass), test:client (422 pass), mcp:typecheck,
mcp:build + mcp:check-build all green.
SAGI_SIZE (the draggable button's real footprint) and SagiAvatar's default
`size` both go 60 -> 90, and the viewBox drops the exporter's padded
`0 0 1280 1280` canvas for a tight window on the art: the measured bbox over
every path is x 331..1114 / y 173..1044, padded out to a square and raised to
y 106 so the zzz / bang / sparkle mood overlays stay inside and the box keeps
the 1:1 aspect of the square width/height.
Path data is not rescaled, so MAX_PUPIL_SHIFT and the eye/mood
transform-origins in sagi.css stay valid in the original 1280-unit space.
Full rename across files, identifiers, CSS classes, and user-facing strings
(en/vi locales, ARCHITECTURE.md). Replaces the hand-drawn animated cat
avatar with the pig-superhero mascot artwork, split into parts to keep
per-eye cursor tracking and blink animation working; whole-mascot mood
transforms (breathe/bob/shake/tilt) and new zzz/bang/sparkle overlays
carry the rest of the mood expression since the traced art has no shared
palette to key off of.