Skip to content
Development
Hook

Hooks

What genesis runs automatically, and when. A hook is a command Claude Code fires at a fixed moment, without you asking for it.

From plugin
genesis
410 skills1 hook

Claude Code

> /plugin marketplace add gabrieldabbah/genesis
> /plugin install genesis@genesis-marketplace

What fires, and when

Stop

  • node "${CLAUDE_PLUGIN_ROOT}/hooks/stop-acceptance.mjs"
Read hooks/hooks.json

Where it lives

  • hooks/stop-acceptance.mjsRunsGitHub
    Read the script
    #!/usr/bin/env node
    /**
     * stop-acceptance.mjs — genesis acceptance Stop gate.
     *
     * Checks one fact: a genesis build is in flight (.scratch/acceptance.json exists) and its own acceptance
     * file says the criteria are not met. It does not judge whether the work is good; the build wrote that file.
     *
     * SELF-INERT: with no .scratch/acceptance.json it does nothing, so it never touches an ordinary session.
     * Two independent backstops stop it insisting forever: the build's own iteration ceiling, and a count of
     * the blocks this script itself has issued.
     *
     * Stop-hook contract (confirm the shape against the hooks docs for your build):
     *   - print {"decision":"block","reason":"..."} to keep the session going (Claude gets the reason), OR
     *   - print nothing / exit 0 to allow the stop.
     * Written defensively: any parse problem allows the stop (fail-open) so it can never wedge a session.
     *
     * Node rather than shell, deliberately. The shell version parsed with `jq`, which neither macOS nor Windows
     * ships — and a missing `jq` disarmed this gate silently, since the fail-open path is indistinguishable from
     * a finished build. Node runs the same on every platform Claude Code supports, including native Windows
     * where a .sh file cannot be executed at all without Git for Windows.
     */
    'use strict';
    import fs from 'node:fs';
    import path from 'node:path';
    
    function readStdin() {
      return new Promise((resolve) => {
        let s = '';
        process.stdin.on('data', (d) => (s += d));
        process.stdin.on('end', () => resolve(s));
        process.stdin.resume();
      });
    }
    
    const raw = await readStdin();
    let data = {};
    try { data = JSON.parse(raw || '{}'); } catch { /* ignore — the payload is not what we read the state from */ }
    
    try {
      const projectDir = data.cwd || process.env.CLAUDE_PROJECT_DIR || process.cwd();
      const accPath = path.join(projectDir, '.scratch', 'acceptance.json');
    
      let acc;
      try { acc = JSON.parse(fs.readFileSync(accPath, 'utf8')); } catch { process.exit(0); }
      // Not a genesis run, or a malformed/empty file → allow the stop. Never wedge on corruption.
      if (acc === null || typeof acc !== 'object' || Array.isArray(acc)) process.exit(0);
    
      // Non-integer counters fall back to their defaults; they must never fall through to a block.
      const int = (v, dflt) => (Number.isInteger(v) && v >= 0 ? v : dflt);
      const iteration = int(acc.iteration, 0);
      const maxIterations = int(acc.max_iterations, 50);
    
      // Runaway backstop: at the iteration ceiling the build escalates to the human, so allow the stop.
      if (iteration >= maxIterations) process.exit(0);
    
      const blocksFile = path.join(projectDir, '.scratch', '.stop-blocks');
    
      if (acc.criteria_met === true) {
        try { fs.unlinkSync(blocksFile); } catch { /* absent → nothing to reset */ }
        process.exit(0); // criteria observed green → allow the stop
      }
    
      // Self-incrementing backstop: the ceiling above relies on the build updating .iteration. Count our own
      // blocks too, so a session that never updates acceptance.json (or a stale file) can't be re-blocked forever.
      let blocks = 0;
      try { blocks = int(Number.parseInt(fs.readFileSync(blocksFile, 'utf8'), 10), 0); } catch { /* absent → 0 */ }
      if (blocks >= maxIterations) process.exit(0); // we alone have blocked this many times → a human should look
    
      try {
        fs.mkdirSync(path.dirname(blocksFile), { recursive: true });
        fs.writeFileSync(blocksFile, String(blocks + 1));
      } catch { process.exit(0); } // cannot record the block → do not block
    
      const open = Array.isArray(acc.open) ? acc.open.join('; ') : '';
      const reason =
        `A genesis build is in flight and its acceptance criteria are not yet met ` +
        `(iteration ${iteration}/${maxIterations}). Open: ${open || 'unspecified'}. Continue the build, and ` +
        `update .scratch/acceptance.json with what you observed. If the remaining work genuinely needs the ` +
        `operator, record it in docs/DEPLOYMENT.md and set criteria_met=true — that is a finished run, not a ` +
        `shortcut.`;
    
      process.stdout.write(JSON.stringify({ decision: 'block', reason }));
      process.exit(0);
    } catch {
      process.exit(0); // fail open, always — never wedge a session
    }
    

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.

