code-review-graph
Builds a local, persistent map of your codebase with tree-sitter so Claude Code reads only the code that matters. Offers skills for code review, debugging, exploring structure, and safe refactoring.
What brooks-lint runs automatically, and when. A hook is a command Claude Code fires at a fixed moment, without you asking for it.
Claude Code
> /plugin marketplace add hyhmrright/brooks-lint> /plugin install brooks-lint@brooks-lint-marketplace
Cursor
Cursor also runs Claude Code hooks from .claude/settings.json, so copy these hooks there to use them in Cursor.
What fires, and when
SessionStart
Fires once when a session begins, and again after a context compaction. It is where a plugin sets up its environment, or restores state the compaction dropped.
startup|clear|compactnode "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.mjs"Where it lives
#!/usr/bin/env node
import {
existsSync,
mkdirSync,
readFileSync,
readdirSync,
rmSync,
writeFileSync,
} from "node:fs";
import os from "node:os";
import path from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const pluginDir = path.resolve(__dirname, "..");
const homeDir = process.env.HOME || os.homedir();
function readVersion() {
const packageJson = JSON.parse(
readFileSync(path.join(pluginDir, "package.json"), "utf8"),
);
if (!packageJson.version) {
throw new Error("Failed to read version from package.json");
}
return packageJson.version;
}
function installCommands(version) {
const commandDir = path.join(homeDir, ".claude", "commands");
const sentinel = path.join(commandDir, `.brooks-lint-v${version}`);
// Already installed for this version — nothing to do.
if (existsSync(sentinel)) return;
mkdirSync(commandDir, { recursive: true });
const commandsDir = path.join(pluginDir, "commands");
for (const entry of readdirSync(commandsDir)) {
if (/^brooks-.*\.md$/.test(entry)) {
// Short forms live in ~/.claude/commands/ (user commands), where
// ${CLAUDE_PLUGIN_ROOT} does not expand — bake in the absolute path so
// the wrapper can still locate its SKILL.md.
const body = readFileSync(path.join(commandsDir, entry), "utf8").replaceAll(
"${CLAUDE_PLUGIN_ROOT}",
pluginDir,
);
writeFileSync(path.join(commandDir, entry), body);
}
}
for (const entry of readdirSync(commandDir)) {
if (entry === ".brooks-lint-installed" || entry.startsWith(".brooks-lint-v")) {
rmSync(path.join(commandDir, entry), { force: true });
}
}
writeFileSync(sentinel, "");
}
function buildContext() {
return [
"You have the brooks-lint plugin installed. It provides six independent skills - load the relevant one via the Skill tool:",
" brooks-lint:brooks-review -> PR code review",
" brooks-lint:brooks-audit -> Architecture audit",
" brooks-lint:brooks-debt -> Tech debt assessment",
" brooks-lint:brooks-test -> Test quality review",
" brooks-lint:brooks-health -> Codebase health dashboard",
" brooks-lint:brooks-sweep -> Full sweep: analyse all dimensions and auto-fix findings",
"",
"Triggers when the user asks to review code, discuss architecture, assess tech debt, or discuss test quality. Each skill's own description carries its full trigger phrases and exclusions.",
].join("\n");
}
function buildOutput(context) {
if (process.env.CLAUDE_PLUGIN_ROOT) {
return {
hookSpecificOutput: {
hookEventName: "SessionStart",
additionalContext: context,
},
};
}
return {
additional_context: context,
};
}
try {
installCommands(readVersion());
process.stdout.write(`${JSON.stringify(buildOutput(buildContext()), null, 2)}\n`);
} catch (error) {
process.stderr.write(`${error.message}\n`);
process.exit(1);
}
Read the script before you install anything that runs on your machine. This is the one part of a plugin that acts without being asked.
Portable AI code quality reviews for Codex, Cursor, Copilot and other coding agents: six Agent Skills for architecture, technical debt, tests and remediation.
Builds a local, persistent map of your codebase with tree-sitter so Claude Code reads only the code that matters. Offers skills for code review, debugging, exploring structure, and safe refactoring.