Windsurf
Apothem harness adapter for Windsurf (GA).
Vendor: Devin Desktop (formerly Codeium Windsurf)
Install name: windsurf
Status: GA
Native config: <project>/.devin/rules/apothem-rules.md
Windsurf is now Devin Desktop, and .devin/rules/ is the preferred
workspace-rules location (it takes precedence over .windsurf/rules/).
Installation
apothem install --harness windsurf --project /path/to/projectThe adapter writes one project-scope Windsurf rules file from the shared Apothem rules and governance surface, writes eleven of Apothem's helpers as Devin Local subagents in the project (see Subagents), and registers two Devin Local hooks (see Hooks).
It also writes Apothem's skills, and the rules and templates they cite, to your user home, before it touches the project (see Files outside the project).
Files written:
<project>/.devin/rules/apothem-rules.md, the rules file.<project>/.devin/agents/<name>.mdfor eleven Apothem helpers, in the project.<project>/.devin/config.local.json, the hook registration, in the project. Your own entries in it stay.<project>/.apothem/support/windsurf/hooks/, the hook scripts, in the project.~/.agents/skills/<name>/SKILL.mdfor each Apothem skill and command, in your user home.~/.config/apothem/rules/and~/.config/apothem/templates/, in your user home.
Files outside the project
The install also writes Apothem's skills to your user home, before it changes anything in the project:
| Folder | What Apothem writes there |
|---|---|
~/.agents/skills/ | One folder with a SKILL.md for each Apothem skill, and one for each Apothem command (a command becomes a skill of the same name). |
~/.config/apothem/rules/, ~/.config/apothem/templates/ | The rules and templates that the skills and the rules file refer to. |
These folders are shared. They are not private to the project:
- Every project you install
windsurfinto, and every other Apothem install that names the folder, uses the same copy and writes the same files, so the order you install in does not matter. Several other tools read~/.agents/skills/too; the harness registry lists them. --projectchooses the rules file to write and which project the install belongs to. It does not change where the skills go.- The install adds no skill or rule file to your repository. The project
gets the rules file, the subagent files in
.devin/agents/, the hook registration in.devin/config.local.json, plus the.apothem/folder every project install creates, which also holds the hook scripts. - The home folders are written first. If that fails, for example because a folder in the path is a link that leaves your home directory (a link that stays inside it is followed) or cannot be written, the install stops with the error before anything in the project changes.
- A skill folder with an Apothem skill's name that Apothem did not write is
left alone, and the install prints a warning that names it. Rename or move
it, then run
apothem update.apothem verifyfails while that name is held. - The files add up to a few megabytes.
The install prints a note that names the folders it writes outside --project,
and --dry-run lists them.
Subagents
Devin Local, which new Devin Desktop tabs start on, reads a subagent from a
Markdown file in <project>/.devin/agents/, per the
Devin subagents documentation. Cascade,
the older mode, has no subagents. The install writes eleven of Apothem's
fourteen helpers into that folder. It installs for the project only and writes no
user-level subagent folder (~/.config/devin/agents/ on Linux and macOS,
%APPDATA%\devin\agents\ on Windows).
Each file keeps the helper's instructions unchanged and carries these frontmatter keys:
| Key | What Apothem writes |
|---|---|
name, description | The helper's name and description. |
allowed-tools | The tools the helper may use, as a list of Devin tool names: read, edit, grep, glob, exec (the helper's Bash) and write. |
Devin has no key that denies a tool, so the helper's allowed tools minus its denied
tools become the one allowed-tools list. The helper's Bash is exec in Devin,
and a tool Devin has no listed name for is left out. Read-only helpers get read,
glob and grep, plus exec for the ones that run commands, and never write or
edit.
Three helpers are not installed: citation-auditor, fact-checker and
research-scout. They need web search and web fetch, and Devin documents no
allowed-tools name for either, so the install holds them back instead of
writing a version that cannot research or one that has every tool. A file of yours
in .devin/agents/ with one of those names is never touched.
The install writes no model key. Devin runs a subagent on its own default
subagent model, which is not the model of the session that started it. It also
writes no max-nesting and none of Apothem's maxTurns, version, updated and
portability keys.
Things to know:
- Custom subagents are experimental. Devin labels the format and options as subject
to change, and Devin Desktop has a Subagents (Preview) switch in Devin Settings
(the Devin CLI setting
subagents_enabledis on by default). - The subagent files are ordinary project files. Commit them with the project or
list
.devin/agents/in.gitignore; Apothem does not choose for you. - A file of yours with an Apothem helper's name is saved under
~/.apothem/backups/and then replaced. The uninstall does not put it back. Files with other names are never touched. - Devin also reads the shared
.agents/agents/folder, which Apothem never writes, and the Devin CLI documents an import of subagents from a.claude/folder without naming the path. Devin Local finds its files the way the Devin CLI does, so that import applies there too. - Apothem has not confirmed the
allowed-toolsnames for web tools, which valuesmodelaccepts, or how an emptyallowed-toolslist is read.
Hooks
Devin Local runs hooks from the hooks key of its config files, per the
Devin hooks documentation.
The install registers two:
| Event | What runs |
|---|---|
SessionStart | The session bootstrap: session metadata, the skill index, the memory and plan summaries and the standing posture, added to the model's context. |
PostToolUse (every tool) | The proactive-compaction tracker. It counts activity and, at most twice per compaction cycle, tells the model to save its state or compact. It is silent otherwise. |
Both add context for the model. Neither blocks a tool call or a session.
Apothem registers no PreToolUse guard on Devin. Devin's documentation lists
additionalContext (the field Apothem's guards speak through) for
UserPromptSubmit, SessionStart and PostToolUse, and lists only a decision and
an input rewrite for PreToolUse. A guard registered there would cost a process
start on every tool call and might deliver nothing, so the write, edit and shell
guards, the AskUserQuestion check and the session-end protocol stay on the
tools that deliver them. Apothem will register a guard on a Devin event once the
documentation, or a probe, shows that it reaches the model.
These are Devin Local hooks. The older Cascade mode reads a different hook format
(.devin/hooks.json), which the install does not write.
Where the files go
| File | What it holds |
|---|---|
<project>/.devin/config.local.json | The two hook registrations, merged into the file's hooks key. Devin documents this file as the local override and gitignored, and excludes local config files from git itself through .git/info/exclude. |
<project>/.apothem/support/windsurf/hooks/ | The dispatcher script, its helpers and its message files. |
Each registered command names the interpreter Apothem found when it ran, and the
absolute path of the project, so it is machine-specific. That is why the install
writes the local file and never the shared <project>/.devin/config.json, the
standalone .devin/hooks.v1.json or the .claude/ settings. The install does not
edit .gitignore. Devin excludes its local config files from git itself (through
.git/info/exclude), so a teammate's checkout does not receive commands that
point at your machine; check that your .gitignore lists .apothem/.
Paths the shell would misread. A project or interpreter path that contains
$, a backtick, a double quote or a backslash is refused before anything is
written: inside the quoted command it would run a different file, or break the
JSON the command is written into. The error names the path; move or rename the
project and run the install again. A space or an apostrophe in a path is fine.
A command looks like this, with your interpreter and project path in place of the two paths:
"/path/to/python" "/path/to/project/.apothem/support/windsurf/hooks/dispatch.py" --contract devin SessionStart--contract devin maps Devin's lowercase tool names (exec, write, edit,
read, grep, glob) onto the names Apothem's handlers test, and leaves the
output as the same envelope Claude Code reads. No matcher is written: Devin's
matcher is a regular expression, an omitted one matches every tool, and
SessionStart has no tool to match.
Things to check after the install
- Devin runs no hook while the workspace is in Restricted Mode. Trust the workspace first.
- To see whether the hooks loaded, open the Hooks tab in Devin Local's
Customizations, or run
/hooksin the Devin CLI. Both list each hook with its source file. - Devin's documentation names no shell for hook commands on Windows. The commands
use
shquoting, which PowerShell would not parse without a call operator. Apothem has not confirmed what Devin Local runs on Windows; if the hooks do not load there, say so in an issue.
Devin also runs the hooks Claude Code wrote. Devin loads the hooks in
~/.claude/settings.json, .claude/settings.json and
.claude/settings.local.json while read_config_from.claude is on, which is its
default: Devin Local finds its files the way the Devin CLI does. If you also
installed Apothem for Claude Code, both sets of hooks can
run. The SessionStart command here and the Claude Code copy of it share one
marker per session in Apothem's hook state folder, so whichever runs second is
silent and the bootstrap reaches the model once; Apothem finds Devin from the
DEVIN_PROJECT_DIR variable Devin sets for its hooks. The marker covers ten
seconds, so a later start of the same session still delivers. The context-size
counter runs in both places, so its thresholds are reached early, and Apothem does
not de-duplicate the counters. To load only these hooks, set
"claude": false under "read_config_from" in your user config
(~/.config/devin/config.json, or %APPDATA%\devin\config.json on Windows) or in
the project's .devin/config.json; that also stops Devin importing Claude Code's
rules, skills, commands and MCP servers. The install prints this as a note.
Your own hooks. The registration is merged into your file by key. Hooks and
other keys you wrote stay as they were, a handler of yours under the same event
stays beside Apothem's, and an update replaces only the handlers whose command runs
the Apothem dispatcher (.apothem/support/windsurf/hooks/dispatch.py with
--contract devin, whichever project path it was written under). A hook of yours
that only shares the name, or that runs python -m apothem.conformity.gate, is
never taken for Apothem's. A file with comments or other JSON5
syntax cannot be rewritten without losing them, so the install reports a
config.unparseable error for that file, leaves it untouched and stops, with the
other files it had begun to write removed again: remove the comments, or add the
two entries yourself.
Turning the hooks off. Set APOTHEM_HOOKS_DISABLE=1 in Devin's environment to
silence the Apothem hooks.
Profile-to-native-config mapping
The adapter reads Apothem's shared profile and renders the project rules file
on every apothem install or apothem update run. The shared profile is the
source of truth; project-local edits to the generated file are backed up before
the next sync replaces the Apothem-managed content.
The file opens with its trigger: always_on frontmatter, which sets the rule's
activation mode. The Apothem-managed block follows it; text you add after the
block is kept on every sync.
Compatibility notes
Windsurf's current rules surface is project-scoped under .devin/rules/ (the
preferred location, which takes precedence over the .windsurf/rules/
backward-compat fallback). Workflows and machine-local memories are
operator-owned; Apothem does not write them, and neither the Cascade hook file
nor the shared Devin config. The single-file .windsurfrules
form is intentionally not written.
Devin Desktop (Windsurf) discovers ~/.agents/skills/, so the skills the
install writes appear without further setup. Its Claude Code import, on by
default, reads skills from the project's .claude/skills/ folder only, so the
skills an Apothem install for Claude Code writes to ~/.claude/skills/ are not
documented to appear there as well. Apothem has not confirmed how
Windsurf treats a SKILL.md header key it does not list; the skills carry
user-invocable, disable-model-invocation, allowed-tools, argument-hint,
and a metadata map.
Verification
apothem verify --harness windsurf --project /path/to/projectThe verify command confirms that:
- The native config exists at the expected path.
- Each managed target exists, the
.devin/agents/folder and the hook registration.devin/config.local.jsonincluded; managed files are non-empty, and JSON or YAML configs parse. The hook file must hold a handler that runs the Apothem dispatcher (the check does not run it), so a file that was reverted or emptied no longer verifies. Add--profile PATHto also confirm that the installed files match that profile. For.devin/agents/the check is that the folder exists, not that each helper file is in it;apothem diff --harness windsurf --project /path/to/projectlists the helper files that are missing or out of date. - Every Apothem skill folder is in place with a
SKILL.md, whichever install wrote it, and no skill folder with an Apothem name belongs to something Apothem did not write. A failed check names the missing or foreign folders. - The adapter-specific verification routine reports success.
Updating
apothem update --harness windsurf --project /path/to/projectRe-derives the project rules file from the current shared profile state.
The update also rewrites any skill folder whose files differ from the current ones.
If you installed with an earlier release that wrote no skills, the update adds them.
It rewrites subagent files that differ from the current ones, and adds any that are missing.
It also refreshes the hook scripts and the Apothem handlers in
.devin/config.local.json, leaving your own entries alone.
Uninstalling
apothem uninstall --harness windsurf --project /path/to/projectRemoves the Apothem block, and the frontmatter Apothem wrote above it, from
<project>/.devin/rules/apothem-rules.md and keeps any other text in it. The
file is deleted only when nothing else remains in it. Before the change, a
timestamped copy of the file is saved under ~/.apothem/backups/; no backup
file is left in the project. The shared profile YAML and Apothem engine are
unaffected.
The uninstall also removes the subagent files it wrote in <project>/.devin/agents/
and keeps any other file there; the folder is removed when it is left empty.
It removes the Apothem hook handlers from <project>/.devin/config.local.json,
recognising them by the dispatcher path in their command, and keeps your own hooks
and keys. The file is deleted only when Apothem created it and nothing else remains
in it. The hook scripts in <project>/.apothem/support/windsurf/hooks/ go too.
It removes the skill folders it wrote in ~/.agents/skills/ and the
rules and templates in ~/.config/apothem/, but only when no other Apothem
install still uses them. Another project, or another tool that shares the
folder, may. In that case the uninstall keeps the folders, prints which install
uses them, and the last uninstall removes them. Files you added to those
folders stay, and a folder left empty is removed. Each
folder is backed up under ~/.apothem/backups/ before it is removed.
Conformity gate
python -m apothem.conformity.gate --all .Troubleshooting
| Symptom | Fix |
|---|---|
| Config file not found | Re-run apothem install --harness windsurf --project /path/to/project |
| Verification failed | Run apothem update --harness windsurf --project /path/to/project, then verify again |
| Devin Local lists none of the Apothem helpers | Run apothem diff --harness windsurf --project /path/to/project. A pending line for the .devin/agents folder means helper files are missing or out of date, so run apothem update --harness windsurf --project /path/to/project. apothem verify is not a test of this: it passes when .devin/agents/ exists, even with no helper file in it. If diff reports no pending changes, check that the Subagents (Preview) setting is on and that the project is open in Devin Desktop's Local mode, then start a new tab |
| The Apothem hooks do not run | Devin runs no hook in a workspace in Restricted Mode: trust the workspace. Open the Hooks tab in Devin Local's Customizations, or run /hooks in the Devin CLI, to see whether the Apothem entries loaded. On Windows Apothem has not confirmed which shell Devin runs hook commands in |
An install reports config.unparseable for config.local.json | The file has comments or other syntax a rewrite would lose. Remove the comments and install again, or add the two Apothem hook entries yourself |
| The Apothem context appears twice, or the context-size reminder comes early | Devin also runs the hooks the Claude Code install wrote. Set "claude": false under "read_config_from" in your Devin config to load only the hooks in .devin/config.local.json |
apothem verify names a missing skill folder | Run apothem install --harness windsurf --project /path/to/project; it restores the folder |
| An install or update warns that it skipped a skill folder | A folder with an Apothem skill's name already exists in the skills folder and Apothem did not write it. Rename or move it, then run apothem update |
| An install stops before it changes the project | A write in your home failed. Read the error, fix the folder it names (a link that leaves your home directory, a file where a folder belongs, or a read-only folder), and install again |
| Unexpected config content | Check ~/.config/apothem/profile.yaml or --profile PATH, then re-run apothem update --harness windsurf --project /path/to/project |
Configuration knobs
| Flag | Default | Description |
|---|---|---|
--dry-run | false | Preview install without writing files. |
See also
- All harnesses — the full catalog of supported tools
- Install guide — install Apothem into this harness
apothem harnessesreference — list and inspect adapters from the CLI