windsurf

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jun 15, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package windsurf implements the Windsurf (Cascade) adapter for agentsync.

Windsurf's config model is asymmetric across scopes (per docs.windsurf.com, now docs.devin.ai):

  • MCP servers live ONLY in the global ~/.codeium/windsurf/mcp_config.json (a JSON `mcpServers` object). There is no project-level MCP file, so MCP is rendered at user scope and skipped (with a report) at project scope.
  • Rules (memory): project scope renders a workspace rule at .windsurf/rules/agentsync.md carrying the documented `trigger: always_on` activation frontmatter; user scope renders the single global rules file ~/.codeium/windsurf/memories/global_rules.md (always-on, frontmatter-less).
  • Workflows (slash commands) are plain markdown at BOTH scopes: .windsurf/workflows/ (project) and ~/.codeium/windsurf/global_workflows/ (user).

(Upstream now documents `.devin/rules|workflows/` as the preferred workspace layout with `.windsurf/` as the supported fallback; agentsync targets `.windsurf/`, which every released version reads.)

Skills, subagents, hooks, and LSP have no Windsurf concept and are skipped. 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 Windsurf-native server entry (the value under mcp_config.json `mcpServers.<id>`) into the canonical MCPServerSpec. A server carrying `serverUrl` (or `url`) is canonicalised to the http transport (Windsurf does not distinguish sse/http in the config), otherwise stdio. Native keys agentsync doesn't model are preserved in Extra.

Types

type Adapter

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

Adapter implements adapter.Adapter for Windsurf.

func New

func New(opts Options) *Adapter

New constructs a Windsurf 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. The DestWriter owns the foreign-collision backup invariant — 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 Windsurf's native config and returns a partial source.Canonical. It is the inverse of Render, honoring the same scope asymmetry: MCP and the global rules file from `~/.codeium/windsurf/` plus global workflows at user scope; workspace rules + workflows from the project `.windsurf/` tree at project scope. The agentsync-rendered `trigger: always_on` frontmatter on the workspace rule is stripped so the canonical memory body stays byte-clean.

func (*Adapter) KeyMergeStrategy

func (a *Adapter) KeyMergeStrategy() string

KeyMergeStrategy is windsurf's single key-merge strategy: JSON (mcp_config.json). It is the only file whose keys agentsync co-owns; rules and workflows are whole-file markdown writes.

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 Windsurf.

Windsurf's config is scope-asymmetric: MCP renders only at user scope (its config is global), while memory + commands render only at project scope (rules/ workflows live in the repo's .windsurf/ tree; global rules are app-managed). The non-applicable scope reports a skip for each affected item, so nothing is dropped silently. Windsurf has no native plugin enable-state agentsync models, so there is no PluginIngester; it still receives plugin-projected components on apply.

func (*Adapter) SetStderr

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

SetStderr replaces the warning sink the adapter writes Ingest warnings to. See claude.Adapter.SetStderr for the contract.

type Options

type Options struct {
	TargetRoot string // honors AGENTSYNC_TARGET_ROOT (real "/Users/x" in production)
	// Stderr is the warning sink for Ingest; nil means os.Stderr.
	Stderr io.Writer
	// LookPath overrides exec.LookPath for testing. nil means use exec.LookPath.
	LookPath func(file string) (string, error)
}

Options configure the adapter at construction.

type Paths

type Paths struct {
	ConfigDir    string // ~/.codeium/windsurf (user) — also the Detect probe
	MCP          string // ~/.codeium/windsurf/mcp_config.json (user scope only; "" at project)
	GlobalRules  string // ~/.codeium/windsurf/memories/global_rules.md (user scope only; "" at project)
	RulesDir     string // <proj>/.windsurf/rules (project scope only; "" at user)
	WorkflowsDir string // <proj>/.windsurf/workflows (project) / ~/.codeium/windsurf/global_workflows (user)
}

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

The fields are scope-asymmetric, mirroring Windsurf's own layout: MCP and the single global rules file are global (`~/.codeium/windsurf/`; empty at project scope), workspace rules are the project's `.windsurf/rules/` (empty at user scope), and workflows exist at BOTH scopes (project `.windsurf/workflows/`, global `~/.codeium/windsurf/global_workflows/`).

func ResolvePaths

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

ResolvePaths returns the Paths for the given target root and optional project.

Jump to

Keyboard shortcuts

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