enforce-specs: exclude patterns don't match absolute file paths

Resolved 💬 3 comments Opened Apr 10, 2026 by LuisLadino Closed Apr 14, 2026

Problem

The enforce-specs hook is blocking edits to files in project-specific directories (e.g., projects/handshake/reviews/) even though .claude/specs/architecture/project-structure.md explicitly excludes those paths with the pattern projects/**.

When attempting to write or edit files under projects/, the hook fails with:

[BLOCKED] Read all required specs before editing.

But the specs file clearly marks projects/ as a project-specific location (outside kit-owned files), so these paths should not trigger spec-read enforcement.

Root Cause

In .claude/hooks/context/enforce-specs.cjs, the matchGlob function normalizes file paths by removing the leading slash: path.replace(/^\//, ''). However, it then attempts to match this absolute path against glob patterns that are relative paths.

When a path like /Users/luisladino/Repositories/Personal/my-brain/projects/handshake/reviews/... is normalized, it becomes Users/luisladino/... (still an absolute path without the leading slash). This is compared against the pattern projects/**, which compiles to the regex ^projects/.*.

Since the normalized path doesn't START with projects/, it fails to match, even though it contains that path component. The applies_to patterns work because they use **/*.md which compiles to .*\.md and matches anywhere in the path.

Reproduction

  1. Create or edit a file under projects/handshake/reviews/
  2. Observe: enforce-specs hook blocks the edit even though specs file excludes projects/**
  3. Expected: File should be editable without triggering spec-read enforcement

Proposed Solutions

Option A: Strip path down to project root

Before matching against glob patterns, detect if the path contains a project root and extract only the relative portion from there:

let matchPath = filePath;
if (filePath.includes('/projects/')) {
  matchPath = filePath.split('/projects/')[1];
  matchPath = 'projects/' + matchPath;
}

Then match matchPath against the glob patterns. This ensures paths like projects/... match the projects/** exclude pattern correctly.

Option B: Use glob matching library with proper path handling

Replace the custom matchGlob implementation with a robust glob library (e.g., minimatch or micromatch) that correctly handles both absolute and relative paths by design.

Impact

Currently, any project-specific work that requires file creation or editing in the projects/ directory triggers unnecessary spec-enforcement. This affects review workflows, testing, and documentation tasks that fall outside the kit scope.

View original on GitHub ↗

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