[BUG] Claude Code does not report errors in custom slash commands in a user-friendly, useful form

Resolved 💬 3 comments Opened Oct 18, 2025 by behrangsa Closed Oct 19, 2025

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

I reformatted the front-matter for one of my custom slash commands to look like this:

---
description: >
  Lorem ipsum
allowed-tools:
  - Bash(git reset:*)
  - Bash(git status:*)
  - Bash(git diff:*)
  - Bash(git diff --staged:*)
  - Bash(git diff --cached:*)
  - Bash(git branch:*)
  - Bash(git log:*)
  - Bash(git add:*)
  - Bash(git commit:*)
  - Bash(git commit --amend:*)
  - Bash(git show:*)
---

Now Claude Code thinks my custom slash command doesn't have the permission to use any tools.

A related issue is reported in #4695.

What Should Happen?

As long as the front-matter is valid YAML, Claude Code should parse it correctly and respect it.

Error Messages/Logs

I asked CC to do some tasks and then call `/commit`:


● Now let me commit the current changes using the /commit slash command:
  ⎿  Error: Bash command permission check failed for pattern "!`
       - `": Command appears to be an incomplete fragment (starts with flags)
  ⎿  Interrupted · What should Claude do instead?


I explicitly ran `/commit`:


> /commit
  ⎿  Error: Bash command permission check failed for pattern "!`git reset`": This command requires approval

Steps to Reproduce

Use this custom slash command:

~~~md
---
description: >
Create intelligent, well-structured commits for the Rust Book project
with automatic validation and project-aware categorization
allowed-tools:

  • Bash(git reset:*)
  • Bash(git status:*)
  • Bash(git diff:*)
  • Bash(git diff --staged:*)
  • Bash(git diff --cached:*)
  • Bash(git branch:*)
  • Bash(git log:*)
  • Bash(git add:*)
  • Bash(git commit:*)
  • Bash(git commit --amend:*)
  • Bash(git show:*)
  • Bash(just validate:*)
  • Bash(cargo build:*)
  • Bash(cargo run:*)
  • Bash(filterdiff:*)
  • Bash(command:*)
  • Bash(cat:*)
  • Bash(fmt:*)
  • Read
  • Grep
  • Glob
  • TodoWrite

---

Intelligent Commit Creation for Rust Book

Create well-structured commits for "Mastering Rust for Java Programmers" with automatic validation, smart categorization, and project-aware commit messages.

Context

  • Track all untracked files that are not git ignored: !git ls-files -z --others --exclude-standard | xargs -0 -r git add
  • Unstage all currently staged changes, but keep them in the working directory: !git reset
  • Current git status: !git status
  • Current git diff: !git diff HEAD
  • Current branch: !git branch --show-current
  • Recent commits: !git log --oneline -10

Your Task

Based on the above context, commit the changes for this Rust programming book project.

  • For complex multi-commit workflows, use the TodoWrite tool to track each commit you plan to make
  • If all changes are related, commit them together with a single, clear commit message
  • If there are multiple unrelated changes, stage and commit them separately with distinct commit messages
  • If a single file contains multiple unrelated changes (different hunks):
  1. Check if filterdiff is available: command -v filterdiff
  2. If available, use filterdiff to selectively stage hunks:

```bash
# Generate diff for the file
git diff HEAD -- <file> > /tmp/file.diff

# Extract specific hunks (e.g., hunks 1 and 3 for one commit)
filterdiff --hunks=1,3 /tmp/file.diff > /tmp/selected.diff

# Apply to staging area
git apply --cached /tmp/selected.diff

# Commit the selected hunks
git commit -m "..."

