Applied Intelligence
Module 11: Skills, Hooks, and Automation

Exercise: Custom Skill and Automation Workflow

Build a practical automation toolkit: a custom skill for release preparation, hooks for quality gates, and parallel agent sessions using worktrees.

Overview

Gum is a command-line tool for building interactive shell scripts. It provides styled prompts, spinners, selection menus, and other UI components that transform basic scripts into polished developer tools. You will both work on the gum repository and use gum itself to build nicer scripts—the tool eating its own dog food.

Here is the situation: your team has ad-hoc manual release steps that vary by developer. You want to standardize this with a custom skill that guides the process, hooks that enforce quality gates, and worktrees for running parallel agent sessions.

You will:

  1. Clone the repository and create a custom skill for release preparation
  2. Configure hooks to enforce pre-commit quality gates
  3. Set up git worktrees for parallel agent execution
  4. Build a multi-stage workflow combining these components

Setup

Clone the repository

git clone https://github.com/charmbracelet/gum.git
cd gum

Install gum

Gum is required for the interactive scripts:

# macOS
brew install gum

# Debian/Ubuntu
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://repo.charm.sh/apt/gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/charm.gpg
echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | sudo tee /etc/apt/sources.list.d/charm.list
sudo apt update && sudo apt install gum

# Windows (scoop)
scoop install charm-gum

Verify installation:

gum --version

Verify Go installation

The gum repository is a Go project:

go version

If Go is not installed, install version 1.21 or later before proceeding.

The gum binary you installed is separate from the repository. You use the installed gum to build interactive scripts. The repository is the codebase you work on with Claude Code.

Phase 1: Create a custom skill

Build a skill that standardizes release preparation across your team.

Create the skill directory structure

mkdir -p .claude/skills/release-prep

Create the SKILL.md file

Create .claude/skills/release-prep/SKILL.md:

---
name: release-prep
description: Prepares a release by running tests, generating changelog, and creating version tags. Use when preparing a new release or when asked to create a release.
argument-hint: [version-type]
disable-model-invocation: true
allowed-tools: Bash, Read, Edit
---

## Objective

Guide the release preparation process with proper validation and documentation.

## Steps

1. **Validate environment**
   - Verify working directory is clean (no uncommitted changes)
   - Confirm on the main branch
   - Ensure all tests pass

2. **Determine version bump**
   - If version type provided as argument, use it
   - Otherwise, analyze commits since last tag to suggest type
   - Version types: patch (bug fixes), minor (new features), major (breaking changes)

3. **Generate changelog**
   - List commits since last tag
   - Group by type (feat, fix, docs, etc.)
   - Format as markdown

4. **Create release**
   - Update version in relevant files
   - Create git tag
   - Provide summary of changes

## Conventions

- Follow semantic versioning (MAJOR.MINOR.PATCH)
- Tag format: v1.2.3
- Changelog entries should be concise and user-focused
- Do not push to remote—leave that decision to the developer

Verify skill discovery

Start Claude Code and check that the skill appears:

claude

Inside Claude Code:

/release-prep

The skill should be listed. Type /release-prep patch to invoke it (or cancel if you prefer to test later).

The disable-model-invocation: true setting ensures this skill only runs when explicitly invoked with /release-prep. Without this, Claude might trigger it whenever release-related topics come up in conversation.

Test the skill

In Claude Code, invoke the skill:

/release-prep patch

Watch what happens:

  • Does Claude validate the environment?
  • Does it check for uncommitted changes?
  • Does it analyze commits appropriately?

Write down any issues for refinement.

AspectObservation
Environment validation
Commit analysis
Version handling
Areas to improve

Phase 2: Configure quality gate hooks

Hooks enforce standards automatically. Configure a pre-commit hook that runs quality checks.

Create the hooks directory

mkdir -p .claude/hooks

Create the quality gate script

Create .claude/hooks/pre-commit-check.sh:

#!/bin/bash
set -e

# Skip in CI environments
if [ -n "$CI" ]; then
    exit 0
fi

# Get the files being edited
FILE="$1"

