HookStackGitHub
Back to catalogue
ContextSessionStartSessionStartOn Claude Code session start· non-blocking

GitHub context loader

Open PRs and CI status loaded before you ask

At session start, injects the repository GitHub state via the gh CLI: open pull requests (up to 5) and check status for the current branch PR. Local git context tells the agent where the working tree is; this hook covers the blind spot of what is happening on GitHub. Silent no-op when gh is missing, unauthenticated, or the repo has no GitHub remote.

What does the GitHub context loader hook do?

GitHub context loader is a Claude Code SessionStart hook. It fires automatically at that lifecycle event — outside the model, so it can't be skipped or forgotten. Open PRs and CI status loaded before you ask.

Use cases

  • Resuming work with awareness of PRs awaiting review
  • Reacting to failing CI checks without being asked to look
  • Avoiding duplicate work on changes already in an open PR

Tags

#context#github#ci#productivity

settings.json fragment

{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/session-start-github-context.mjs"
          }
        ]
      }
    ]
  }
}

Script · .claude/hooks/session-start-github-context.mjs

#!/usr/bin/env node
// Injecte l'état GitHub (PRs ouvertes, checks de la branche) au démarrage de session (SessionStart)
import { readFileSync } from 'fs';
import { execSync } from 'child_process';
import { fileURLToPath } from 'url';

function defaultExec(cmd) {
  try {
    return execSync(cmd, { encoding: 'utf8', timeout: 10_000, stdio: 'pipe' }).trim();
  } catch {
    return '';
  }
}

export function run(_input, { exec = defaultExec } = {}) {
  // Silencieux si gh absent, non authentifié ou dépôt sans remote GitHub
  const prs = exec('gh pr list --state open --limit 5');
  const checks = exec('gh pr checks 2>/dev/null');

  if (!prs && !checks) return null;

  const lines = ['## GitHub Context'];
  if (prs) lines.push('### Open PRs', '```', prs, '```');
  if (checks) lines.push('### Checks on current branch PR', '```', checks, '```');

  return {
    hookSpecificOutput: {
      hookEventName: 'SessionStart',
      additionalContext: lines.join('\n'),
    },
  };
}

/* v8 ignore next 5 */
if (process.argv[1] === fileURLToPath(import.meta.url)) {
  const input = JSON.parse(readFileSync(0, 'utf8'));
  const result = run(input);
  if (result) process.stdout.write(JSON.stringify(result));
}