cursor

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 16, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package cursor implements the Cursor adapter for agentsync.

Cursor stores its configuration under a `.cursor/` directory — user-level at ~/.cursor and project-level at <repo>/.cursor (per cursor.com/docs). Unlike Claude (which mixes many concerns into settings.json) Cursor uses dedicated JSON files per concern: MCP servers live in `.cursor/mcp.json` (the same `mcpServers` object shape Claude uses) and hooks in `.cursor/hooks.json` (a `{ "version": 1, "hooks": { … } }` document). Both are JSON, so the adapter has a single key-merge strategy (merge-json-keys), exactly as Claude owns keys in two JSON files (.claude.json + settings.json).

The remaining components are files: memory → AGENTS.md (project scope only — Cursor keeps user-level rules in app-local storage), skills → the shared `.cursor/skills/<name>/` directory, subagents → `.cursor/agents/<name>.md`, and slash commands → `.cursor/commands/<name>.md`. See docs/capability-matrix.md for the per-component coverage and documented loss.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IngestMCPSpec

func IngestMCPSpec(raw map[string]any) source.MCPServerSpec

IngestMCPSpec translates one Cursor-native MCP server table — the value under `.cursor/mcp.json` `mcpServers.<id>` — into the canonical MCPServerSpec. It is the inverse of renderMCP: type/command/args/env/url/headers carry over and any other native key (timeout, envFile, auth, …) is preserved verbatim in Extra.

Types

type Adapter

type Adapter struct {
	// contains filtered or unexported fields
}

Adapter implements adapter.Adapter for Cursor.

func New

func New(opts Options) *Adapter

New constructs a Cursor adapter.

func (*Adapter) Apply

func (a *Adapter) Apply(ops []adapter.FileOp, w adapter.DestWriter) error

Apply routes every destination write through the supplied DestWriter rather than calling iox.AtomicWrite directly. This is the contract that keeps the foreign-collision backup guarantee honest — see the doc on adapter.DestWriter.

func (*Adapter) Capabilities

func (a *Adapter) Capabilities() adapter.Capability

func (*Adapter) Detect

func (a *Adapter) Detect() (bool, error)

func (*Adapter) Ingest

func (a *Adapter) Ingest(scope adapter.Scope, project string) (source.Canonical, error)

Ingest reads Cursor's native config files and returns a partial source.Canonical. It is the inverse of Render: Ingest(Apply(Render(c))) round-trips to c for the components agentsync manages (modulo the documented projected loss — subagent tools/color, command frontmatter — which Render drops with a reported Skip).

func (*Adapter) KeyMergeStrategy

func (a *Adapter) KeyMergeStrategy() string

KeyMergeStrategy is cursor's single key-merge strategy: JSON. Both `.cursor/mcp.json` and `.cursor/hooks.json` are JSON key-merge destinations (the same strategy Claude uses for .claude.json + settings.json), so the single strategy the render pipeline uses for orphan-cleanup synthesis is correct for every key-merge path this adapter owns.

func (*Adapter) Name

func (a *Adapter) Name() string

func (*Adapter) Render

func (a *Adapter) Render(r secrets.Resolved, scope adapter.Scope, project string) ([]adapter.FileOp, []adapter.Skip, error)

Render converts the resolved canonical into FileOps for Cursor.

Render projects each plugin's COMPONENTS (MCP, memory, skills, subagents, commands, hooks) to Cursor's native `.cursor/` paths. Cursor has a native plugin system, but where it records local enable-state is undocumented, so the adapter implements no PluginIngester yet and never re-emits any enable-state on apply — the same read-is-discovery / apply-fans-out-components invariant every adapter follows (see docs/architecture.md § "PluginIngester (read-only)").

func (*Adapter) SetStderr

func (a *Adapter) SetStderr(w io.Writer)

SetStderr replaces the warning sink the adapter writes Ingest warnings to, so a CLI command can route adapter warnings through the same styled writer it uses for its own output. See claude.Adapter.SetStderr for the contract.

type Options

type Options struct {
	TargetRoot string // honors AGENTSYNC_TARGET_ROOT (real "/Users/x" in production)
	// LookPath overrides exec.LookPath for testing. nil means use exec.LookPath.
	LookPath func(file string) (string, error)
	// Stderr receives Ingest warnings (lenient-YAML notices, dropped components).
	// nil means os.Stderr.
	Stderr io.Writer
}

Options configure the adapter at construction.

type Paths

type Paths struct {
	ConfigDir   string // ~/.cursor (or <proj>/.cursor)
	MCP         string // .cursor/mcp.json  (mcpServers; merge-json-keys)
	Hooks       string // .cursor/hooks.json ({version, hooks}; merge-json-keys)
	Memory      string // <proj>/AGENTS.md at project scope; "" at user scope
	SkillsDir   string // .cursor/skills (skill directories)
	AgentsDir   string // .cursor/agents (subagent markdown)
	CommandsDir string // .cursor/commands (slash-command markdown)
}

Paths resolves the destination paths for a given (scope, project, target-root).

Note SkillsDir lives under ~/.cursor/skills (Cursor reads personal skills from $HOME/.cursor/skills as well as the shared ~/.agents/skills). Memory is empty at user scope: Cursor keeps user-level rules in app-local storage, so there is no user-scope filesystem target — only project-scope memory lands as the repo-root AGENTS.md (which Cursor reads natively).

func ResolvePaths

func ResolvePaths(targetRoot, project string, projectScope bool) Paths

ResolvePaths returns the Paths for the given target root and optional project. projectScope=true + non-empty project uses project-local .cursor/ dirs and the repo's AGENTS.md.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL