How Agents Are Converted to Cursor Agent Requested Rules in Compound Engineering
When converting a Claude Code plugin to a Cursor bundle, each Claude agent becomes a separate .mdc rule file under .cursor/rules/ with alwaysApply: false and a descriptive field, creating an Agent Requested rule that Cursor only activates when relevant.
The EveryInc/compound-engineering-plugin repository provides a CLI tool that transforms Claude Code plugins into Cursor-compatible bundles. Understanding how agents are converted to Cursor Agent Requested rules is essential for developers migrating their AI-assisted workflows between these environments.
The Conversion Pipeline
The transformation begins in src/converters/claude-to-cursor.ts, where the convertClaudeToCursor function orchestrates the migration. For each agent defined in the Claude plugin, it invokes convertAgentToRule to generate a corresponding Cursor rule object.
This conversion adheres to the Cursor rule specification defined in docs/specs/cursor.md, specifically implementing the Agent Requested rule type characterized by three properties: alwaysApply: false, an empty globs array, and a populated description field.
Understanding the Agent Requested Rule Model
Cursor distinguishes between rule types based on when they should be applied to a conversation. The Agent Requested model delegates activation decisions to the AI itself:
| Rule type | alwaysApply |
globs |
description |
Meaning |
|---|---|---|---|---|
| Agent Requested | false |
empty | set | The AI decides whether to include the rule based on relevance of its description |
When alwaysApply is false and no file globs are specified, Cursor's runtime evaluates the rule's description against the current conversation context to determine relevance.
Step-by-Step Agent Transformation
The convertAgentToRule function implements a four-stage pipeline to transform Claude agents into Cursor Agent Requested rules.
Name Normalization and Deduplication
First, the agent's name undergoes normalization via normalizeName(agent.name), which converts the identifier to lowercase and hyphenates it for filesystem compatibility. The uniqueName utility then ensures this identifier remains unique across the entire plugin, preventing collisions when multiple agents might have similar names.
Front-Matter Construction
The rule's YAML front-matter is constructed with exactly two fields:
description: <agent description or fallback>
alwaysApply: false
Notably, the globs field is omitted entirely, which satisfies the Agent Requested model's requirement for an empty glob pattern. This structure is defined in src/converters/claude-to-cursor.ts between lines 35-38.
Body Content Transformation
The agent's body content passes through transformContentForCursor, which handles path rewrites, slash-command flattening, and other syntax adaptations necessary for Cursor compatibility. If the agent defines capabilities, these are prefixed to the body as a ## Capabilities section before final assembly.
Final Rule Assembly
The formatFrontmatter utility combines the YAML front-matter with the transformed body content to produce the rule's final content string. The resulting CursorRule object contains the normalized name and the formatted content, ready for filesystem output.
File Output and Bundle Generation
Once the conversion pipeline generates CursorRule objects, src/targets/cursor.ts handles the physical bundle creation. This module writes each rule to a separate .mdc file within the .cursor/rules/ directory of the output bundle.
The filename corresponds to the normalized, deduplicated rule name assigned during conversion. This file structure allows Cursor's IDE integration to discover and load these rules dynamically, applying them only when the Agent Requested logic determines relevance based on the conversation context.
Code Example
The following example demonstrates converting a Claude plugin containing a security review agent:
import { convertClaudeToCursor } from "./src/converters/claude-to-cursor";
const claudePlugin = {
agents: [
{
name: "Security Reviewer",
description: "Reviews code for security vulnerabilities and dependency risks",
body: "Analyze the provided code for:\n- SQL injection vectors\n- Unsafe dependency versions\n- Hardcoded secrets",
capabilities: ["code_analysis", "security_scanning"]
},
],
commands: [],
skills: [],
};
const cursorBundle = convertClaudeToCursor(claudePlugin, {});
// The resulting bundle contains one CursorRule:
// {
// name: "security-reviewer",
// content: `---
// description: Reviews code for security vulnerabilities and dependency risks
// alwaysApply: false
// ---
// ## Capabilities
// - code_analysis
// - security_scanning
//
// Analyze the provided code for:
// - SQL injection vectors
// - Unsafe dependency versions
// - Hardcoded secrets
// `
// }
When written to disk via src/targets/cursor.ts, this rule becomes .cursor/rules/security-reviewer.mdc and operates as an Agent Requested rule within Cursor.
Summary
- Conversion Entry Point: The
convertClaudeToCursorfunction insrc/converters/claude-to-cursor.tsorchestrates the transformation of Claude agents into Cursor rules. - Agent Requested Model: Converted rules set
alwaysApply: falseand omitglobs, allowing Cursor's AI to decide relevance based on thedescriptionfield. - Name Processing: Agents undergo normalization via
normalizeNameand deduplication viauniqueNameto generate filesystem-safe identifiers. - Content Transformation: Agent bodies pass through
transformContentForCursorto handle syntax adaptations, with optional capability sections prepended. - File Output: The
src/targets/cursor.tsmodule writes each rule as a separate.mdcfile under.cursor/rules/in the output bundle.
Frequently Asked Questions
What determines whether an Agent Requested rule is activated in Cursor?
Cursor's AI evaluates the description field of the rule against the current conversation context. If the description appears relevant to the user's query or the code being edited, the AI includes the rule's content in the context window. This differs from "Always Apply" rules which are included in every interaction, and "Glob Match" rules which activate based on file patterns.
Why are Claude agent names normalized and deduplicated during conversion?
The conversion process uses normalizeName to convert agent names into lowercase, hyphenated identifiers suitable for filesystem paths (e.g., "Security Reviewer" becomes "security-reviewer"). The uniqueName utility then ensures no two rules share the same filename, preventing collisions when multiple agents have similar names or when converting multiple plugins into the same bundle. This guarantees each .mdc file has a unique path under .cursor/rules/.
What happens to Claude agent capabilities during the conversion process?
If a Claude agent defines capabilities, the convertAgentToRule function prepends them to the rule body as a ## Capabilities section before the main content. This preserves the capability metadata in a format readable by Cursor, ensuring the AI understands what tools or functions the agent can access. The capabilities section appears after the YAML front-matter but before the transformed agent body content.
Where are the converted Cursor rules physically stored in the output bundle?
The src/targets/cursor.ts module handles the physical file system operations, writing each converted rule to a separate .mdc file within the .cursor/rules/ directory of the output bundle. Each filename corresponds to the normalized, deduplicated rule name generated during conversion (e.g., security-reviewer.mdc). This directory structure aligns with Cursor's native rule discovery mechanism, allowing the IDE to automatically detect and load these Agent Requested rules.
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 →