# Repeat for remaining hunks
```

  1. If filterdiff is not available, inform the user that the file contains mixed changes and recommend installing patchutils or manually separating hunks using git add -p <file>
  • Always verify staged changes with git diff --staged before committing
  • Ensure commit messages are concise yet descriptive, following best practices
  • For non-trivial changes, always include a body explaining the what and why

Project Context

This Rust book uses:

  • Typst files in formats/typst/en_US/parts/ - Book content
  • Code examples in code/chap-XX/rust-examples/src/ - Runnable Rust code
  • Build system with justfile and Cargo.toml - Build automation
  • Documentation in CLAUDE.md, README.md - Project guidelines
  • Spiral Learning System - Progressive pedagogical approach
  • Target audience - Java programmers learning Rust

Commit Message Format

Structure

type(scope): Imperative description

[Body explaining what and why, not how]

Type System (Project-Specific)

  • content - Adding/updating chapters, sections in Typst files
  • example - Adding/modifying Rust code examples
  • fix - Correcting errors, typos, broken code, incorrect output comments
  • refactor - Restructuring code without changing functionality
  • style - Code formatting (cargo fmt), Typst formatting (typstyle)
  • build - Changes to justfile, Cargo.toml, or build configuration
  • docs - Updates to README.md, CLAUDE.md, or other documentation
  • chore - Maintenance tasks, dependencies, gitignore updates

Single Type Rule: Each commit MUST have exactly one type. If changes span multiple types (e.g., both content and examples), create separate commits for each type.

Scope Guidelines

  • Part X - Changes to a specific part
  • Part X, Chapter Y - Changes to specific chapter
  • All Parts - Changes across multiple parts
  • Omit scope for project-wide changes (build, docs, chore)

Subject Line Rules

  • Imperative mood - "Add feature" not "Added feature" or "Adds feature"
  • Lowercase after colon - fix: correct typo not fix: Correct typo
  • No period at end - docs: update README not docs: update README.
  • Under 72 characters (soft limit) - Be concise but clear

Body Rules

  • Required for non-trivial changes - Simple fixes can omit the body
  • Explain what and why - Not how (the diff shows how)
  • Use bullet points for multiple changes
  • Blank line between subject and body
  • Wrap at 72 characters for readability - Use fmt -w 72 or editor settings to enforce
  • Format consistently - Each paragraph should be properly wrapped, not just the first line

Commit Message Examples

Example 1: Single Type with Scope

content(Part 1): Add section on ownership and borrowing

Introduces ownership concepts with Java comparisons for easier
understanding by the target audience. Includes memory diagrams
showing heap vs stack allocation.

Example 2: Multiple Files, Single Type

example(Part 3): Add more code examples for Part 3

Added 2 practical examples:
- format_precision.rs - Floating point precision
- format_width.rs - Field width control

All examples include output comments verified by running the code.

Example 3: Fix with Detailed Body

fix(Part 4): Correct Display trait output comments

The output comments were showing incorrect values due to
outdated code. Updated after running:
  cargo run --bin point_display
  cargo run --bin temperature

Also fixed a typo in the chapter text explaining the trait.

Example 4: Simple Fix (No Body Needed)

fix(Part 2): Correct typo in println macro explanation

Example 5: Project-Wide Change

style: Format all Rust code and update justfile

- Applied cargo fmt to all code examples in Parts 1-5

Example 6: Documentation Only

docs: Enhance CLAUDE.md with quick reference section

Added essential commands cheat sheet and project structure
diagram for easier onboarding of AI agents and contributors.

Validation Before Committing

For Code Examples

# Validate the affected part
cd code/chap-XX/rust-examples
cargo build --all

# Or validate all parts
just validate

For Typst Changes

# Build the book to ensure it compiles
just build

Important Notes

  • Several chapters contain intentional compilation errors for pedagogical purposes:
  • code/chap-01/rust-examples/src/placeholder_mismatch.rs - Placeholder count mismatch
  • code/chap-01/rust-examples/src/ownership_scope.rs - Ownership violation
  • code/chap-01/rust-examples/src/exclamation_mark.rs - Missing macro !
  • code/chap-02/rust-examples/src/point_no_display.rs - Missing Display trait
  • code/chap-03/rust-examples/src/struct_no_debug.rs - Missing Debug trait
  • code/chap-03/rust-examples/src/tuple_no_display.rs - Tuples don't implement Display
  • code/chap-04/rust-examples/src/point_no_display.rs - Missing Display trait
  • All code examples MUST include // Output: or // Error: comments
  • Error comments in Chapters 3+ should only show primary error line and location
  • Always run code to verify output comments before committing

Commit Workflow Patterns

Pattern 1: Content + Examples (Separate Commits)

When adding a new section with accompanying code examples, commit them separately:

# First commit - Content
git add formats/typst/en_US/parts/part-02/chap-01.typ
git commit -m "$(cat <<'EOF'
content(Part 2): Add section on print vs println macros

Explains the difference between print! and println! macros,
their buffering behavior, and when to use each variant.
Includes Java comparisons for familiar reference points.
EOF
)"

# Second commit - Examples
git add code/chap-02/rust-examples/src/print_example.rs
git add code/chap-02/rust-examples/Cargo.toml
git commit -m "$(cat <<'EOF'
example(Part 2): Add print/println demonstration code

Implements practical examples showing:
- Basic print! vs println! usage
- Buffering behavior differences
- Flushing stdout manually
EOF
)"

Pattern 2: Separate Unrelated Changes

When changes span different concerns:

# First commit - Content changes
git add formats/typst/en_US/parts/part-02/*.typ
git commit -m "$(cat <<'EOF'
content(Part 2): Expand explanation of format strings

Added subsection explaining positional vs named arguments
with comparison to Java's String.format().
EOF
)"

# Second commit - Code examples
git add code/chap-02/rust-examples/src/*.rs
git add code/chap-02/rust-examples/Cargo.toml
git commit -m "$(cat <<'EOF'
example(Part 2): Add format argument demonstrations

Added three examples showing different argument styles:
- positional_args.rs - Positional arguments
- named_args.rs - Named arguments
- mixed_args.rs - Combining both styles
EOF
)"

# Third commit - Fixes
git add code/chap-03/rust-examples/src/debug_trait.rs
git commit -m "fix(Part 3): Update Debug trait output comment"

Pattern 3: Style Changes (Keep Separate)

Always separate formatting from content:

# Format first
just format
git add -u
git commit -m "style: Apply cargo fmt to all code examples"

# Then commit actual changes
git add <files>
git commit -m "content(Part X): ..."

Pattern 4: Using Selective Hunk Staging

When a file has unrelated changes in different hunks:

Identifying Hunks

First, examine the diff to identify which hunks contain which changes:

# View the diff with hunk headers
git diff HEAD -- CLAUDE.md

# Count the hunks (lines starting with @@)
git diff HEAD -- CLAUDE.md | grep -c "^@@"

# Examine each hunk to determine what it changes
# Hunks are numbered sequentially from 1
Staging Specific Hunks
# Check if filterdiff is available
command -v filterdiff

# Generate diff
git diff HEAD -- CLAUDE.md > /tmp/claude.diff

# Stage only documentation hunks (e.g., hunks 1,2,4)
filterdiff --hunks=1,2,4 /tmp/claude.diff > /tmp/selected.diff
git apply --cached /tmp/selected.diff
git commit -m "docs: Add slash commands documentation"

# Stage remaining hunks for separate commit
git add CLAUDE.md
git commit -m "docs: Update hard rules section"

Tip: If filterdiff is not available, use git add -p CLAUDE.md for interactive staging.

Special Commit Scenarios

Amending Commits

Only amend commits that haven't been pushed to a remote repository:

# Check if the last commit has been pushed
git status  # Look for "Your branch is ahead of 'origin/branch' by 1 commit"

# Amend to add forgotten files (keeps same message)
git add <forgotten-file>
git commit --amend --no-edit

# Amend to fix the commit message
git commit --amend -m "$(cat <<'EOF'
fix(Part 2): Correct ownership example

Fixed the borrowing demonstration to properly show
move semantics vs borrowing.
EOF
)"

# Amend to add changes AND update message
git add <files>
git commit --amend

WARNING: Never amend commits that have been pushed unless you're prepared to force-push and potentially disrupt other contributors.

Handling Merge Commits

Generally avoid merge commits by rebasing feature branches. When necessary:

# For feature branch merges
git merge --no-ff feature-branch -m "$(cat <<'EOF'
Merge 'feature-branch': Add comprehensive error handling

Integrates new error handling system across all chapters
with improved pedagogical examples showing common pitfalls.
EOF
)"

Work-in-Progress (WIP) Commits

For incomplete work that needs to be saved:

# Create a WIP commit (to be amended later)
git add .
git commit -m "WIP: [description of partial work]"

# Later, when work is complete, amend with proper message
git add <remaining-changes>
git commit --amend -m "$(cat <<'EOF'
content(Part 3): Add section on trait bounds

Explains trait bounds with Java generics comparisons
and practical examples of common constraints.
EOF
)"

Decision Tree

  1. Check current state:
  • Run git status to see uncommitted changes
  • Run git diff --staged to review staged changes
  • Run git log -1 to check if you need to amend
  1. Analyze changes:
  • Modified .typ files → Content change
  • Modified .rs files → Example change
  • Modified Cargo.toml or justfile → Build change
  • Modified .md files → Documentation change
  1. Determine relationship:
  • All changes same type → Single commit
  • Changes span multiple types → Separate commits (one per type)
  • Unrelated changes → Multiple commits
  • Mixed hunks in one file → Use filterdiff or git add -p
  1. Determine scope:
  • Single part affected → Use (Part X) scope
  • Multiple parts → Use (All Parts) or omit scope
  • Project-wide → Omit scope
  1. Write commit message:
  • Simple change → Subject line only
  • Complex change → Subject + detailed body
  • Use imperative mood, lowercase after colon
  • Keep subject under 72 characters
  • Wrap body text at 72 characters using fmt or editor settings
  1. Validate before committing:
  • Code changes → Run just validate
  • Typst changes → Run just build
  • Check output comments are accurate by running the code

Validation Checklist

  • [ ] Code examples compile (except intentional errors)
  • [ ] Output comments match actual output (run the code!)
  • [ ] Typst book builds successfully (just build)
  • [ ] Commit message follows format rules
  • [ ] Subject line under 72 characters
  • [ ] Uses imperative mood
  • [ ] Includes scope when applicable
  • [ ] Body included for non-trivial changes
  • [ ] All modified files staged in at least one commit
  • [ ] No unrelated changes staged together

Commit Message Guidelines

Soft Guidelines

  • Keep the first line under 72 characters when possible
  • Prefer smaller, atomic commits over large monolithic ones
  • When in doubt, add a body explaining the change
  • Use descriptive branch names that reflect the changes

Hard Requirements

The following are absolute requirements from .claude/hard-rules.md:

  • Single Type: Each commit MUST have exactly one type - never combine types
  • Staging: Every file must be part of at least one commit
  • Focus: Only stage related changes together (atomic commits)
  • Bodies: Non-trivial changes require explanatory body text
  • Validation: Always validate before committing (just validate for code, just build for content)
  • Types: Use only project-specific types (content, example, fix, etc. - never feat)

Quick Reference: Common Scenarios

| Scenario | Type | Scope | Example |
| ---------------------- | --------- | ---------- | ------------------------------------------ |
| Add chapter section | content | (Part X) | content(Part 1): Add ownership section |
| Add code example | example | (Part X) | example(Part 2): Add println demo |
| Add content + code: | | | |
| → First commit | content | (Part X) | content(Part 3): Add Debug trait section |
| → Second commit | example | (Part X) | example(Part 3): Add Debug trait demos |
| Fix typo | fix | (Part X) | fix(Part 1): Correct variable name |
| Fix output comment | fix | (Part X) | fix(Part 4): Update Display output |
| Run cargo fmt | style | Omit | style: Apply cargo fmt to all examples |
| Update justfile | build | Omit | build: Add format-check command |
| Update CLAUDE.md | docs | Omit | docs: Add commit conventions |
| Update .gitignore | chore | Omit | chore: Add build artifacts to gitignore |

Tips for Success

  • Read recent commits - Use git log --oneline -20 to follow established patterns
  • One type per commit - Never combine types; split content and examples into separate commits
  • Think atomically - One logical change per commit (can span multiple files if same type)
  • Explain why, not what - The diff shows what changed, the body explains why it was necessary
  • Verify everything - Run the code, build the book, check for errors before committing
  • Use descriptive scopes - Help readers quickly identify affected areas
  • Keep it focused - If you're listing more than 3-4 things in the body, consider splitting commits
  • Review staged changes - Always use git diff --staged as final check before commit
  • Use TodoWrite for complexity - Track multi-commit workflows with todo items
  • Format consistently - Use heredocs for multi-line messages, wrap body at 72 chars
  • Test intentional errors - Verify that pedagogical error examples still produce expected errors

~~~

Claude Model

Sonnet (default)

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.0.22

Platform

Anthropic API

Operating System

Other Linux

Terminal/Shell

Other

Additional Information

Add Ghostty to the list of terminals, as it is becoming increasingly popular.

View original on GitHub ↗

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