The Mechanism Behind .cursor Rules for Agent Activation in Compound Engineering Plugin
The mechanism behind .cursor rules for agent activation converts Claude agents into Markdown-based Cursor rules through a five-step pipeline that parses agent definitions, transforms their content for Cursor compatibility, and writes them as .mdc files to the /.cursor/rules/ directory for on-demand runtime invocation.
The Compound Engineering Plugin bridges Claude's agent architecture with Cursor's rule-based system. Understanding the mechanism behind .cursor rules for agent activation reveals how AI assistants written for Claude's ecosystem become executable instructions within Cursor's editor environment.
How .cursor Rules Transform Claude Agents into Cursor-Compatible Instructions
The conversion process treats Claude agents as source material that must be normalized for Cursor's runtime. Each agent undergoes structural transformation where its body content, command references, and file paths are rewritten to match Cursor's rule syntax while preserving the original logic.
The Five-Step Agent Activation Flow
Step 1: Parsing Claude Plugin Definitions
The pipeline begins in src/parsers/claude.ts, where the system parses raw Claude plugin files into structured objects including ClaudeAgent, ClaudeCommand, and related entities. This parsing phase extracts agent names, descriptions, capabilities, and body content from the original .claude format.
Step 2: Agent-to-Rule Conversion
In src/converters/claude-to-cursor.ts, the convertAgentToRule function transforms each ClaudeAgent into a CursorRule object. This step generates a unique, normalized kebab-case name using uniqueName and normalizeName to prevent collisions. The function constructs frontmatter containing the description and alwaysApply: false, ensuring the rule requires explicit invocation.
Step 3: Content Transformation for Cursor Syntax
The transformContentForCursor function rewrites agent body content to match Cursor's expectations:
- Task calls: Converts
Task agent-name(args)syntax intoUse the <skill> skill to: argsformat - Slash commands: Flattens nested command namespaces for Cursor compatibility
- Path rewriting: Updates
~/.claude/and.claude/references to~/.cursor/and.cursor/ - Agent references: Transforms
@agent-namementions into "the<rule-name>rule" syntax
Step 4: Rule File Generation
The writeCursorBundle function in src/targets/cursor.ts persists the transformed rules to disk. It combines formatted frontmatter with the transformed body using formatFrontmatter, then writes each rule as <name>.mdc to the /.cursor/rules/ directory. This file-based contract enables Cursor's runtime to discover available rules.
Step 5: Runtime Activation and Execution
When a user types @<agent-name> or references "the <rule-name> rule" in a Cursor session, the editor resolves this reference against the files in /.cursor/rules/. Because the generated rules specify alwaysApply: false, Cursor loads the rule on demand rather than automatically. The rule's Markdown content, including any "## Capabilities" section added during conversion, executes as instructions guiding the AI's behavior.
Code Implementation: From Agent to Rule
Converting Agents with convertAgentToRule
The core conversion logic resides in src/converters/claude-to-cursor.ts:
function convertAgentToRule(agent: ClaudeAgent, usedNames: Set<string>): CursorRule {
const name = uniqueName(normalizeName(agent.name), usedNames) // → unique, kebab‑case name
const description = agent.description ?? `Converted from Claude agent ${agent.name}`
const frontmatter = {
description,
alwaysApply: false, // rule is not auto‑run
}
// body is transformed to Cursor‑compatible syntax
let body = transformContentForCursor(agent.body.trim())
if (agent.capabilities?.length) {
const caps = agent.capabilities.map(c => `- ${c}`).join('\n')
body = `## Capabilities\n${caps}\n\n${body}`.trim()
}
if (!body) body = `Instructions converted from the ${agent.name} agent.`
const content = formatFrontmatter(frontmatter, body) // ← front‑matter + body
return { name, content } // → CursorRule
}
Transforming Content for Cursor Compatibility
The transformContentForCursor function handles syntax normalization:
export function transformContentForCursor(body: string): string {
// 1️⃣ Task agent calls → “Use the <skill> skill to: …”
const taskPattern = /^(\s*-?\s*)Task\s+([a-z][a-z0-9-]*)\(([^)]+)\)/gm
body = body.replace(taskPattern, (_, p, a, args) =>
`${p}Use the ${normalizeName(a)} skill to: ${args.trim()}`)
// 2️⃣ Slash command flattening
const slashCmd = /(?<![:\w])\/([a-z][a-z0-9_:-]*?)(?=[\s,."')\]}`]|$)/gi
body = body.replace(slashCmd, (m, c) => (c.includes('/') ? m : `/${flattenCommandName(c)}`))
// 3️⃣ Path rewrite from .claude/ → .cursor/
body = body.replace(/~\/\.claude\//g, "~/.cursor/").replace(/\.claude\//g, ".cursor/")
// 4️⃣ @‑agent → “the <rule‑name> rule”
const agentRef = /@([a-z][a-z0-9-]*-(?:agent|reviewer|researcher|analyst|specialist|oracle|sentinel|guardian|strategist))/gi
body = body.replace(agentRef, (_, n) => `the ${normalizeName(n)} rule`)
return body
}
Example Output: A Generated .mdc Rule File
The conversion produces Markdown files with YAML frontmatter:
---
description: Review security aspects of the code base.
alwaysApply: false
---
## Capabilities
- Detect vulnerable dependencies
- Enforce least‑privilege policies
When you notice a risky pattern, **the security-reviewer rule** will suggest mitigations.
When a user types @security-reviewer in Cursor, the runtime locates this file in /.cursor/rules/ and executes the instructions.
Key Source Files and Their Roles
The implementation spans several modules in the Compound Engineering Plugin repository:
-
src/parsers/claude.ts– Parses Claude plugin definitions into structuredClaudeAgentobjects. -
src/converters/claude-to-cursor.ts– ContainsconvertAgentToRuleandtransformContentForCursor, handling the core logic for agent-to-rule conversion and content normalization. -
src/targets/cursor.ts– ImplementswriteCursorBundleto persist rules as.mdcfiles in the/.cursor/rules/directory. -
src/types/cursor.ts– Defines TypeScript interfaces includingCursorRule,CursorCommand, andCursorBundle. -
tests/cursor-converter.test.ts– Validates that Claude agents convert to correctly structured Cursor rules. -
tests/cursor-writer.test.ts– EnsureswriteCursorBundlecreates the expected directory layout and file formats.
Summary
- Agent activation relies on a file-based contract where Claude agents become Cursor rules stored in
/.cursor/rules/. - The
convertAgentToRulefunction insrc/converters/claude-to-cursor.tsgenerates unique, normalized rule names and setsalwaysApply: falseto enable on-demand loading. - Content transformation rewrites Task calls, slash commands, file paths, and agent references to match Cursor's expected syntax.
- Rules are persisted as
.mdcfiles with YAML frontmatter, allowing the Cursor runtime to resolve@<agent-name>references and execute the embedded Markdown instructions.
Frequently Asked Questions
What triggers a .cursor rule to activate?
A rule activates when a user references it by typing @<rule-name> or mentioning "the <rule-name> rule" in a Cursor prompt. Because the Compound Engineering Plugin generates rules with alwaysApply: false in the frontmatter, they do not run automatically and require explicit invocation by the user.
How does the conversion handle naming conflicts between agents?
The convertAgentToRule function in src/converters/claude-to-cursor.ts uses uniqueName and normalizeName utilities to generate kebab-case identifiers and checks them against a usedNames set. If a collision occurs, the function appends a suffix to ensure every rule file has a unique name, preventing filesystem and runtime conflicts.
Can .cursor rules auto-apply without user invocation?
No. The conversion process explicitly sets alwaysApply: false in the rule frontmatter. This design ensures that agents converted from Claude's architecture behave as on-demand tools rather than persistent background processes, matching Cursor's rule-based execution model where users control when specific capabilities are invoked.
What happens to Claude-specific syntax during conversion?
The transformContentForCursor function in src/converters/claude-to-cursor.ts systematically rewrites Claude-specific constructs: Task invocations become skill-based instructions, slash commands are flattened to simple commands, file paths migrate from .claude/ directories to .cursor/, and @agent-name references convert to "the <rule-name> rule" syntax. This ensures the resulting Markdown content is fully compatible with Cursor's rule engine.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →