Skip to content

fix: prepend YAML frontmatter to Cursor .mdc files#1699

Merged
mnriem merged 2 commits intogithub:mainfrom
fsilvaortiz:fix/cursor-mdc-frontmatter
Feb 27, 2026
Merged

fix: prepend YAML frontmatter to Cursor .mdc files#1699
mnriem merged 2 commits intogithub:mainfrom
fsilvaortiz:fix/cursor-mdc-frontmatter

Conversation

@fsilvaortiz
Copy link
Contributor

Summary

  • Cursor IDE requires YAML frontmatter (alwaysApply: true) in .mdc rule files for auto-inclusion — without it, rules are silently ignored
  • Adds frontmatter generation to both scripts/bash/update-agent-context.sh and scripts/powershell/update-agent-context.ps1
  • Handles all three scenarios: new file creation, existing file without frontmatter, and existing file with frontmatter (no duplication)

Closes #669

Changes

  • scripts/bash/update-agent-context.sh: Added frontmatter prepend in create_new_agent_file() and update_existing_agent_file()
  • scripts/powershell/update-agent-context.ps1: Added frontmatter prepend in New-AgentFile and Update-ExistingAgentFile
  • tests/test_cursor_frontmatter.py: 7 new tests (3 static analysis + 4 integration)

Test plan

  • Static analysis: bash script contains .mdc frontmatter logic in both functions
  • Static analysis: PowerShell script contains .mdc frontmatter logic in both functions
  • Integration: new .mdc file starts with valid YAML frontmatter (---, alwaysApply: true, ---)
  • Integration: existing .mdc file without frontmatter gets it prepended on update
  • Integration: existing .mdc file with frontmatter does NOT get duplicated
  • Integration: non-.mdc files (e.g., Claude's CLAUDE.md) are NOT affected
  • Full test suite passes (102 tests)

🤖 Generated with Claude Code

Cursor IDE requires YAML frontmatter with `alwaysApply: true` in .mdc
rule files for them to be automatically loaded. Without this frontmatter,
users must manually configure glob patterns for the rules to take effect.

This fix adds frontmatter generation to both the bash and PowerShell
update-agent-context scripts, handling three scenarios:
- New .mdc file creation (frontmatter prepended after template processing)
- Existing .mdc file update without frontmatter (frontmatter added)
- Existing .mdc file with frontmatter (no duplication)

Closes github#669

🤖 Generated with [Claude Code](https://claude.com/code)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the agent-context update scripts to ensure Cursor IDE .mdc rule files include required YAML frontmatter (alwaysApply: true) so Cursor auto-applies the rules, and adds tests to prevent regressions (closes #669).

Changes:

  • Prepend Cursor YAML frontmatter when creating new .mdc agent rule files (bash + PowerShell).
  • Prepend Cursor YAML frontmatter when updating existing .mdc files that lack it, without duplicating existing frontmatter.
  • Add new test coverage (static checks + integration tests) validating .mdc frontmatter behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
scripts/bash/update-agent-context.sh Adds .mdc frontmatter prepending for new and updated Cursor rule files.
scripts/powershell/update-agent-context.ps1 Adds .mdc frontmatter prepending for new and updated Cursor rule files in PowerShell.
tests/test_cursor_frontmatter.py Adds static + integration tests asserting correct frontmatter behavior for Cursor .mdc files.
Comments suppressed due to low confidence (6)

scripts/bash/update-agent-context.sh:512

  • The frontmatter presence check only matches an exact '---' line. If an existing .mdc file uses CRLF line endings, the first line will be '---\r' and this will incorrectly prepend a second frontmatter block. Consider normalizing the first line (e.g., stripping '\r') or matching '^---\r?$' so CRLF files don’t get duplicated frontmatter.
    # Ensure Cursor .mdc files have YAML frontmatter for auto-inclusion
    if [[ "$target_file" == *.mdc ]]; then
        if ! head -1 "$temp_file" | grep -q '^---$'; then
            local frontmatter_file
            frontmatter_file=$(mktemp) || { rm -f "$temp_file"; return 1; }
            printf '%s\n' "---" "description: Project Development Guidelines" "globs: [\"**/*\"]" "alwaysApply: true" "---" "" > "$frontmatter_file"
            cat "$temp_file" >> "$frontmatter_file"
            mv "$frontmatter_file" "$temp_file"
        fi

scripts/powershell/update-agent-context.ps1:265

  • In New-AgentFile, $frontmatter is built with a trailing blank line (because the array includes ''), and then another NewLine is concatenated before $content. This results in two blank lines after the frontmatter delimiter. Consider removing the extra [Environment]::NewLine concatenation or removing the trailing '' element so the spacing is consistent with Update-ExistingAgentFile.
    # Prepend Cursor frontmatter for .mdc files so rules are auto-included
    if ($TargetFile -match '\.mdc$') {
        $frontmatter = @('---','description: Project Development Guidelines','globs: ["**/*"]','alwaysApply: true','---','') -join [Environment]::NewLine
        $content = $frontmatter + [Environment]::NewLine + $content
    }

tests/test_cursor_frontmatter.py:12

  • tempfile is imported but never used in this test module. Removing it avoids dead imports and keeps the test file tidy.
import os
import shutil
import subprocess
import tempfile
import textwrap

tests/test_cursor_frontmatter.py:45

  • This test reads a script file containing non-ASCII characters (e.g., the '✓' in log_success) using open(...) without an explicit encoding. On systems where the default encoding isn’t UTF-8, this can raise UnicodeDecodeError. Consider open(..., encoding="utf-8") here.

This issue also appears in the following locations of the same file:

  • line 50
  • line 67
        with open(SCRIPT_PATH) as f:
            content = f.read()
        assert 'if [[ "$target_file" == *.mdc ]]' in content

tests/test_cursor_frontmatter.py:53

  • Same as above: open(SCRIPT_PATH) without encoding="utf-8" can fail on non-UTF-8 default locales because the script includes non-ASCII characters.
        with open(SCRIPT_PATH) as f:
            content = f.read()
        # There should be two occurrences of the .mdc check — one per function
        occurrences = content.count('if [[ "$target_file" == *.mdc ]]')

tests/test_cursor_frontmatter.py:69

  • open(ps_path) should specify encoding="utf-8" for consistent cross-platform behavior; the PowerShell script may contain non-ASCII characters and locale defaults aren’t guaranteed to be UTF-8.
        with open(ps_path) as f:
            content = f.read()
        assert "alwaysApply: true" in content

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Handle CRLF line endings in frontmatter detection (grep '^---' instead
  of '^---$')
- Fix double blank line after frontmatter in PowerShell New-AgentFile
- Remove unused tempfile import from tests
- Add encoding="utf-8" to all open() calls for cross-platform safety

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@fsilvaortiz
Copy link
Contributor Author

Addressed Copilot's low-confidence suggestions in f227ab6:

  1. CRLF handling — Changed grep '^---$' to grep '^---' so frontmatter detection works with both LF and CRLF line endings
  2. Double blank line in PowerShell — Removed extra [Environment]::NewLine concatenation in New-AgentFile to avoid double spacing after frontmatter
  3. Unused tempfile import — Removed from test file
  4. encoding="utf-8" on open() calls — Added to all 3 open() calls in static analysis tests for cross-platform safety

All 7 tests passing.

🤖 Generated with Claude Code

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (4)

tests/test_cursor_frontmatter.py:263

  • test_non_mdc_file_has_no_frontmatter checks .claude/CLAUDE.md, but the bash script writes the Claude context to $REPO_ROOT/CLAUDE.md (repo root). As written, this test can pass without asserting anything (because it only asserts when the file exists), so it won’t catch regressions. Update the test to assert against git_repo / "CLAUDE.md" and require the file to exist before checking it doesn’t start with frontmatter.
        claude_file = git_repo / ".claude" / "CLAUDE.md"
        if claude_file.exists():
            content = claude_file.read_text()
            assert not content.startswith("---"), (
                "Non-mdc file should not have frontmatter"
            )

scripts/powershell/update-agent-context.ps1:347

  • The frontmatter duplication check uses $output[0] -ne '---'. If the existing file starts with a UTF-8 BOM (common with -Encoding utf8 in Windows PowerShell) the first line may be \uFEFF---, which would incorrectly trigger another frontmatter prepend. Consider normalizing the first line (trim BOM/whitespace) or using a regex like '^\uFEFF?---$' before deciding to insert.
    # Ensure Cursor .mdc files have YAML frontmatter for auto-inclusion
    if ($TargetFile -match '\.mdc$' -and $output.Count -gt 0 -and $output[0] -ne '---') {
        $frontmatter = @('---','description: Project Development Guidelines','globs: ["**/*"]','alwaysApply: true','---','')
        $output.InsertRange(0, $frontmatter)
    }

scripts/bash/update-agent-context.sh:365

  • mktemp is used to create frontmatter_file, but the file name doesn’t match the cleanup trap patterns (/tmp/agent_update_*_$$). If cat/mv fails (or the script exits due to set -e), this temp file can be left behind in /tmp. Prefer creating the temp file with a predictable prefix that the existing cleanup removes, or explicitly rm it on error.

This issue also appears on line 504 of the same file.

    # Prepend Cursor frontmatter for .mdc files so rules are auto-included
    if [[ "$target_file" == *.mdc ]]; then
        local frontmatter_file
        frontmatter_file=$(mktemp) || return 1
        printf '%s\n' "---" "description: Project Development Guidelines" "globs: [\"**/*\"]" "alwaysApply: true" "---" "" > "$frontmatter_file"
        cat "$temp_file" >> "$frontmatter_file"
        mv "$frontmatter_file" "$temp_file"
    fi

scripts/bash/update-agent-context.sh:512

  • Same temp-file cleanup issue as in create_new_agent_file(): frontmatter_file=$(mktemp) here won’t be removed by the existing cleanup trap if an error occurs during cat/mv (and set -e will abort). Use a prefix that matches the cleanup pattern or add explicit cleanup on failure.
    # Ensure Cursor .mdc files have YAML frontmatter for auto-inclusion
    if [[ "$target_file" == *.mdc ]]; then
        if ! head -1 "$temp_file" | grep -q '^---'; then
            local frontmatter_file
            frontmatter_file=$(mktemp) || { rm -f "$temp_file"; return 1; }
            printf '%s\n' "---" "description: Project Development Guidelines" "globs: [\"**/*\"]" "alwaysApply: true" "---" "" > "$frontmatter_file"
            cat "$temp_file" >> "$frontmatter_file"
            mv "$frontmatter_file" "$temp_file"
        fi

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@mnriem mnriem merged commit b55d00b into github:main Feb 27, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix specify-rules.mdc format for Cursor IDE

3 participants