Development
Hook
Hooks
What brooks-lint runs automatically, and when. A hook is a command Claude Code fires at a fixed moment, without you asking for it.
Install
> /plugin marketplace add hyhmrright/brooks-lint > /plugin install brooks-lint@brooks-lint-marketplace
Ships with brooks-lint. Installing the plugin gets these hooks.
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.
- Matches
startup|clear|compactnode "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.mjs"
Where it lives
- hooks/session-start.mjsRunsGitHub
Read the script
#!/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.
Ships withbrooks-lint
AI code reviews grounded in 12 classic engineering books — decay risk diagnostics with book citations, severity labels, and 6 analysis modes including full-sweep auto-fix
Get the whole plugin, auto-invoked
Stats
1,483
Stars
66
Forks
Active
Maintenance
HTML
Language
MIT
License
3d ago
Last commit
5mo ago
Created
Repo: hyhmrright/brooks-lint

