Skip to content
Research
Hook

Hooks

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

From plugin
academic-research-skills
56k42 agents16 commands2 hooks

Claude Code

> /plugin marketplace add Imbad0202/academic-research-skills
> /plugin install academic-research-skills@academic-research-skills

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.

  • bash "${CLAUDE_PLUGIN_ROOT}/scripts/announce-ars-loaded.sh"

PreToolUse

  • MatchesWrite|Edit|MultiEdit|Bashbash "${CLAUDE_PLUGIN_ROOT}/hooks/run_guard.sh"
Read hooks/hooks.json

Where it lives

  • hooks/run_guard.shRunsGitHub
    Read the script
    #!/bin/sh
    # version: 1.1.0
    #
    # ARS write-scope guard LAUNCHER — PreToolUse hook (#454 Windows portability fix).
    #
    # WHY THIS EXISTS: the guard hook used to be wired as `python3 ".../ars_write_scope_guard.py"`
    # directly. On Windows, `python3` is commonly a 0-byte Microsoft Store App Execution Alias
    # stub (not real Python); invoking it non-interactively fails BEFORE the guard's Python runs,
    # so none of the guard's own fail-safes apply — it just errors and spams the hook log (#454).
    #
    # This launcher finds a REAL Python (skipping stubs), then runs the guard as a SUPERVISED
    # subprocess. Design: docs/design/2026-06-17-454-windows-python-hook-portability-design.md.
    #
    # POSTURE (Plan A — graceful degradation; the guard is OPTIONAL v3.10 hardening and ARS core
    # needs no Python): if no real Python is found, OR the guard subprocess misbehaves, the
    # launcher emits a valid PASS-THROUGH hook JSON and exits 0. It NEVER exits non-zero on these
    # degraded paths (a non-2 exit blocks nothing anyway and only spams logs; exit 2 would
    # hard-lock the user out of all writes/Bash for an environment gap or an ARS-side bug — wrong
    # for an optional layer). It stays SILENT on stderr on degraded paths: PreToolUse is a hot
    # path, so any per-call stderr IS the spam #454 is about.
    #
    # Bash 3.2 / POSIX sh compatible (same constraint as scripts/announce-ars-loaded.sh). On
    # Windows this runs under Git Bash; with no Git Bash, CC falls back to PowerShell which can't
    # run this .sh — the guard is then inactive (accepted degradation, see spec §3.3).
    
    # Canonical pass-through output: no permissionDecision => falls back to the normal permission
    # flow (NEVER emit "allow" — that would skip every other permission rule).
    PASS_THROUGH='{"hookSpecificOutput":{"hookEventName":"PreToolUse"}}'
    
    emit_passthrough_and_exit() {
        printf '%s\n' "$PASS_THROUGH"
        exit 0
    }
    
    # --- Resolve the guard script from THIS launcher's own location (codex P1) ---------------
    # CC substitutes ${CLAUDE_PLUGIN_ROOT} into the hook COMMAND text before the shell, but does
    # NOT guarantee it as an env var inside this script. So compute the guard path from $0.
    # (No production env override: the guard path is ALWAYS derived from the launcher's own
    # location. Tests that need a broken/alternate guard run the launcher from a temp plugin
    # layout, so there is no production back door — P2-e.)
    # shellcheck disable=SC1007  # `CDPATH= cd` is intentional: clear CDPATH for this one cd only
    SELF_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) || emit_passthrough_and_exit
    GUARD="$SELF_DIR/../scripts/ars_write_scope_guard.py"
    
    # --- Read the payload from stdin ONCE (we must replay it to the guard subprocess) ---------
    # Known trade-off (gemini round-6 P2, accepted): the payload is held in a shell variable and
    # replayed with `printf '%s'`. `printf` is a builtin so it is NOT bound by ARG_MAX, and the
    # stripped trailing newline is irrelevant to the guard's JSON parse, so for ordinary hook
    # payloads this is safe. A multi-megabyte Write payload on a POSIX shell that caps variable
    # length is the narrow case this does not cover; buffering to a private temp file would handle
    # it but adds another temp-file lifecycle (and symlink surface) to a hot path, so it is left as
    # documented degradation rather than fixed speculatively.
    PAYLOAD=$(cat)
    
    # --- Marker: did this candidate start real Python? ---------------------------------------
    # Each candidate runs one Python process (#1015, below) whose first output is the marker line.
    # A 0-byte Store stub fails to execute / prints nothing, so it is skipped. We bound each run
    # so a broken-but-hanging interpreter can't wedge the hot path (spec §3.3): prefer `timeout`
    # when present, else a portable process-group watchdog.
    MARKER=ARS_PY_OK
    END_MARKER=ARS_PY_END
    NL='
    '
    # Per-candidate (and guard) wall-clock bound, seconds. A small ops knob; validated to be a
    # bare integer so it can't smuggle anything into the `timeout`/`sleep` args. Default 3.
    PROBE_BOUND=${ARS_PROBE_BOUND:-3}
    case "$PROBE_BOUND" in
        ''|*[!0-9]*) PROBE_BOUND=3 ;;
    esac
    
    # ARS_GUARD_FORCE_WATCHDOG=1 forces the no-`timeout` watchdog path even on hosts that HAVE
    # `timeout`. This is a test/debug switch: it only changes the BOUNDING MECHANISM (timeout
    # binary vs process-group watchdog), never the security decision — both paths enforce the
    # same wall-clock bound and the same pass-through-on-overrun posture. Honored if set; safe
    # to leave unset (the default prefers a usable `timeout` binary when present).
    #
    # #970: a `timeout` on PATH is used only if it accepts the GNU form we call it with
    # (`timeout <N>s cmd`). On Git for Windows, `timeout` can resolve to the Windows built-in
    # timeout.exe (`/T <seconds>`), which rejects that form and exits non-zero; trusting mere
    # existence failed every bounded call, so no Python was ever found and every write passed
    # through. A present-but-foreign `timeout` now takes the watchdog fallback, like a missing one.
    # Decided once per launch, not per bounded call. `-k 1s` bounds the probe itself at about 2s
    # even if the `true` on PATH hangs and ignores SIGTERM; a `timeout` without `-k` fails the
    # probe and also takes the fallback, so the probe can never disable the guard.
    TIMEOUT_USABLE=
    if [ -z "${ARS_GUARD_FORCE_WATCHDOG:-}" ] && command -v timeout >/dev/null 2>&1 \
            && timeout -k 1s 1s true </dev/null >/dev/null 2>&1; then
        TIMEOUT_USABLE=1
    fi
    have_timeout() {
        [ -n "$TIMEOUT_USABLE" ]
    }
    
    # Reserved exit status meaning "the bounded command was killed for overrunning its bound".
    TIMEOUT_STATUS=124
    
    # Run "$@" with a wall-clock bound; its stdout flows to OUR stdout (capture via $(...)).
    # Returns the command's real exit status, or $TIMEOUT_STATUS if it overran the bound.
    # Stdin for "$@" is whatever the caller arranges (we redirect it per call site) — the guard
    # call site PIPES the payload in, so the bounded command MUST keep that stdin.
    run_bounded() {
        if have_timeout; then
            # GNU timeout exits 12

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.

@imbad0202
Ships withacademic-research-skills

A comprehensive suite of Claude Code skills for academic research, covering the full pipeline from research to publication.

Stars on GitHub

Momentum

stars in total
56.2k
Star history of Imbad0202/academic-research-skills on GitHub, a chart by star-history.com

More plugins that ship hooks.

synthadoc

synthadoc

Ingests PDFs, Word and PowerPoint files, images, Markdown and plain text into a searchable knowledge base for research. Suits individuals and teams building a document-backed knowledge store.

10 skills1 hook2k
@axoviq-ai@axoviq-ai
Install Plugin
science-superpowers

science-superpowers

Guides your AI research agent through a disciplined analysis workflow, from framing a question and planning the analysis before touching data, to investigating anomalies, running parallel checks and executing a pre-registered plan with review checkpoints.

16 skills1 hook365
@k-dense-ai@k-dense-ai
Install Plugin
co-researcher

co-researcher

Co-Researcher is an academic research plugin for Claude Code, Gemini CLI, OpenAI Codex and OpenCode. It runs literature reviews, systematic reviews, peer review and citation checks inside the AI assistant you already use.

15 skills+2138
@poemswe@poemswe
Install Plugin
research-council

research-council

A Claude Code plugin that orchestrates deep research across two coding agents, Claude Code and Codex CLI (OpenAI), running in parallel with cross-pollination refinement and final synthesis.

1 hook+1107
@hamelsmu@hamelsmu
Install Plugin

Questions about the hooks in academic-research-skills.

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