Skip to content

feat: native Cursor IDE integration#301

Merged
danielmeppiel merged 3 commits intomainfrom
feat/cursor-integration
Mar 14, 2026
Merged

feat: native Cursor IDE integration#301
danielmeppiel merged 3 commits intomainfrom
feat/cursor-integration

Conversation

@danielmeppiel
Copy link
Collaborator

@danielmeppiel danielmeppiel commented Mar 14, 2026

Summary

Adds full Cursor IDE support as the third native integration target alongside GitHub Copilot and Claude. When a .cursor/ directory exists in a project, apm install deploys primitives in Cursor's native formats — no compilation step needed.

Closes #302

Primitive Mapping

APM Primitive Cursor Destination Format
Instructions (.instructions.md) .cursor/rules/*.mdc applyTo:globs: frontmatter conversion
Agents (.agent.md) .cursor/agents/*.md Markdown with YAML frontmatter
Skills (SKILL.md) .cursor/skills/{name}/SKILL.md Identical (agentskills.io standard)
Hooks (.json) .cursor/hooks.json + .cursor/hooks/{pkg}/ Merged JSON with _apm_source tracking
MCP servers .cursor/mcp.json Standard mcpServers JSON

Architecture

  • TargetProfile data layer (targets.py): Data-driven target definitions — adding a new target = adding a dict entry to KNOWN_TARGETS, not creating new classes
  • Opt-in pattern: Cursor integration only activates when .cursor/ directory exists (same as Claude)
  • .cursor-plugin/plugin.json detection for consuming Cursor-native plugin repositories
  • BaseIntegrator updated with .cursor/ prefixes and partition buckets for install/uninstall
  • Full wiring in install.py (3 code paths) and uninstall.py (sync + re-integration)

New Files

File Purpose
src/apm_cli/integration/targets.py TargetProfile, PrimitiveMapping, KNOWN_TARGETS
src/apm_cli/adapters/client/cursor.py CursorClientAdapter for .cursor/mcp.json
tests/unit/test_cursor_mcp.py 13 MCP adapter tests

Tests

73 new tests across 5 test files:

  • 18 skill integrator tests (opt-in, deployment, sub-skills, sync, multi-target)
  • 13 agent integrator tests (deployment, frontmatter, multi-target, sync)
  • 21 instruction/rules tests (.mdc conversion, frontmatter mapping, collision detection)
  • 8 hook integrator tests (merge, additive, script copy, sync cleanup)
  • 13 MCP adapter tests (factory, config path, read/write/merge, opt-in)

1758 total tests passing.

Docs

8 pages updated to reflect Cursor as a native integration target (no longer "compile-only"):

  • how-it-works.md, compilation.md, teams.md, adoption-playbook.md
  • skills.md, plugins.md, ide-tool-integration.md, what-is-apm.md

Add full Cursor support as the third integration target alongside
GitHub Copilot and Claude. When a .cursor/ directory exists, apm install
deploys primitives in Cursor's native formats:

- Instructions → .cursor/rules/*.mdc (applyTo: → globs: conversion)
- Agents → .cursor/agents/*.md
- Skills → .cursor/skills/{name}/SKILL.md
- Hooks → .cursor/hooks.json (merged with _apm_source tracking)
- MCP → .cursor/mcp.json (CursorClientAdapter)

Architecture:
- TargetProfile data layer (targets.py) for scalable multi-target design
- Opt-in pattern: only deploys when .cursor/ already exists
- .cursor-plugin/plugin.json detection for Cursor-native plugin repos
- BaseIntegrator updated with .cursor/ prefixes and partition buckets
- Full install/uninstall wiring across all 3 code paths

Tests: 73 new tests (18 skill, 13 agent, 8 hook, 21 rules, 13 MCP)
Docs: 8 pages updated to reflect Cursor as native integration target

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 14, 2026 17:37
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 adds native Cursor IDE integration as the third target alongside GitHub Copilot and Claude. When a .cursor/ directory exists in a project, apm install deploys primitives in Cursor's native formats (rules .mdc, agents, skills, hooks, MCP) — no compilation needed.

Changes:

  • Adds TargetProfile data layer and CursorClientAdapter for data-driven multi-target architecture and Cursor MCP support
  • Extends all integrators (instructions, agents, skills, hooks) with Cursor-specific deployment methods and wires them into install/uninstall flows
  • Updates 8 documentation pages and CHANGELOG to reflect Cursor as a native integration target

Reviewed changes

Copilot reviewed 31 out of 32 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/apm_cli/integration/targets.py New data-driven target profile definitions (TargetProfile, PrimitiveMapping, KNOWN_TARGETS)
src/apm_cli/adapters/client/cursor.py New CursorClientAdapter for .cursor/mcp.json management
src/apm_cli/integration/base_integrator.py Add .cursor/ integration prefixes and partition buckets
src/apm_cli/integration/instruction_integrator.py Add Cursor Rules (.mdc) conversion and deployment
src/apm_cli/integration/agent_integrator.py Add Cursor agent deployment to .cursor/agents/
src/apm_cli/integration/skill_integrator.py Add Cursor skill deployment to .cursor/skills/
src/apm_cli/integration/hook_integrator.py Add Cursor hook integration to .cursor/hooks.json
src/apm_cli/integration/mcp_integrator.py Add Cursor to MCP runtime detection and stale cleanup
src/apm_cli/commands/install.py Wire Cursor integration into all 3 install code paths
src/apm_cli/commands/uninstall.py Wire Cursor cleanup and re-integration during uninstall
src/apm_cli/factory.py Register CursorClientAdapter in ClientFactory
src/apm_cli/utils/helpers.py Add .cursor-plugin/plugin.json detection
src/apm_cli/deps/github_downloader.py Add .cursor-plugin/plugin.json validation
src/apm_cli/core/target_detection.py Update target descriptions for Cursor
src/apm_cli/integration/__init__.py Export new target types
tests/unit/test_cursor_mcp.py 13 MCP adapter tests
tests/unit/test_mcp_client_factory.py Add cursor to supported types
tests/unit/test_helpers.py Add cursor plugin.json tests
tests/unit/integration/test_skill_integrator.py 18 Cursor skill tests
tests/unit/integration/test_instruction_integrator.py 21 Cursor rules tests
tests/unit/integration/test_hook_integrator.py 8 Cursor hook tests
tests/unit/integration/test_agent_integrator.py 13 Cursor agent tests
docs/src/content/docs/*/ 8 doc pages updated
CHANGELOG.md Unreleased entry for Cursor integration
Comments suppressed due to low confidence (1)