# Only check Go files
if [[ ! "$FILE" =~ \.go$ ]]; then
    exit 0
fi

# Check if gofmt would make changes
if ! gofmt -l "$FILE" | grep -q .; then
    exit 0
fi

# Formatting needed - output to stderr for Claude to see
echo "File needs formatting: $FILE" >&2
echo "Run: gofmt -w $FILE" >&2
exit 2

Make it executable:

chmod +x .claude/hooks/pre-commit-check.sh

Configure the hook in Claude Code settings

Create or update .claude/settings.json:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/pre-commit-check.sh \"$CLAUDE_FILE_PATH\""
          }
        ]
      }
    ]
  }
}

Hook exit code 2 blocks the operation and shows the stderr message to Claude. Exit code 0 allows the operation to proceed. Test hooks carefully before relying on them.

Test the hook

Start a new Claude Code session (hooks load at session start):

claude

Ask Claude to make a change to a Go file with intentionally bad formatting:

Add a comment to gum.go with inconsistent spacing

Watch for:

  • Does the hook detect the formatting issue?
  • Does Claude see the feedback?
  • Does Claude attempt to fix the formatting?
TestResult
Hook executed after edit?
Formatting issue detected?
Feedback visible to Claude?
Claude attempted correction?

Phase 3: Set up parallel agent workflow

Git worktrees let you run multiple agent sessions on different tasks simultaneously.

Create the worktree setup script

Create scripts/setup-parallel.sh:

#!/bin/bash
set -e

# Styled header using gum
gum style \
    --border double \
    --padding "1" \
    --foreground 212 \
    "Parallel Agent Workflow Setup"

# Get current branch
BASE_BRANCH=$(git branch --show-current)
echo "Base branch: $BASE_BRANCH"

# Define tasks
TASKS=(
    "docs:Update documentation"
    "tests:Add test coverage"
    "refactor:Code cleanup"
)

# Let user select tasks
echo ""
SELECTED=$(printf '%s\n' "${TASKS[@]}" | gum choose --no-limit --header "Select tasks to run in parallel:")

if [ -z "$SELECTED" ]; then
    gum log --level warn "No tasks selected"
    exit 0
fi

# Create worktree directory
WORKTREE_BASE="../gum-worktrees"
mkdir -p "$WORKTREE_BASE"

# Create worktrees for selected tasks
echo ""
gum style --foreground 10 "Creating worktrees..."

echo "$SELECTED" | while IFS=: read -r task_id task_desc; do
    BRANCH_NAME="agent-$task_id"
    WORKTREE_PATH="$WORKTREE_BASE/$BRANCH_NAME"

    # Check if worktree already exists
    if [ -d "$WORKTREE_PATH" ]; then
        gum log --level warn "Worktree exists: $BRANCH_NAME (skipping)"
        continue
    fi

    gum spin --spinner dot --title "Creating: $BRANCH_NAME" -- \
        git worktree add -b "$BRANCH_NAME" "$WORKTREE_PATH" "$BASE_BRANCH" 2>/dev/null

    gum log --level info "Created: $BRANCH_NAME$WORKTREE_PATH"
done

# Show status
echo ""
gum style --foreground 212 "Worktree Status:"
git worktree list

# Instructions
echo ""
gum style \
    --border rounded \
    --padding "1" \
    "To start agents, open a new terminal for each worktree and run 'claude'"

Make it executable:

chmod +x scripts/setup-parallel.sh

Run the setup script

./scripts/setup-parallel.sh

Select at least two tasks. Verify worktrees are created:

git worktree list

Start parallel agent sessions

Open separate terminal windows for each worktree. In each terminal:

cd ../gum-worktrees/agent-docs  # or agent-tests, agent-refactor
claude

Give each agent a task:

Documentation agent:

Review the README.md and suggest improvements for the installation section.
Make the changes if appropriate.

Tests agent:

Find functions in the filter package that lack test coverage.
Suggest which functions would benefit most from tests.

Let both agents work simultaneously. Each has isolated context and working directory.

Monitor progress

Create scripts/worktree-status.sh:

#!/bin/bash

gum style --border double --foreground 212 "Worktree Status"
echo ""