@gabrieldabbah
Ships withgenesis

Ultimate Opus 5 builder. Genesis creates and transforms any setup into the ultimate setup for generation 5 models. Genesis turns an empty folder into a working SaaS, web app, API, or CLI, running autonomously on your machine in Claude Code.

Stars on GitHub

Momentum

stars in total
4
Star history of gabrieldabbah/genesis on GitHub, a chart by star-history.com

More plugins that ship hooks.

superpowers

superpowers

A development methodology for coding agents that makes the agent brainstorm before building, follow plans, run parallel work and finish branches in a disciplined way. You get fewer skipped steps and more consistent results from your coding assistant.

15 skills1 hook311k
@obra@obra
Install Plugin
ponytail

ponytail

A Claude Code plugin with skills for auditing a whole repo, reviewing a change, listing deferred shortcut comments, and showing measured savings and a quick command reference.

6 skills10 hooks188k
@dietrichgebert@dietrichgebert
Install Plugin
agent-skills

agent-skills

Walks a software change from a written spec through design, testing, code review, CI/CD, and release, applying the matching engineering skill at each stage. Useful for developers using Claude Code on full development workflows.

25 skills+3112k
@addyosmani@addyosmani
Install Plugin
planning-with-files

planning-with-files

Persistent file-based planning for AI coding agents on long-running, multi-step tasks. It keeps task_plan.md, findings.md and progress.md on disk, so work can resume after /clear or context compaction.

6 skills+228k
@othmanadi@othmanadi
Install Plugin
gsd-core

gsd-core

A spec-driven development workflow for Claude Code that guides a project through planning, phases, milestone audits and fixes. Includes skills to generate tests from UAT criteria and to audit completed work.

72 skills+311k
@open-gsd@open-gsd
Install Plugin
superpowers-zh

superpowers-zh

Chinese-language skill pack for Claude Code that adds workflow guidance for brainstorming, TDD, debugging, and code review, plus Chinese conventions for commits, documentation, and domestic Git platforms like Gitee and Coding.net.

21 skills1 hook8.5k
@jnmetacode@jnmetacode
Install Plugin
socraticode

socraticode

Gives Claude Code semantic search, dependency graph and architecture context over a codebase, so an AI assistant can explore and understand a project's code. Includes skills for indexing a project and managing its file watching.

2 skills+33.4k
@giancarloerra@giancarloerra
Install Plugin
cocoindex-code

cocoindex-code

A lightweight code search engine that uses AST-based semantic search with local embeddings and incremental indexing. It helps Claude Code users find code faster and more efficiently.

1 skill1 MCP+13k
@cocoindex-io@cocoindex-io
Install Plugin

Questions about the hooks in genesis.

Which coding agents can use the hooks in genesis?
The hooks in genesis install in Claude Code and Cursor: each runs Claude Code hooks from .claude/settings.json, so copy the hooks there.