Development
Hook
Hooks
What 97 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 oribarilan/97 > /plugin install 97@97-marketplace
Ships with 97. 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 /** * SessionStart hook for 97 plugin. * * Reads skills/using-97/SKILL.md, strips frontmatter (matching the OpenCode * adapter for cross-harness consistency), and emits the platform-appropriate * context-injection JSON on stdout. * * Output shape: * - Claude Code (default): * { hookSpecificOutput: { hookEventName: "SessionStart", * additionalContext: "..." } } * - Copilot CLI (when COPILOT_CLI env var is set, any non-empty value): * { additionalContext: "..." } * * Cursor is intentionally not supported — see CONTRIBUTE.md harness * scope policy. Add a new harness adapter only after content evidence * justifies the scope expansion. * * Zero deps, Node built-ins only. Invoked directly via `node` from * hooks/hooks.json so it works on Linux, macOS, and Windows without * relying on a POSIX shell. */ import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const skillPath = path.resolve(__dirname, '..', 'skills', 'using-97', 'SKILL.md'); // Strip frontmatter to mirror .opencode/plugins/97.js behavior. CRLF-tolerant // for Windows checkouts. function stripFrontmatter(content) { const m = content.match(/^---\r?\n[\s\S]*?\r?\n---\r?\n([\s\S]*)$/); return m ? m[1] : content; } let body = ''; try { const raw = fs.readFileSync(skillPath, 'utf8'); body = stripFrontmatter(raw); } catch (err) { // Fail loud on stderr; emit empty-context JSON so the harness still // gets a parseable object rather than a crash. process.stderr.write(`97 session-start: failed to read ${skillPath}: ${err.message}\n`); } const sessionContext = `<bootstrap name="using-97"> ${body} </bootstrap>`; const isCopilot = !!process.env.COPILOT_CLI; const payload = isCopilot ? { additionalContext: sessionContext } : { hookSpecificOutput: { hookEventName: 'SessionStart', additionalContext: sessionContext, }, }; process.stdout.write(JSON.stringify(payload, null, 2) + '\n');
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 with97
Agent skills distilled from the hard-won lessons of world-renowned programmers, in the spirit of "97 Things Every Programmer Should Know"
Get the whole plugin
Stats
24
Stars
1
Forks
Maintained
Maintenance
JavaScript
Language
4mo ago
Last commit
4mo ago
Created
Repo: oribarilan/97