src/apm_cli/commands/install.py:660

  • The commands integration block (lines 647–660) is indented inside the for tp in cursor_agent_result.target_paths: loop body. This means the Claude commands integration only runs when cursor_agent_result.target_paths is non-empty — i.e., only when Cursor agents were deployed. If there are no Cursor agent target paths (e.g., .cursor/ doesn't exist), the commands block is silently skipped entirely.

This was likely caused by inserting the Cursor agents block between the Claude agents block and the commands block without adjusting indentation. The commands block (and the closing of the if integrate_claude: guard that previously wrapped it) needs to be dedented back to the function's top indentation level.

        deployed.append(tp.relative_to(project_root).as_posix())

        # --- commands (.claude) ---
        command_result = command_integrator.integrate_package_commands(
            package_info, project_root,
            force=force, managed_files=managed_files,
            diagnostics=diagnostics,
        )
        if command_result.files_integrated > 0:
            result["commands"] += command_result.files_integrated
            _rich_info(f"  └─ {command_result.files_integrated} commands integrated → .claude/commands/")
        if command_result.files_updated > 0:
            _rich_info(f"  └─ {command_result.files_updated} commands updated")
        result["links_resolved"] += command_result.links_resolved
        for tp in command_result.target_paths:
            deployed.append(tp.relative_to(project_root).as_posix())

managed_files=_buckets["agents_cursor"] if _buckets else None)
agents_cleaned += result.get("files_removed", 0)

if Path(".github/skills").exists() or Path(".claude/skills").exists():
Comment on lines +96 to +103
# Known integration prefixes that APM is allowed to deploy/remove under.
# Derived from ``targets.KNOWN_TARGETS`` so the allow-list stays in sync.
@staticmethod
def _get_integration_prefixes() -> tuple:
from apm_cli.integration.targets import get_integration_prefixes
return get_integration_prefixes()

INTEGRATION_PREFIXES = (".github/", ".claude/", ".cursor/")
| GitHub Copilot | `.github/instructions/`, `.github/prompts/`, agents, hooks, plugins, MCP | `AGENTS.md` (optional) | **Full** |
| Claude | `.claude/` commands, skills, MCP | `CLAUDE.md` | **Full** |
| Cursor | | `.cursor/rules/` | Instructions via compile |
| Cursor | `.cursor/mcp.json` (MCP) | `.cursor/rules/` | MCP + Instructions |
Comment on lines +187 to +194
#### Cursor (`.cursor/`)

| Location | Purpose |
|----------|---------|
| `.cursor/rules/*.mdc` | Instructions converted to Cursor rules format |
| `.cursor/agents/*.md` | Sub-agents from installed packages |
| `.cursor/hooks.json` (hooks key) | Hooks from installed packages (merged into config) |
| `.cursor/hooks/{pkg}/` | Referenced hook scripts |
# Copy the entire skill folder (identical to github copy)
shutil.copytree(source_path, cursor_skill_dir)

return (github_skill_dir, claude_skill_dir)
danielmeppiel and others added 2 commits March 14, 2026 18:51
…alability

- Fix critical indentation bug: commands block was nested inside cursor
  agents for-loop, causing Claude commands to silently skip when .cursor/
  didn't exist (install.py:647-660)

- Derive INTEGRATION_PREFIXES from KNOWN_TARGETS: removed hardcoded class
  attribute, validate_deploy_path() now calls _get_integration_prefixes()
  so adding a target auto-propagates the allow-list (base_integrator.py)

- Change copy_skill_to_target() return from tuple[Path|None, Path|None]
  to list[Path]: scales to N targets without fixed-width tuples. Refactored
  opt-in target loop to iterate ('.claude', '.cursor') (skill_integrator.py)

- Add .cursor/skills guard in uninstall cleanup (uninstall.py:425)

- Fix docs: Cursor feature table now shows 'Full' support, added missing
  skills and MCP rows to ide-tool-integration.md Cursor table

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@danielmeppiel danielmeppiel merged commit b3bf575 into main Mar 14, 2026
9 checks passed
@danielmeppiel danielmeppiel deleted the feat/cursor-integration branch March 14, 2026 20:38
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.

feat: Native Cursor IDE integration

2 participants