🎯

Shfmt

v1.1.0

Validation and quality enforcement for shell scripts using shfmt.

Installation

Install han binary (required for hooks to work):

curl -fsSL https://han.guru/install.sh | bash

Then install this plugin:

han plugin install jutsu-shfmt

Overview

Validation and quality enforcement for shell scripts using shfmt, the shell parser, formatter, and interpreter.

What This Jutsu Provides

Validation Hooks

  • Format Validation: Runs shfmt -d on shell scripts to check formatting consistency
  • Validates scripts on session stop and when agents complete work
  • Only runs when shell files have changed (with --cached flag)
  • Non-zero exit if any files need formatting

Skills

This jutsu provides the following skills:

  • shfmt-configuration: Configuration files, EditorConfig integration, and project setup
  • shfmt-formatting: Formatting patterns, shell dialect support, and editor integration
  • shell-best-practices: Portable scripting, error handling, and secure coding patterns

Installation

Install via the Han marketplace:

han plugin install jutsu-shfmt

Or install manually:

claude plugin marketplace add thebushidocollective/han
claude plugin install jutsu-shfmt@han

Usage

Once installed, this jutsu automatically validates your shell script formatting:

  • When you finish a conversation with Claude Code
  • When Claude Code agents complete their work
  • Before commits (when combined with git hooks)

Manual Validation

Check formatting manually:

# Show diff of what would change
shfmt -d .

# List files that need formatting
shfmt -l .

# Format files in place
shfmt -w .

Configuring shfmt

Create a .shfmt.toml or shfmt.toml file in your project root:

# Shell dialect (posix, bash, mksh, bats)
shell = "bash"

# Indent with spaces (0 for tabs)
indent = 2

# Binary operators at start of line
binary-next-line = true

# Switch cases indented
switch-case-indent = true

Or use EditorConfig in .editorconfig:

[*.sh]
indent_style = space
indent_size = 2
shell_variant = bash
binary_next_line = true
switch_case_indent = true

Requirements

  • shfmt installed and available in PATH
  • Shell scripts with .sh or .bash extensions

Installing shfmt

macOS:

brew install shfmt

Ubuntu/Debian:

snap install shfmt

Go install:

go install mvdan.cc/sh/v3/cmd/shfmt@latest

Binary releases:

Download from GitHub releases.

Command Reference

CommandDescription
shfmt -d .Show diff of changes (validation)
shfmt -l .List files needing formatting
shfmt -w .Write formatted files in place
shfmt -i 2Use 2-space indentation
shfmt -ciIndent switch cases
shfmt -bnBinary ops on next line
shfmt -ln bashForce bash dialect

Supported Shell Dialects

shfmt supports multiple shell dialects:

DialectDescriptionShebang
posixPOSIX shell#!/bin/sh
bashBash#!/bin/bash or #!/usr/bin/env bash
mkshMirBSD Korn Shell#!/bin/mksh
batsBash Automated Testing#!/usr/bin/env bats

Overriding Hooks

Create a han-config.json in directories where you want to customize behavior:

{
  "hooks": {
    "jutsu-shfmt": {
      "format": {
        "enabled": false
      }
    }
  }
}

Or override the command:

{
  "hooks": {
    "jutsu-shfmt": {
      "format": {
        "command": "shfmt -d -i 4 ."
      }
    }
  }
}

CI/CD Integration

GitHub Actions

name: Shell Format Check
on: [push, pull_request]
jobs:
  shfmt:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install shfmt
        run: |
          curl -sS https://webinstall.dev/shfmt | bash
          echo "$HOME/.local/bin" >> $GITHUB_PATH
      - name: Check formatting
        run: shfmt -d .

Pre-commit

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/scop/pre-commit-shfmt
    rev: v3.8.0-1
    hooks:
      - id: shfmt

Differences from ShellCheck

ToolPurposeFocus
shfmtFormatterCode style, consistency
ShellCheckLinterBugs, pitfalls, best practices

Both tools complement each other. Use ShellCheck for catching bugs and shfmt for consistent formatting.

Contributing

See CONTRIBUTING.md for guidelines.

License

MIT License - See LICENSE for details.

Skills

Hooks

⚠

Token Usage Notice

Hooks run automatically during Claude Code sessions and their output is sent to the model for processing. This may increase token usage and associated costs. Consider disabling hooks you don't need via han-config.yml.

🛑

Stop

Runs when the main Claude Code agent has finished responding. Can verify task completion, check quality gates, or ensure documentation requirements are met before the session ends.

🛑

SubagentStop

Runs when a Claude Code subagent (Task tool call) has finished responding. Can validate subagent outputs, enforce quality standards, or trigger additional workflows after delegated tasks complete.