Bun-based MCP channel plugins paired with Claude Code skills that drive interactive HTML artifacts. Each plugin lives at localhost:<port> and exposes typed MCP tools so Claude can write findings, QA, comments, and verdicts back into the artifact in real time. Pinned comments posted from the browser are forwarded to the live Claude session as notifications/claude/channel — that bidirectional channel is the whole point.
Replaces /diff-review and /review. Single session at a fixed port (4747, override via CODE_REVIEW_PORT). Renders a collapsible diff tree with inline findings/comments, syntax highlighting, control-flow Mermaid, parallel-agent results, and threaded pinned comments.
cd code-review && bun install
# or run via the alias:
claude-review
The claude-review alias lives in ~/.zshrc and resolves to:
claude --mcp-config ~/Code/Misc/agentic-channels/code-review/standalone.mcp.jsonReplaces /scout and /plan. Multi-session, multi-port (4848+, override via FORGE_PORT/FORGE_SESSION; auto-increments up to 10 ports if taken). 3 tabs (Plan, Code, Risks & Tests), comment-driven live updates with semantic flags (📌 comment / 🔬 verify), confidence gate that gates draft diffs.
cd forge && bun install
claude --mcp-config ~/Code/Misc/agentic-channels/forge/standalone.mcp.json
Per-instance state at ~/.local/share/agentic-channels/forge/<repo-slug>-<session>/{data,comments}.json.
The plugins are intentionally NOT registered globally — opt in per launch.
skills/code-review/ and skills/forge/ are markdown skills that drive their respective artifacts. Both are deployed to ~/.agents/skills/<name> via a chezmoi symlink directive in ~/Code/Misc/master-terminal/home/dot_agents/skills/. Edits in this repo immediately reflect in ~/.claude/skills and ~/.codex/skills.
To deploy after pulling (only needed if the symlink itself moved):
chezmoi --source ~/Code/Misc/master-terminal/home apply --force ~/.agents/skills
agentic-channels/
├── package.json # root: dev / validate scripts
├── scripts/
│ ├── dev.ts # boots both servers on sandbox ports against the example fixtures; prints [ready] when both are bound
│ └── validate.ts # bun run validate — schema + semantic checks for any data.json
├── examples/
│ ├── code-review.example.json # checked-in fixture used by `bun run dev`
│ ├── forge.example.json
│ └── examples.test.ts # asserts both fixtures Zod-parse
├── code-review/ # Bun MCP plugin — single session, port 4747
│ ├── server.ts
│ ├── index.html # plugin-specific styles (overrides shared/styles.css)
│ ├── scripts/ # build-diff-tree.ts (uses shared/parse-diff.ts) + tests
│ ├── types.ts # z.infer re-exports from shared/schemas.ts
│ ├── SCHEMA.md # data.json contract (human-readable docs)
│ └── standalone.mcp.json # consumed by the claude-review alias
├── forge/ # Bun MCP plugin — multi-session, multi-port (4848+)
│ ├── server.ts
│ ├── index.html # plugin-specific styles (overrides shared/styles.css)
│ ├── types.ts # z.infer re-exports from shared/schemas.ts
│ ├── SCHEMA.md
│ └── standalone.mcp.json
├── shared/ # single source of truth + reusable infra
│ ├── schemas.ts # Zod schemas — shared FileNode/GroupNode + plugin-specific Data
│ ├── validate.ts # validate(schema, value, semChecks?) → {complete, missing[], invalid[]}
│ ├── watch.ts # makeTolerantReader: fs.watch + Zod-validate → cache swap
│ ├── instance.ts # XDG per-instance paths (repo-slug + branch / session)
│ ├── persist.ts # WS clients + broadcast(event, sessionId?, payload?) + JSON I/O
│ ├── routes.ts # common HTTP routes (data, comments, qa, /shared/{pins,tree}.js + styles.css)
│ ├── comments.ts # pure handlers + types for pinned comments
│ ├── channel.ts # makeDeliverChannel — channel notification builder
│ ├── bootstrap.ts # bindWithPortRetry (EADDRINUSE fallback)
│ ├── parse-diff.ts # unified-diff → FileNode[] (used by code-review + forge draft→diff)
│ ├── tree.client.js # browser-side file-tree component (renderHunk + renderLeaf hooks)
│ ├── pins.client.js # browser-side pin/comment components
│ └── styles.css # shared theming, tabs, tg-* tree, hunks, pin overlay, comment panel
└── skills/
├── code-review/ # SKILL.md + references/ — chezmoi-deployed
└── forge/ # SKILL.md + references/ — chezmoi-deployed
Per-instance state lives at $XDG_DATA_HOME/agentic-channels/<plugin>/<id>/:
- code-review: id =
<repo-slug>-<branch>(auto-derived) - forge: id =
<repo-slug>-<session>
bun run dev # boots both servers on sandbox ports (4757 + 4858+) against the example fixtures
bun run validate # schema + semantic check on the fixtures (or any data.json)
Sub-agent JSON output is folded into data.json via the merge MCP tool that
each plugin exposes — no CLI script. Pass a JSON patch (one or more recognised
section keys) and an optional section to restrict the merge.
bun --watch reloads on server-code changes; an explicit reload WS event reloads the browser on index.html / shared/{tree,pins}.client.js / shared/styles.css edits.
If bun run dev (or a manual server.ts boot) reports port NNNN already in use — running stdio-only, the bootstrap helper has lsof-detected the holding pid and includes a literal kill <pid> line in the same stderr message. Most often it's a stale bun --watch from a prior session.
The repo is a Bun workspace — one install pulls deps for all sub-packages:
bun install
bun run check # typecheck + lint + test (must all pass for every commit)
bun run typecheck # strict TS
bun run lint # ESLint (typescript-eslint recommended)
bun test # all tests across workspaces
bun run check runs in a pre-commit hook (wired via .githooks/pre-commit and a prepare script that sets core.hooksPath). The verification rule lives at .claude/rules/030-verification.md.
To run a single test file:
bun test code-review/scripts/build-diff-tree.test.ts
bun test shared/tree.test.ts -t "renderHunk"
Both plugins expose a minimal stdio MCP API; everything else is direct Edit/Write on data.json followed by a validate() call.
code-review (7): validate, merge, export, mark_addressed, reply_to_comment, list_pending_comments, address_pending_comment.
forge (8): above + set_decision_status (kept because it writes chosen consistently with state and runs the reopen cascade over dependsOn).