Shell Hooks Module for Amplifier

January 26, 2026 · View on GitHub

Add shell-based extensibility to Amplifier with hooks that execute at lifecycle points. Uses Claude Code's proven hook format for compatibility with their ecosystem.

Overview

This module enables shell command hooks in Amplifier projects. Hooks can validate, format, block, or inject context into agent execution—all through simple shell scripts.

What it provides:

  • Shell-based hooks at tool and session lifecycle points
  • Regex pattern matching for selective execution
  • Parallel hook execution for performance
  • Prompt-based hooks for LLM evaluation
  • Skill-scoped hooks (hooks embedded in SKILL.md)
  • Security controls (timeouts, exit code handling)
  • Claude Code format compatibility

Quick Start

Installation

Add to your Amplifier bundle:

# bundle.yaml
hooks:
  - module: hook-shell
    source: git+https://github.com/microsoft/amplifier-module-hook-shell@main

Create Your First Hook

  1. Create hooks directory:
mkdir -p .amplifier/hooks
  1. Create hooks.json:
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Bash command detected' >&2 && exit 0"
          }
        ]
      }
    ]
  }
}

That's it! The hook will run before every Bash tool execution.

Hook Format

Uses Claude Code's JSON hook format for compatibility:

{
  "hooks": {
    "EventName": [
      {
        "matcher": "ToolPattern",
        "parallel": false,
        "hooks": [
          {
            "type": "command",
            "command": "path/to/script.sh",
            "timeout": 30
          }
        ]
      }
    ]
  }
}
FieldDescription
matcherRegex pattern: "Bash", "Edit|Write", ".*"
parallelRun hooks concurrently (default: false)
type"command" or "prompt"
commandShell command or script path
timeoutSeconds before timeout (default: 30)

Supported Events

EventWhen It FiresCan BlockContext Injection
PreToolUseBefore tool executionYesYes
PostToolUseAfter tool completionNoYes
UserPromptSubmitUser submits promptYesYes
NotificationAgent sends notificationNoNo
StopAgent stops executionNoNo
SubagentStartSubagent spawnedNoNo
SubagentStopSubagent completedNoNo
SessionStartSession initializationNoNo
SessionEndSession cleanupNoNo

Hook Input/Output

Input (stdin)

Hooks receive JSON on stdin:

{
  "tool_name": "Bash",
  "tool_input": {
    "command": "ls -la",
    "description": "List files"
  },
  "session_id": "abc-123",
  "timestamp": "2026-01-09T20:15:19Z"
}

Output

Exit codes:

  • 0 - Success, allow operation
  • 2 - Block operation (blocking events only)
  • Other - Error (treated as allow with warning)

JSON output (optional, on stdout):

{
  "decision": "approve",
  "reason": "Explanation",
  "systemMessage": "Message to user",
  "contextInjection": "Feedback to inject into agent context"
}

Parallel Execution

Run multiple hooks concurrently for better performance:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": ".*",
        "parallel": true,
        "hooks": [
          {"type": "command", "command": "./notify-slack.sh"},
          {"type": "command", "command": "./update-metrics.sh"},
          {"type": "command", "command": "./sync-logs.sh"}
        ]
      }
    ]
  }
}

Parallel behavior:

  • All hooks start simultaneously
  • For blocking events: short-circuits on first block decision
  • Exceptions are caught and logged, don't fail the group
  • Default is sequential (parallel: false)

Prompt-Based Hooks

Use LLM evaluation for complex decisions:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "prompt",
            "prompt": "Review this bash command for security issues. Output JSON with 'decision' (approve/block) and 'reason'.",
            "timeout": 60
          }
        ]
      }
    ]
  }
}

Prompt hooks:

  • Send tool context + your prompt to the configured LLM
  • LLM returns JSON with decision
  • Useful for nuanced evaluation (security review, code quality)
  • Higher latency than command hooks—use selectively

Note: Prompt hooks require provider configuration. Currently uses the session's default provider. A future enhancement will allow specifying a fast/cheap model override.

Skill-Scoped Hooks

Embed hooks directly in skill definitions:

---
name: python-guardian
description: Enforces Python best practices
hooks:
  PostToolUse:
    - matcher: "Edit|Write"
      hooks:
        - type: command
          command: "ruff check --fix $FILE_PATH"
---

# Python Guardian

This skill enforces Python code quality...

How it works:

  1. When a skill is loaded, its hooks are registered automatically
  2. Hooks only active while skill is in context
  3. Keeps enforcement rules with the skill that defines them

Requires amplifier-module-tool-skills with hooks support.

Environment Variables

Hooks have access to:

VariableDescription
AMPLIFIER_PROJECT_DIRProject root (from session.working_dir capability, or cwd)
AMPLIFIER_HOOKS_DIR.amplifier/hooks/ directory
AMPLIFIER_SESSION_IDCurrent session ID

Note: The project directory is determined by the session.working_dir coordinator capability when available, falling back to the current working directory for backward compatibility. This enables correct hook discovery in server/web deployments.

Example Hooks

See examples/hooks/ for complete examples:

bash-validator

Blocks dangerous bash commands:

cp -r examples/hooks/bash-validator .amplifier/hooks/

auto-formatter

Formats code after editing (Python, JS, Go, Rust):

cp -r examples/hooks/auto-formatter .amplifier/hooks/

linter

Runs linters and injects feedback:

cp -r examples/hooks/linter .amplifier/hooks/

Claude Code Compatibility

This module uses Claude Code's hook format, making it compatible with:

  • Claude Code plugins (copy hooks directory)
  • Shared hook scripts from their ecosystem
  • Existing Claude Code hook documentation

Note: We use .amplifier/hooks/ instead of .claude/hooks/ for Amplifier-native integration.

Security Considerations

Hooks run with your user permissions. Only install hooks from trusted sources.

Built-in protections:

  • Timeout enforcement (default 30s)
  • Process isolation (subprocess execution)
  • No privilege escalation
  • Exit code validation

Best practices:

  • Review hook code before installation
  • Use timeouts on all hooks
  • Test in non-production first
  • Use specific matchers (avoid .* when possible)

Documentation

Contributing

Note

This project is not currently accepting external contributions, but we're actively working toward opening this up. We value community input and look forward to collaborating in the future. For now, feel free to fork and experiment!

Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit Contributor License Agreements.

When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.

Trademarks

This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.