# Windsurf

> Set up Comity for Windsurf (Devin Desktop) Cascade with workspace hooks, an always-on rule and a user-level MCP entry.

Windsurf's Cascade agent gets workspace hooks for prompts, file writes, terminal commands and responses, plus an always-on rule. Cascade has no project-level MCP file, so `comity init` prints the MCP entry for you to add to your user config.

## Set up

```sh
cd your-repo
comity init --tools windsurf
git add .windsurf/hooks.json .windsurf/rules/comity.md
git commit -m "Set up Comity for Windsurf"
```

Then:

1. Open the repo in Windsurf outside Restricted Mode. Cascade doesn't load or run hooks in Restricted Mode.
2. Add the MCP server to your user-level config (see [MCP](#mcp)).

If the repo already defines hooks in `.devin/hooks.json`, init merges into that file instead. Windsurf ignores the legacy `.windsurf/hooks.json` whenever `.devin/hooks.json` defines hooks.

## What init writes

### `.windsurf/hooks.json`

Each handler has a POSIX `command` (run via `bash -c`) and a `powershell` variant (run via `powershell -Command` on Windows). Both exit quietly when the CLI isn't installed. Shown for one event:

```json
{
  "hooks": {
    "pre_write_code": [
      {
        "command": "command -v comity >/dev/null 2>&1 || exit 0; exec comity hook --tool windsurf --event pre_write_code",
        "powershell": "$c = Get-Command comity -CommandType Application -ErrorAction SilentlyContinue | Select-Object -First 1; if (-not $c) { exit 0 }; & $c.Source hook --tool windsurf --event pre_write_code; exit $LASTEXITCODE"
      }
    ]
  }
}
```

| Cascade event | Comity event |
|---|---|
| `pre_user_prompt` | `UserPromptSubmit` |
| `pre_write_code` | `PreToolUse` (edit) |
| `post_write_code` | `PostToolUse` (edit) |
| `pre_run_command` | `PreToolUse` (shell) |
| `post_run_command` | `PostToolUse` (shell) |
| `post_cascade_response` | `Stop` |

Your own hooks in the file are kept. Cascade has no session start/end events; Comity uses Cascade's `trajectory_id` as the session.

### `.windsurf/rules/comity.md`

A `trigger: always_on` rule with Comity's coordination instructions. Because hooks can't add context in Cascade, this rule and the MCP server are how the agent learns about Comity.

## MCP

Cascade reads MCP servers only from the user-level `mcp_config.json`: `%APPDATA%\devin\mcp_config.json` on Windows, `~/.config/devin/mcp_config.json` on macOS/Linux, or `~/.codeium/windsurf/mcp_config.json` in older Windsurf builds. Open it from the Cascade panel (**⋯ → MCPs → Open MCP config file**) and add:

```json
{
  "mcpServers": {
    "comity": { "command": "node", "args": ["-e", "<launcher>", "mcp"] }
  }
}
```

Copy the exact line `comity init --tools windsurf` prints: it fills in `<launcher>`, a short `node -e` script that finds `comity` on any OS, so the same entry works on Windows, macOS and Linux. Node must be on PATH.

Cascade starts `comity mcp`, a local stdio bridge to the Comity server that uses the login stored by `comity login`. No token goes into any file, and nothing has to be exported.

## What your agent sees

- **Before a file write or terminal command**: a block stops the action (exit code 2). Cascade shows the agent Comity's reason.
- **Everything else**: nothing from the hooks. Cascade hooks can't inject context, so the agent sees briefings, warnings and conflicts only when it calls the Comity MCP tools.

## Verify

```sh
comity doctor
```

Expect `windsurf hooks  all 6 events installed (not in Restricted Mode)` and `windsurf mcp  configured in …/mcp_config.json`. Turn on `"show_output": true` on a hook entry to see its output in Cascade while debugging.

## Limits

- No context injection: Cascade hooks communicate only through exit codes and stderr.
- These hooks apply to the Cascade agent. The Devin Local agent in Devin Desktop has its own hooks and MCP config and isn't covered.
- Workspace hooks have no timeout setting. A slow Comity server delays Cascade's actions until `comity hook` gives up.
