fix: prepend YAML frontmatter to Cursor .mdc files#1699
Conversation
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>
There was a problem hiding this comment.
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
.mdcagent rule files (bash + PowerShell). - Prepend Cursor YAML frontmatter when updating existing
.mdcfiles that lack it, without duplicating existing frontmatter. - Add new test coverage (static checks + integration tests) validating
.mdcfrontmatter 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
tempfileis 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. Consideropen(..., 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)withoutencoding="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 specifyencoding="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>
|
Addressed Copilot's low-confidence suggestions in f227ab6:
All 7 tests passing. 🤖 Generated with Claude Code |
There was a problem hiding this comment.
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_frontmatterchecks.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 againstgit_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 utf8in 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
mktempis used to createfrontmatter_file, but the file name doesn’t match the cleanup trap patterns (/tmp/agent_update_*_$$). Ifcat/mvfails (or the script exits due toset -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 explicitlyrmit 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 duringcat/mv(andset -ewill 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.
Summary
alwaysApply: true) in.mdcrule files for auto-inclusion — without it, rules are silently ignoredscripts/bash/update-agent-context.shandscripts/powershell/update-agent-context.ps1Closes #669
Changes
scripts/bash/update-agent-context.sh: Added frontmatter prepend increate_new_agent_file()andupdate_existing_agent_file()scripts/powershell/update-agent-context.ps1: Added frontmatter prepend inNew-AgentFileandUpdate-ExistingAgentFiletests/test_cursor_frontmatter.py: 7 new tests (3 static analysis + 4 integration)Test plan
.mdcfrontmatter logic in both functions.mdcfrontmatter logic in both functions.mdcfile starts with valid YAML frontmatter (---,alwaysApply: true,---).mdcfile without frontmatter gets it prepended on update.mdcfile with frontmatter does NOT get duplicated.mdcfiles (e.g., Claude'sCLAUDE.md) are NOT affected🤖 Generated with Claude Code