for wt in $(git worktree list --porcelain | grep "^worktree " | cut -d' ' -f2); do
    # Skip main worktree
    if [ "$wt" = "$(pwd)" ]; then
        continue
    fi

    BRANCH=$(git -C "$wt" branch --show-current 2>/dev/null)
    CHANGES=$(git -C "$wt" status --short 2>/dev/null | wc -l | tr -d ' ')
    AHEAD=$(git -C "$wt" rev-list main.."$BRANCH" --count 2>/dev/null || echo "0")

    if [ "$CHANGES" -gt 0 ]; then
        gum style --foreground 214 "● $BRANCH: $CHANGES uncommitted, $AHEAD commits ahead"
    else
        gum style --foreground 10 "○ $BRANCH: clean, $AHEAD commits ahead"
    fi
done

Make executable and run:

chmod +x scripts/worktree-status.sh
./scripts/worktree-status.sh
WorktreeStatusChanges
agent-docs
agent-tests
agent-refactor

Phase 4: Build the integrated workflow

Combine skills, hooks, and parallel execution into a complete workflow.

Create the workflow skill

Create .claude/skills/parallel-tasks/SKILL.md:

---
name: parallel-tasks
description: Orchestrates parallel agent tasks using git worktrees. Use when multiple independent tasks need to run simultaneously.
argument-hint: [task-list-file]
disable-model-invocation: true
allowed-tools: Bash, Read
---

## Objective

Set up and monitor parallel agent execution across git worktrees.

## Prerequisites

- Git worktrees created via scripts/setup-parallel.sh
- Each worktree on its own feature branch
- Base branch (main) is clean

## Workflow

1. **Status check**
   - Run scripts/worktree-status.sh
   - Report which worktrees have changes

2. **Task assignment guidance**
   - List available worktrees
   - Suggest task distribution based on branch names
   - Provide commands to start agents in each worktree

3. **Integration preparation**
   - When tasks complete, list branches ready for merge
   - Check for conflicts between branches
   - Suggest merge order based on dependencies

## Notes

- Each worktree has isolated context (200K tokens)
- Agents do not share conversation history
- Use files for state that must persist across agents
- Monitor with scripts/worktree-status.sh

Test the complete workflow

  1. Invoke the parallel-tasks skill:
/parallel-tasks
  1. Follow the guidance to check worktree status

  2. Start agents in separate terminals

  3. Monitor progress with the status script

  4. When complete, review what each agent produced

Cleanup worktrees

After completing the exercise:

# Remove worktrees
git worktree remove ../gum-worktrees/agent-docs --force
git worktree remove ../gum-worktrees/agent-tests --force
git worktree remove ../gum-worktrees/agent-refactor --force

# Remove branches if desired
git branch -D agent-docs agent-tests agent-refactor

Verify cleanup:

git worktree list

Analysis

Custom skill effectiveness

QuestionYour answer
Did the skill guide the release process effectively?
What instructions were unclear or incomplete?
How would you improve the skill for your team?
Was disable-model-invocation the right choice?

Hook behavior

QuestionYour answer
Did the hook detect formatting issues?
Was the feedback actionable for Claude?
Did exit code 2 block operations as expected?
What other hooks would be valuable?

Parallel execution

QuestionYour answer
How many agents did you run simultaneously?
Did worktree isolation work correctly?
How did you coordinate between agents?
What challenges arose from parallel execution?

Workflow integration

QuestionYour answer
How natural was the skill → hook → worktree flow?
Where did components not fit together well?
What would you add for production use?

Success criteria

  • Custom release-prep skill created with SKILL.md
  • Skill discoverable via /release-prep
  • Skill invoked and observed behavior documented
  • Quality gate hook created and configured
  • Hook tested with intentional formatting issue
  • Worktree setup script created and executed
  • At least two parallel agent sessions started
  • Worktree status monitoring script created
  • Parallel-tasks skill created
  • Complete workflow tested end-to-end
  • Worktrees cleaned up after exercise
  • Analysis section completed

Variations

Variation A: CI-aware skill

Modify the release-prep skill to detect CI environments:

