Recent Cursor builds on Mac ignore all git-ignored files, including those in .git/info/exclude. This broke ai-rizz’s local mode, which relies on .git/info/exclude to keep personal rules out of commits while making them visible to Cursor.
The fix: a --hook-based-ignore flag that uses a pre-commit hook instead of git excludes.
The Problem#
ai-rizz has two modes:
-
Local mode: Personal rules in
.cursor/rules/local/, git-ignored via .git/info/exclude
-
Commit mode: Team rules in
.cursor/rules/shared/, committed to the repository
The .git/info/exclude approach worked because it kept files out of commits without hiding them from Cursor. Mac Cursor’s new behavior broke this assumption.
The Solution#
When initialized with --hook-based-ignore, local mode:
- Skips adding files to
.git/info/exclude
- Installs a pre-commit hook that unstages local files before each commit
- Leaves files visible to Cursor (and
git status)
The hook reads the manifest dynamically to find which files to unstage:
# Find local manifest in repo root
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
LOCAL_MANIFEST=""
for file in "$REPO_ROOT"/*.local.skbd; do
[ -f "$file" ] && LOCAL_MANIFEST=$(basename "$file") && break
done
[ -z "$LOCAL_MANIFEST" ] && exit 0
# Parse target directory from manifest
MANIFEST_PATH="$REPO_ROOT/$LOCAL_MANIFEST"
TARGET_DIR=$(head -n1 "$MANIFEST_PATH" 2>/dev/null | cut -f2)
[ -z "$TARGET_DIR" ] && exit 0
# Unstage local files
git reset HEAD -- "$TARGET_DIR/local/" "$LOCAL_MANIFEST" 2>/dev/null || true
This works with custom manifest names and target directories since it reads from the manifest itself.
Mode Switching#
Users can switch between modes idempotently:
# Switch to hook-based
ai-rizz init --local --hook-based-ignore
# Switch back to regular
ai-rizz init --local
Switching from regular to hook-based removes .git/info/exclude entries and installs the hook. Switching back does the reverse.
The Trade-off#
Hook-based mode leaves a “dirty” git status:
$ git status
On branch main
Untracked files:
(use "git add <file>..." to include in what will be committed)
.cursor/rules/local/
ai-rizz.local.skbd
This may conflict with tooling that expects a clean status. But for Mac users whose Cursor can’t see local rules otherwise, it’s the only option until Cursor changes behavior.
Implementation Details#
The hook preserves existing user hooks by wrapping the ai-rizz section in BEGIN/END markers. On deinit, only the ai-rizz section is removed.
The validate_git_exclude_state() function now checks for hook presence before warning about missing git excludes - if the hook exists, files don’t need to be in .git/info/exclude.
Usage#
# Initialize with hook-based mode
ai-rizz init https://github.com/user/rules.git --local --hook-based-ignore
# Add rules as normal
ai-rizz add rule my-rule.mdc --local
# Files remain visible to Cursor but won't be committed
The hook is harmless if files are already git-ignored (it becomes a no-op), so it could theoretically run in all local mode setups. For now, it’s opt-in via the flag.