Feature Request: Support Sequential, Conditional, and Chainable Hooks for Advanced Workflows

Resolved 💬 3 comments Opened Jul 25, 2025 by coygeek Closed Jan 4, 2026

Title: Feature Request: Support Sequential, Conditional, and Chainable Hooks for Advanced Workflows

Labels: enhancement, feature-request, hooks

Body

Summary & Problem

The current hook system in Claude Code is a powerful feature for automation. However, its capabilities are limited by the parallel execution model, as stated in the official documentation:

All matching hooks run in parallel — en/docs/claude-code/hooks.md

This parallel-only execution prevents developers from creating multi-step, sequential workflows where the output of one hook must be piped as the input to the next. A common developer pipeline, such as formatting code and then linting it (prettier -> eslint), is impossible to configure declaratively and requires writing a single, monolithic external script.

Furthermore, any logic to determine if a hook should run (e.g., only in a CI environment or only on a specific git branch) must be implemented imperatively inside the hook script itself. This adds boilerplate and moves workflow logic out of the declarative settings.json configuration, reducing clarity and maintainability.

This feature request proposes a comprehensive enhancement to the hook system to support sequential execution, I/O chaining, and declarative conditional logic directly within the settings.json configuration.

---

Proposed Solution

We propose introducing a new sequence key within the hook configuration in .claude/settings.json. The presence of this key would define an ordered pipeline of "steps" to be executed sequentially for a given event and matcher, complementing the existing hooks key which would retain its parallel execution behavior.

This new model would have three core components:

1. Sequential Execution & I/O Chaining

A sequence block would define an array of commands that run in serial. The standard I/O would behave like a Unix pipeline:

  • The stdout of command n in the sequence is piped to the stdin of command n+1.
  • The stdin for the first command in the sequence will be the primary content payload for the event (e.g., for a PostToolUse event on the Write tool, this would be the raw file content from tool_input.content). This avoids the need for boilerplate JSON parsing in simple scripts.
  • The final stdout from the last command in the sequence is passed back to Claude Code for processing, following the existing rules for hook output (e.g., structured JSON or plain text).
  • Error Handling: If any command in the sequence exits with a non-zero status code, the entire sequence terminates immediately. The stderr and exit code from the failing command are passed back to Claude Code.

2. Conditional Execution

Each step within a sequence can contain an optional conditions block. The step will only be executed if all of its conditions are met. This allows for creating robust, context-aware workflows.

Proposed conditions:

  • git_branch: The current git branch must match the provided string or regex.
  • env_var_exists: A specific environment variable must be set.
  • file_exists: A file or list of files must exist at the specified path(s) relative to the project root.

3. Variable Substitution

Context variable substitution (e.g., {tool_input.file_path}) will be available to all commands within the sequence, allowing any step to access the initial event context.

---

Proposed Configuration Example

Here is a proposed structure in .claude/settings.json for a format-then-lint workflow that runs on a Write tool operation. This example combines sequential execution with conditional logic.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write",
        "sequence": [
          {
            "description": "Format code with Prettier if a config file is present.",
            "command": "prettier --write --stdin-filepath {tool_input.file_path}",
            "conditions": {
              "file_exists": [".prettierrc", ".prettierrc.json", ".prettierrc.js"]
            }
          },
          {
            "description": "Lint the formatted code with ESLint and return JSON results.",
            "command": "eslint --stdin --stdin-filename {tool_input.file_path} --format json"
          }
        ]
      },
      {
        "matcher": "Write",
        "hooks": [
          {
            "description": "Send a notification to Slack only when in a CI environment.",
            "command": "./scripts/notify-slack.sh 'File {tool_input.file_path} was written in CI.'",
            "conditions": {
              "env_var_exists": "CI"
            }
          }
        ]
      }
    ]
  }
}

Note: In this example, the sequence for formatting and linting would run, and in parallel, the separate hooks block would run its single (conditional) notification hook.

---

Alternatives Considered

The primary alternative is to write a single, complex shell script that internally manages the prettier | eslint pipeline and all conditional logic. This is then called from a single hook.

This approach has several disadvantages:

  • Reduced Readability: It moves workflow logic out of the declarative settings.json configuration, making it harder to understand the automation at a glance.
  • Less Modular: A sequence feature allows for composing small, single-purpose tools. The alternative requires building and maintaining monolithic scripts.
  • Increased Maintenance: Requires managing separate scripts and their dependencies alongside the Claude Code configuration, increasing overhead.

---

Benefits

This enhancement would transform hooks from simple event triggers into a first-class workflow automation engine within Claude Code.

  • Enables Complex Workflows: Allows for building sophisticated, multi-stage data processing, validation, and formatting pipelines directly in settings.json.
  • Improves Modularity & Reusability: Developers can define small, focused, single-purpose commands and compose them into powerful sequences.
  • Enhances Declarative Configuration: Keeps the entire workflow definition within settings.json, improving transparency, readability, and maintainability.
  • Reduces Scripting Boilerplate: Moves conditional logic (e.g., if [ -f ".prettierrc" ]) from shell scripts into the configuration file, making individual hook commands simpler.
  • Enables Context-Specific Automation: Allows for different hook behaviors for different environments (local vs. CI) and project states without requiring complex scripting.

Thank you for considering this powerful enhancement to the hooks system.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