## Environment Detection

Check for CI environment variables:
- If $CI is set, use non-interactive mode
- Skip confirmation prompts in CI
- Use provided arguments instead of interactive selection

Test by setting CI=true before invoking the skill.

Variation B: Approval hook

Add a hook that requires human confirmation for certain operations:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/confirm-dangerous.sh"
          }
        ]
      }
    ]
  }
}

The hook script checks if the command involves rm, git push, or other sensitive operations.

Variation C: Result aggregation

Create a script that collects results from all worktrees:

#!/bin/bash
# scripts/aggregate-results.sh

OUTPUT="parallel-summary.md"
echo "# Parallel Task Results" > "$OUTPUT"
echo "" >> "$OUTPUT"

for wt in $(git worktree list --porcelain | grep "^worktree " | cut -d' ' -f2); do
    BRANCH=$(git -C "$wt" branch --show-current 2>/dev/null)
    if [ -z "$BRANCH" ] || [ "$BRANCH" = "main" ]; then
        continue
    fi

    echo "## $BRANCH" >> "$OUTPUT"
    git -C "$wt" log main.."$BRANCH" --pretty=format:"- %s" >> "$OUTPUT"
    echo "" >> "$OUTPUT"
done

cat "$OUTPUT"

Use this to prepare a merge summary.

Variation D: Skill composition

Create a skill that invokes other skills:

---
name: full-release
description: Complete release workflow including parallel tasks and release prep
disable-model-invocation: true
---

## Workflow

1. Invoke /parallel-tasks to set up worktrees for:
   - Documentation updates
   - Test additions
   - Changelog preparation

2. Monitor until all tasks complete

3. Aggregate results from worktrees

4. Invoke /release-prep with the determined version type

5. Generate release summary

This shows how skills can call other skills in sequence.

Variation E: Metrics collection

Add a hook that logs execution metrics:

#!/bin/bash
# .claude/hooks/log-metrics.sh

LOG_FILE=".claude/metrics.jsonl"
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
TOOL="$CLAUDE_TOOL_NAME"
DURATION="$CLAUDE_DURATION_MS"

echo "{\"timestamp\":\"$TIMESTAMP\",\"tool\":\"$TOOL\",\"duration_ms\":$DURATION}" >> "$LOG_FILE"
exit 0

Configure as a PostToolUse hook and analyze the resulting data.

Takeaways

Custom skills formalize team knowledge. The release-prep skill encodes a workflow that would otherwise exist only in documentation or tribal knowledge. When the skill runs, every team member follows the same process.

Hooks give you guarantees that LLM instructions cannot. The formatting hook runs every time, regardless of how Claude interprets its system prompt. This determinism matters for quality gates. Formatting standards, security checks, and compliance requirements cannot be "usually" enforced—they have to be always enforced.

Parallel execution multiplies context capacity. Each worktree agent has a fresh 200K token context window. Three parallel agents have three times the working memory of a single agent grinding through sequential tasks. The tradeoff is coordination overhead—agents do not share context, so you need to design for that isolation.

Worktrees are what make isolation work. Branches alone are not enough—agents would conflict on file modifications. Worktrees give you physical isolation while keeping git history connected. The merge order becomes important: which branch lands first affects conflict resolution for the others.

Skills and hooks fit together well. The release-prep skill can rely on hooks to enforce formatting. The parallel-tasks skill can delegate to setup scripts. Each component has a clear job, and the boundaries are explicit in the file structure.

The skill system changed recently. Slash commands and skills merged in January 2026. Hot reload means no restart friction. The Agent Skills open standard means skills can work across tools. Understanding these changes helps you build skills that align with where the platform is going.

Gum makes a real difference. The gap between a bare echo "Select task:" and a styled gum choose menu matters for developer experience. Scripts become tools developers want to use rather than avoid. This affects adoption—automation that feels polished gets used.

Exit code 2 is the blocking signal. Hooks that return 0 allow the operation. Hooks that return 2 block it and surface stderr to Claude. Other exit codes log warnings but do not block. This convention is not obvious from general shell scripting but is critical for effective hooks.

On this page