hooks

SKILL.md

<tool_restrictions>

MANDATORY Tool Restrictions

REQUIRED TOOLS — use these, do not skip:

  • AskUserQuestion — REQUIRED for all user choices (Biome install options).

BANNED TOOLS — calling these is a skill violation:

  • EnterPlanMode — BANNED. Do NOT call this tool. This skill has its own structured process. Execute the steps below directly.
  • ExitPlanMode — BANNED. You are never in plan mode. </tool_restrictions>

Step 0: Handle --remove flag

If the user passed --remove:

  1. Read .claude/settings.json
  2. Remove all Arc-installed hooks (identified by comments or known commands)
  3. Write back the cleaned settings
  4. Report what was removed
  5. Done — skip all other steps

Step 1: Detect Biome

grep -q '"@biomejs/biome"' package.json 2>/dev/null

If Biome is in package.json: Continue to Step 2.

If Biome is NOT found:

AskUserQuestion:
  question: "Biome not found in package.json. Arc hooks require Biome for auto-formatting and linting. How would you like to proceed?"
  header: "Biome Required"
  options:
    - label: "Install Biome and continue"
      description: "Add @biomejs/biome as a dev dependency and set up all hooks"
    - label: "Skip formatting hooks"
      description: "Install context monitor and git guard only, skip Biome-dependent hooks"
    - label: "Cancel"
      description: "Exit without installing any hooks"

If user picks "Install Biome and continue":

# Detect package manager from lockfile
if [ -f pnpm-lock.yaml ]; then
  pnpm add -D @biomejs/biome
elif [ -f yarn.lock ]; then
  yarn add -D @biomejs/biome
else
  npm install -D @biomejs/biome
fi

Then check for biome.json / biome.jsonc. If missing:

npx @biomejs/biome init

If user picks "Skip formatting hooks": Set SKIP_BIOME=true, continue to Step 3.

If user picks "Cancel": Stop. Do not install any hooks.

Step 2: Verify Biome works

./node_modules/.bin/biome --version

If this fails, the binary isn't available. Tell the user and offer to reinstall.

Also check for biome config:

ls biome.json biome.jsonc 2>/dev/null

If no config exists, note this — biome will use defaults, which is fine.

Step 3: Build the hooks config

Build the hooks object to merge into .claude/settings.json.

Biome format hook (PostToolUse, Edit|Write):

{
  "matcher": "Edit|Write|NotebookEdit",
  "hooks": [
    {
      "type": "command",
      "command": "jq -r '.tool_input.file_path // .tool_input.filePath // empty' | { read file_path; case \"$file_path\" in *.js|*.ts|*.jsx|*.tsx|*.json|*.jsonc|*.css|*.graphql) ./node_modules/.bin/biome format --write \"$file_path\" 2>/dev/null || true ;; esac; }"
    }
  ]
}

Biome lint hook (Stop):

{
  "hooks": [
    {
      "type": "command",
      "command": "git diff --name-only --diff-filter=d HEAD 2>/dev/null | grep -E '\\.(js|ts|jsx|tsx|json|jsonc|css|graphql)$' | xargs -r ./node_modules/.bin/biome check --fix --unsafe 2>/dev/null || true"
    }
  ]
}

TypeScript check hook (Stop):

Only include this if the project has TypeScript (tsconfig.json exists).

{
  "hooks": [
    {
      "type": "command",
      "command": "npx tsc --noEmit 2>&1 | tail -20 || true"
    }
  ]
}

Git guard hook (PreToolUse, Bash):

This hook blocks destructive git operations before they execute. Always install — not dependent on Biome.

{
  "matcher": "Bash",
  "hooks": [
    {
      "type": "command",
      "command": "jq -r '.tool_input.command' | grep -qE 'git\\s+(reset\\s+--hard|push\\s+(-f|--force)|clean\\s+-f|checkout\\s+\\.)' && echo '{\"decision\":\"block\",\"reason\":\"Destructive git operation blocked by Arc hooks. Ask the user first.\"}' || true"
    }
  ]
}

Context monitor hook (PostToolUse, all tools):

Determine the absolute path to Arc's hooks/ directory by resolving the Arc install root from this skill's location. Use that resolved path as ${ARC_HOOKS_PATH}.

Read hooks/arc-context-monitor.js from the resolved Arc install root to confirm it exists.

{
  "matcher": "",
  "hooks": [
    {
      "type": "command",
      "command": "node ${ARC_HOOKS_PATH}/arc-context-monitor.js"
    }
  ]
}

Where ${ARC_HOOKS_PATH} is the resolved absolute path to the Arc plugin's hooks/ directory.

Statusline hook:

{
  "type": "command",
  "command": "node ${ARC_HOOKS_PATH}/arc-statusline.js"
}

If SKIP_BIOME is true: Only include the git guard, context monitor, and statusline hooks. The tsc hook is independent of Biome — include it if tsconfig.json exists.

Step 4: Read existing settings

cat .claude/settings.json 2>/dev/null

If file doesn't exist:

mkdir -p .claude

Start with an empty object {}.

If file exists: Parse the JSON. Preserve ALL existing fields (permissions, enabledMcpjsonServers, enableAllProjectMcpServers, enabledPlugins, etc.).

Step 5: Merge hooks into settings

This is the critical step. NEVER clobber existing hooks — merge with them.

Read the existing hooks object (may be undefined).

For PreToolUse:

  • Get existing hooks.PreToolUse array (or empty array)
  • Check if an Arc git guard hook already exists (command contains git.*reset.*--hard)
  • Add only if it doesn't exist

For PostToolUse:

  • Get existing hooks.PostToolUse array (or empty array)
  • Check if an Arc biome format hook already exists (command contains biome format)
  • Check if an Arc context monitor hook already exists (command contains arc-context-monitor)
  • Add new entries only if they don't already exist
  • Biome format hook and context monitor hook are separate entries (different matchers)

For Stop:

  • Get existing hooks.Stop array (or empty array)
  • Check if an Arc biome lint hook already exists (command contains biome check)
  • Check if an Arc tsc hook already exists (command contains tsc --noEmit)
  • Add each only if it doesn't exist
  • If no tsconfig.json in the project, skip the tsc hook

For Statusline:

  • Get existing hooks.Statusline array (or empty array)
  • Check if Arc statusline already exists (command contains arc-statusline)
  • Add only if it doesn't exist

Write the merged settings back: Use the Write tool to write the complete JSON (pretty-printed with 2-space indent).

CRITICAL: Preserve all non-hook fields exactly as they were. Do not add, remove, or modify anything outside the hooks key.

Step 6: Verify installation

Read back .claude/settings.json and confirm the hooks are present.

Count installed hooks:

  • PreToolUse entries
  • PostToolUse entries
  • Stop entries
  • Statusline entries

Step 7: Report

Arc hooks installed in .claude/settings.json

  PreToolUse  (Bash)        →  blocks destructive git ops (force push, reset --hard)
  PostToolUse (Edit|Write)  →  biome format --write on edited file
  PostToolUse (all tools)   →  context monitor (warns at 35%/25% remaining)
  Stop                      →  biome check --fix --unsafe on all changed files
  Stop                      →  tsc --noEmit (if tsconfig.json exists)
  Statusline                →  context bar showing usage

Hooks run automatically — zero token cost, zero agent effort.

To remove: /arc:hooks --remove

If SKIP_BIOME was true:

Arc hooks installed in .claude/settings.json

  PreToolUse  (Bash)        →  blocks destructive git ops (force push, reset --hard)
  PostToolUse (all tools)   →  context monitor (warns at 35%/25% remaining)
  Statusline                →  context bar showing usage

Biome hooks skipped (not installed). Run /arc:hooks again after adding Biome.

To remove: /arc:hooks --remove
Weekly Installs
1
Repository
howells/arc
GitHub Stars
14
First Seen
2 days ago
Installed on
amp1
cline1
opencode1
cursor1
kimi-cli1
codex1