diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 8d9589ec1..6e2ad5097 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -61,7 +61,7 @@ jobs:
integrations-lockfiles: ${{ steps.filter.outputs.integrations-lockfiles }}
integrations-openai-agents: ${{ steps.filter.outputs.integrations-openai-agents }}
integrations-openhands: ${{ steps.filter.outputs.integrations-openhands }}
- integrations-windsurf: ${{ steps.filter.outputs.integrations-windsurf }}
+ integrations-devin-desktop: ${{ steps.filter.outputs.integrations-devin-desktop }}
integrations-pipecat: ${{ steps.filter.outputs.integrations-pipecat }}
integrations-agentcore: ${{ steps.filter.outputs.integrations-agentcore }}
integrations-smolagents: ${{ steps.filter.outputs.integrations-smolagents }}
@@ -196,8 +196,8 @@ jobs:
- 'hindsight-integrations/openai-agents/**'
integrations-openhands:
- 'hindsight-integrations/openhands/**'
- integrations-windsurf:
- - 'hindsight-integrations/windsurf/**'
+ integrations-devin-desktop:
+ - 'hindsight-integrations/devin-desktop/**'
integrations-pipecat:
- 'hindsight-integrations/pipecat/**'
integrations-agentcore:
@@ -3866,11 +3866,11 @@ jobs:
# (requires_real_llm) needs a live Hindsight server and runs separately.
run: uv run pytest tests -v -m "not requires_real_llm"
- test-windsurf-integration:
+ test-devin-desktop-integration:
needs: [detect-changes]
if: >-
(github.event_name == 'workflow_dispatch' ||
- needs.detect-changes.outputs.integrations-windsurf == 'true' ||
+ needs.detect-changes.outputs.integrations-devin-desktop == 'true' ||
needs.detect-changes.outputs.ci == 'true')
runs-on: ubuntu-latest
timeout-minutes: 30
@@ -3891,16 +3891,16 @@ jobs:
with:
python-version-file: ".python-version"
- - name: Build windsurf integration
- working-directory: ./hindsight-integrations/windsurf
+ - name: Build devin-desktop integration
+ working-directory: ./hindsight-integrations/devin-desktop
run: uv build
- name: Install dependencies
- working-directory: ./hindsight-integrations/windsurf
+ working-directory: ./hindsight-integrations/devin-desktop
run: uv sync --frozen
- name: Run tests
- working-directory: ./hindsight-integrations/windsurf
+ working-directory: ./hindsight-integrations/devin-desktop
# PR CI runs only the deterministic bucket; the real-LLM E2E bucket
# (requires_real_llm) needs a live Hindsight server and runs separately.
run: uv run pytest tests -v -m "not requires_real_llm"
@@ -4957,7 +4957,7 @@ jobs:
- test-llamaindex-integration
- test-openai-agents-integration
- test-openhands-integration
- - test-windsurf-integration
+ - test-devin-desktop-integration
- test-agentcore-integration
- test-haystack-integration
- test-pip-slim
diff --git a/hindsight-dev/hindsight_dev/generate_changelog.py b/hindsight-dev/hindsight_dev/generate_changelog.py
index 269259baf..7a2c99004 100644
--- a/hindsight-dev/hindsight_dev/generate_changelog.py
+++ b/hindsight-dev/hindsight_dev/generate_changelog.py
@@ -82,7 +82,7 @@ class IntegrationMeta:
"continue": IntegrationMeta("hindsight-continue", "Continue"),
"zed": IntegrationMeta("hindsight-zed", "Zed"),
"openhands": IntegrationMeta("hindsight-openhands", "OpenHands"),
- "windsurf": IntegrationMeta("hindsight-windsurf", "Windsurf"),
+ "devin-desktop": IntegrationMeta("hindsight-devin-desktop", "Devin Desktop"),
}
VALID_INTEGRATIONS = list(INTEGRATIONS.keys())
diff --git a/hindsight-docs/docs-integrations/devin-desktop.md b/hindsight-docs/docs-integrations/devin-desktop.md
new file mode 100644
index 000000000..483f59474
--- /dev/null
+++ b/hindsight-docs/docs-integrations/devin-desktop.md
@@ -0,0 +1,46 @@
+---
+sidebar_position: 7
+title: "Devin Desktop Persistent Memory with Hindsight | Integration"
+description: "Add long-term memory to Devin Desktop (formerly Windsurf) with Hindsight via MCP. One command wires the Hindsight MCP server into mcp_config.json plus an always-on recall/retain rule, so memory works automatically in Devin."
+---
+
+# Devin Desktop
+
+Long-term memory for [Devin Desktop](https://devin.ai) — the editor formerly known as Windsurf (Codeium) — powered by [Hindsight](https://vectorize.io/hindsight). One command connects Devin to the Hindsight MCP server and adds a rule telling the agent to use it — so it recalls relevant memory at the start of a task and retains durable facts as it goes. Recall happens at query time against your actual message, and from your seat it's automatic.
+
+:::note
+Cognition rebranded Windsurf to Devin Desktop in June 2026. The MCP config still lives under `~/.codeium/windsurf/` — that's Devin Desktop's on-disk data directory and is unchanged by the rebrand. The workspace rule now lives under `.devin/rules/` (with `.windsurf/rules/` kept as a legacy fallback).
+:::
+
+## How It Works
+
+Devin Desktop supports two things this integration uses:
+
+- **MCP servers:** Devin Desktop runs MCP servers configured under `mcpServers` in `~/.codeium/windsurf/mcp_config.json` and surfaces their tools to the agent. Remote servers connect via a `serverUrl` field with optional headers, so the Hindsight MCP endpoint connects directly — no bridge needed — giving the agent `recall` / `retain` / `reflect` tools.
+- **Workspace rules** in `.devin/rules/`. A rule file with `trigger: always_on` frontmatter is included in every Devin request in the workspace. The integration writes a small rule there telling the agent to recall first and retain what it learns.
+
+## Setup
+
+```bash
+pip install hindsight-devin-desktop
+cd your-project
+hindsight-devin-desktop init --api-token YOUR_HINDSIGHT_API_KEY --bank-id my-memory
+```
+
+`init` adds the `hindsight` MCP server to `~/.codeium/windsurf/mcp_config.json` (Devin Desktop's single global MCP config) and writes the recall/retain rule to `./.devin/rules/hindsight.md`. Reload Devin Desktop (or refresh MCP servers), and the `hindsight` server's tools become available.
+
+Use a [Hindsight Cloud](https://hindsight.vectorize.io) key, or point at a self-hosted server with `--api-url http://localhost:8888` (no token needed for an open local server). If your `mcp_config.json` isn't plain JSON, `init` prints the entry to paste rather than rewriting the file — or run `hindsight-devin-desktop init --print-only` anytime.
+
+## Commands
+
+| Command | Description |
+| --- | --- |
+| `hindsight-devin-desktop init` | Add the MCP server + recall/retain rule |
+| `hindsight-devin-desktop status` | Show whether the server + rule are configured |
+| `hindsight-devin-desktop uninstall` | Remove the server + rule |
+
+## Note
+
+Recall and retain run through MCP tools the agent calls, guided by the always-on rule. This makes recall query-time precise (no lag), with the tradeoff that it relies on the agent following the "recall first" instruction rather than the editor enforcing it.
+
+See the [package README](https://github.com/vectorize-io/hindsight/tree/main/hindsight-integrations/devin-desktop) for full configuration options.
diff --git a/hindsight-docs/docs-integrations/windsurf.md b/hindsight-docs/docs-integrations/windsurf.md
deleted file mode 100644
index 7a276910d..000000000
--- a/hindsight-docs/docs-integrations/windsurf.md
+++ /dev/null
@@ -1,42 +0,0 @@
----
-sidebar_position: 7
-title: "Windsurf Persistent Memory with Hindsight | Integration"
-description: "Add long-term memory to Windsurf (Codeium) with Hindsight via MCP. One command wires the Hindsight MCP server into mcp_config.json plus an always-on recall/retain rule, so memory works automatically in Cascade."
----
-
-# Windsurf
-
-Long-term memory for [Windsurf](https://windsurf.com) (Codeium), powered by [Hindsight](https://vectorize.io/hindsight). One command connects Cascade to the Hindsight MCP server and adds a rule telling the agent to use it — so it recalls relevant memory at the start of a task and retains durable facts as it goes. Recall happens at query time against your actual message, and from your seat it's automatic.
-
-## How It Works
-
-Windsurf supports two things this integration uses:
-
-- **MCP servers:** Windsurf runs MCP servers configured under `mcpServers` in `~/.codeium/windsurf/mcp_config.json` and surfaces their tools in Cascade. Remote servers connect via a `serverUrl` field with optional headers, so the Hindsight MCP endpoint connects directly — no bridge needed — giving the agent `recall` / `retain` / `reflect` tools.
-- **Workspace rules** in `.windsurf/rules/`. A rule file with `trigger: always_on` frontmatter is included in every Cascade request in the workspace. The integration writes a small rule there telling the agent to recall first and retain what it learns.
-
-## Setup
-
-```bash
-pip install hindsight-windsurf
-cd your-project
-hindsight-windsurf init --api-token YOUR_HINDSIGHT_API_KEY --bank-id my-memory
-```
-
-`init` adds the `hindsight` MCP server to `~/.codeium/windsurf/mcp_config.json` (Windsurf's single global MCP config) and writes the recall/retain rule to `./.windsurf/rules/hindsight.md`. Reload Windsurf (or refresh MCP servers in Cascade), and the `hindsight` server's tools become available.
-
-Use a [Hindsight Cloud](https://hindsight.vectorize.io) key, or point at a self-hosted server with `--api-url http://localhost:8888` (no token needed for an open local server). If your `mcp_config.json` isn't plain JSON, `init` prints the entry to paste rather than rewriting the file — or run `hindsight-windsurf init --print-only` anytime.
-
-## Commands
-
-| Command | Description |
-| --- | --- |
-| `hindsight-windsurf init` | Add the MCP server + recall/retain rule |
-| `hindsight-windsurf status` | Show whether the server + rule are configured |
-| `hindsight-windsurf uninstall` | Remove the server + rule |
-
-## Note
-
-Recall and retain run through MCP tools the agent calls, guided by the always-on rule. This makes recall query-time precise (no lag), with the tradeoff that it relies on the agent following the "recall first" instruction rather than the editor enforcing it.
-
-See the [package README](https://github.com/vectorize-io/hindsight/tree/main/hindsight-integrations/windsurf) for full configuration options.
diff --git a/hindsight-docs/src/data/integrations.json b/hindsight-docs/src/data/integrations.json
index 621a282e8..0f071aef8 100644
--- a/hindsight-docs/src/data/integrations.json
+++ b/hindsight-docs/src/data/integrations.json
@@ -571,14 +571,14 @@
"icon": "/img/icons/openhands.png"
},
{
- "id": "windsurf",
- "name": "Windsurf",
- "description": "Long-term memory for Windsurf (Codeium) via its native MCP support. One command wires the Hindsight MCP server into mcp_config.json plus an always-on recall/retain rule, so memory works automatically in Cascade.",
+ "id": "devin-desktop",
+ "name": "Devin Desktop",
+ "description": "Long-term memory for Devin Desktop (the editor formerly known as Windsurf) via its native MCP support. One command wires the Hindsight MCP server into mcp_config.json plus an always-on recall/retain rule, so memory works automatically.",
"type": "official",
"by": "hindsight",
"category": "tool",
- "link": "/sdks/integrations/windsurf",
- "icon": "/img/icons/windsurf.svg"
+ "link": "/sdks/integrations/devin-desktop",
+ "icon": "/img/icons/devin-desktop.svg"
},
{
"id": "epimetheus",
diff --git a/hindsight-docs/static/img/icons/devin-desktop.svg b/hindsight-docs/static/img/icons/devin-desktop.svg
new file mode 100644
index 000000000..440b59fb5
--- /dev/null
+++ b/hindsight-docs/static/img/icons/devin-desktop.svg
@@ -0,0 +1 @@
+
diff --git a/hindsight-docs/static/img/icons/windsurf.svg b/hindsight-docs/static/img/icons/windsurf.svg
deleted file mode 100644
index 7670303f6..000000000
--- a/hindsight-docs/static/img/icons/windsurf.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/hindsight-integrations/README.md b/hindsight-integrations/README.md
index 3c573ddbb..da7c0e8bd 100644
--- a/hindsight-integrations/README.md
+++ b/hindsight-integrations/README.md
@@ -14,7 +14,7 @@ Each integration lives in its own subdirectory with its own README, configuratio
| [**Cursor CLI**](./cursor-cli) | Python hook scripts for Cursor CLI. Auto-recall on `beforeSubmitPrompt`, auto-retain on `stop`, final flush on `sessionEnd`. | `./scripts/install.sh` |
| [**Continue.dev**](./continue) | HTTP context provider for precise `@hindsight` recall in chat, plus optional MCP-server + rules for automatic recall/retain in agent mode. | `pip install hindsight-continue` |
| [**GitHub Copilot**](./github-copilot) | MCP server config (`.vscode/mcp.json`) + a recall/retain rule for VS Code Copilot's agent mode. | `pip install hindsight-copilot` |
-| [**Windsurf**](./windsurf) | Native MCP server config + always-on recall/retain rule for Windsurf (Codeium) Cascade. | `pip install hindsight-windsurf` |
+| [**Devin Desktop**](./devin-desktop) | Native MCP server config + always-on recall/retain rule for Devin Desktop (formerly Windsurf). | `pip install hindsight-devin-desktop` |
| [**Roo Code**](./roo-code) | Persistent memory for Roo Code VS Code extension. | See README |
| [**Hermes (OpenAI Agents SDK)**](./hermes) | Memory layer for OpenAI Agents SDK. | See README |
| [**Grok Build**](./grok-build) | Hooks for Grok Build (xAI). | See README |
diff --git a/hindsight-integrations/continue/hindsight_continue/server.py b/hindsight-integrations/continue/hindsight_continue/server.py
index 01d65077b..5f0c6b460 100644
--- a/hindsight-integrations/continue/hindsight_continue/server.py
+++ b/hindsight-integrations/continue/hindsight_continue/server.py
@@ -25,8 +25,19 @@
_MAX_BODY_BYTES = 1_000_000
-def make_handler(client: Hindsight, config: HindsightContinueConfig):
- """Build a request-handler class bound to a client and config."""
+def make_handler(config: HindsightContinueConfig, client: Optional[Hindsight] = None):
+ """Build a request-handler class.
+
+ When ``client`` is None (production), a fresh Hindsight client is resolved
+ **per request**. This is deliberate: the adapter runs on a
+ :class:`ThreadingHTTPServer` (one worker thread per request), and the
+ Hindsight client's underlying aiohttp session is bound to the thread /
+ event loop that first used it. A single shared client therefore succeeds on
+ the first request and then raises ``Timeout context manager should be used
+ inside a task`` on every request after it. Resolving per request keeps each
+ recall on its own thread's client. Tests may inject a client directly (they
+ drive the handler single-threaded).
+ """
class _Handler(BaseHTTPRequestHandler):
# Quiet the default per-request stderr logging; route through our logger.
@@ -66,8 +77,10 @@ def do_POST(self) -> None: # noqa: N802 - stdlib signature
self._write_json(400, {"error": "request body must be a JSON object"})
return
+ request_client = None
try:
- items = build_context_items(payload, client=client, config=config)
+ request_client = client if client is not None else resolve_client()
+ items = build_context_items(payload, client=request_client, config=config)
except HindsightError as e:
# Surface the failure so it shows up in Continue's warnings rather
# than silently returning no memory.
@@ -77,6 +90,15 @@ def do_POST(self) -> None: # noqa: N802 - stdlib signature
logger.exception("Unexpected error handling context request")
self._write_json(500, {"error": f"internal error: {e}"})
return
+ finally:
+ # Close only a client we created here (a per-request client),
+ # not a test-injected one. Otherwise the fresh aiohttp session
+ # leaks a connector every request on the long-running server.
+ if client is None and request_client is not None:
+ try:
+ request_client.close()
+ except Exception: # pragma: no cover - best-effort cleanup
+ logger.debug("client close failed", exc_info=True)
self._write_json(200, serialize(items))
@@ -88,8 +110,10 @@ def build_server(
) -> ThreadingHTTPServer:
"""Create (but do not start) the adapter HTTP server."""
config = config or get_config()
- client = client or resolve_client()
- handler = make_handler(client, config)
+ # Do not pre-resolve a shared client: pass it through so the handler resolves
+ # a fresh client per request (see make_handler). A test-injected client is
+ # used as-is.
+ handler = make_handler(config, client)
return ThreadingHTTPServer((config.host, config.port), handler)
diff --git a/hindsight-integrations/continue/pyproject.toml b/hindsight-integrations/continue/pyproject.toml
index 51397ee77..dcf91bfd0 100644
--- a/hindsight-integrations/continue/pyproject.toml
+++ b/hindsight-integrations/continue/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "hindsight-continue"
-version = "0.1.0"
+version = "0.1.1"
description = "Continue.dev integration for Hindsight - persistent long-term memory via an HTTP context provider"
readme = "README.md"
requires-python = ">=3.10"
diff --git a/hindsight-integrations/continue/tests/test_server.py b/hindsight-integrations/continue/tests/test_server.py
index c5f4ec3bf..0e934ddb9 100644
--- a/hindsight-integrations/continue/tests/test_server.py
+++ b/hindsight-integrations/continue/tests/test_server.py
@@ -97,3 +97,30 @@ def test_recall_error_surfaces_as_502(self):
assert status == 502
assert "error" in json.loads(raw)
+
+ def test_resolves_a_fresh_client_per_request(self, monkeypatch):
+ """Regression: with no injected client, resolve one per request.
+
+ ThreadingHTTPServer handles each request on its own thread, and the
+ Hindsight client's aiohttp session is thread/loop-bound — so a single
+ shared client fails on the 2nd request with "Timeout context manager
+ should be used inside a task". The adapter must resolve per request.
+ """
+ import hindsight_continue.server as server_mod
+
+ calls = []
+
+ def fake_resolve():
+ calls.append(1)
+ return make_client(["recalled fact"])
+
+ monkeypatch.setattr(server_mod, "resolve_client", fake_resolve)
+
+ # client=None -> production path -> per-request resolution
+ with running_server(None) as (host, port):
+ for _ in range(3):
+ status, raw = _post(host, port, continue_request(query="hi"))
+ assert status == 200
+ assert "recalled fact" in json.loads(raw)[0]["content"]
+
+ assert len(calls) == 3, f"expected a fresh client per request, got {len(calls)} resolves"
diff --git a/hindsight-integrations/continue/uv.lock b/hindsight-integrations/continue/uv.lock
index 372636d97..d4584d04c 100644
--- a/hindsight-integrations/continue/uv.lock
+++ b/hindsight-integrations/continue/uv.lock
@@ -361,7 +361,7 @@ wheels = [
[[package]]
name = "hindsight-continue"
-version = "0.1.0"
+version = "0.1.1"
source = { editable = "." }
dependencies = [
{ name = "hindsight-client" },
diff --git a/hindsight-integrations/devin-desktop/README.md b/hindsight-integrations/devin-desktop/README.md
new file mode 100644
index 000000000..7195a8972
--- /dev/null
+++ b/hindsight-integrations/devin-desktop/README.md
@@ -0,0 +1,84 @@
+# hindsight-devin-desktop
+
+Long-term memory for **Devin Desktop** (the editor formerly known as Windsurf / Codeium), powered by [Hindsight](https://github.com/vectorize-io/hindsight).
+
+`hindsight-devin-desktop init` wires the Hindsight **MCP server** into Devin Desktop's
+`~/.codeium/windsurf/mcp_config.json` and adds an always-on recall/retain rule to
+`.devin/rules/hindsight.md`. Devin then has `recall` / `retain` / `reflect`
+tools and — guided by the rule — recalls relevant memory at the start of a task
+and retains durable facts as it works.
+
+> **Note:** Cognition rebranded Windsurf to Devin Desktop (June 2026). The MCP
+> config path still lives under `~/.codeium/windsurf/` — that's Devin Desktop's
+> on-disk data directory and is unchanged by the rebrand. The workspace rule now
+> lives under `.devin/rules/` (with `.windsurf/rules/` kept as a legacy fallback).
+
+## How it works
+
+Devin Desktop supports two things this integration uses:
+
+- **MCP servers** in `~/.codeium/windsurf/mcp_config.json` under `mcpServers`,
+ including **remote servers** via `serverUrl` with headers — so the Hindsight
+ MCP endpoint connects directly:
+
+ ```json
+ {
+ "mcpServers": {
+ "hindsight": {
+ "serverUrl": "https://api.hindsight.vectorize.io/mcp/my-project/",
+ "headers": { "Authorization": "Bearer hsk_..." }
+ }
+ }
+ }
+ ```
+
+- **Workspace rules** in `.devin/rules/`. A rule file with `trigger: always_on`
+ frontmatter is applied to every Devin request in the workspace — that's where
+ the recall/retain rule lives.
+
+## Install
+
+```bash
+pip install hindsight-devin-desktop
+cd your-project
+hindsight-devin-desktop init --api-token YOUR_HINDSIGHT_API_KEY --bank-id my-project
+```
+
+`init` merges the `mcpServers` entry into `~/.codeium/windsurf/mcp_config.json`
+(Devin Desktop's single global MCP config) and writes the rule into
+`./.devin/rules/hindsight.md`. Reload Devin Desktop (or refresh MCP servers) and
+the `hindsight` tools are available.
+
+Use a [Hindsight Cloud](https://hindsight.vectorize.io) key, or a self-hosted
+server with `--api-url http://localhost:8888` (no token needed for an open local
+server). If `mcp_config.json` isn't plain JSON, `init` prints the snippet to
+paste instead of touching the file — or run `hindsight-devin-desktop init --print-only`
+anytime.
+
+## Commands
+
+| Command | Description |
+| --- | --- |
+| `hindsight-devin-desktop init` | Add the MCP server + recall/retain rule |
+| `hindsight-devin-desktop status` | Show whether the server + rule are configured |
+| `hindsight-devin-desktop uninstall` | Remove the server + rule |
+
+## Configuration
+
+| Setting | Env var | Default |
+| --- | --- | --- |
+| API URL | `HINDSIGHT_API_URL` | `https://api.hindsight.vectorize.io` |
+| API token | `HINDSIGHT_API_TOKEN` | _(none; required for Cloud)_ |
+| Bank id | `HINDSIGHT_DEVIN_DESKTOP_BANK_ID` | `devin-desktop` |
+
+## Development
+
+```bash
+uv sync
+uv run pytest tests -v -m 'not requires_real_llm' # deterministic suite
+uv run pytest tests -v -m requires_real_llm # gated MCP-endpoint check
+```
+
+## License
+
+MIT
diff --git a/hindsight-integrations/devin-desktop/hindsight_devin_desktop/__init__.py b/hindsight-integrations/devin-desktop/hindsight_devin_desktop/__init__.py
new file mode 100644
index 000000000..521d1ec88
--- /dev/null
+++ b/hindsight-integrations/devin-desktop/hindsight_devin_desktop/__init__.py
@@ -0,0 +1,12 @@
+"""Hindsight memory integration for Devin Desktop (formerly Windsurf / Codeium).
+
+Wires the Hindsight MCP server into Devin Desktop's ``~/.codeium/windsurf/mcp_config.json``
+and writes an always-on recall/retain rule into ``.devin/rules/hindsight.md``,
+so Devin has ``recall``/``retain``/``reflect`` tools and uses them automatically.
+
+CLI::
+
+ hindsight-devin-desktop init --api-token hsk_... --bank-id my-project
+"""
+
+__version__ = "0.1.0"
diff --git a/hindsight-integrations/windsurf/hindsight_windsurf/cli.py b/hindsight-integrations/devin-desktop/hindsight_devin_desktop/cli.py
similarity index 82%
rename from hindsight-integrations/windsurf/hindsight_windsurf/cli.py
rename to hindsight-integrations/devin-desktop/hindsight_devin_desktop/cli.py
index b145b6dac..b2b67884e 100644
--- a/hindsight-integrations/windsurf/hindsight_windsurf/cli.py
+++ b/hindsight-integrations/devin-desktop/hindsight_devin_desktop/cli.py
@@ -1,8 +1,8 @@
-"""CLI for the Hindsight Windsurf integration.
+"""CLI for the Hindsight Devin Desktop integration.
-``hindsight-windsurf init`` wires the Hindsight MCP server into Windsurf's
-``~/.codeium/windsurf/mcp_config.json`` and writes an always-on recall/retain
-rule into ``.windsurf/rules/hindsight.md``. Cascade then exposes
+``hindsight-devin-desktop init`` wires the Hindsight MCP server into Devin
+Desktop's ``~/.codeium/windsurf/mcp_config.json`` and writes an always-on
+recall/retain rule into ``.devin/rules/hindsight.md``. Devin then exposes
``recall``/``retain``/``reflect`` and (via the rule) uses them automatically.
"""
@@ -16,7 +16,7 @@
from typing import Optional
from . import __version__
-from .config import USER_CONFIG_FILE, WindsurfConfig, load_config
+from .config import USER_CONFIG_FILE, DevinDesktopConfig, load_config
from .mcp_config import (
McpResult,
apply_to_mcp,
@@ -36,7 +36,7 @@ class InstallOutcome:
rules_path: Path
-def build_install(config: WindsurfConfig, mcp_path: Path, rules_path: Path) -> InstallOutcome:
+def build_install(config: DevinDesktopConfig, mcp_path: Path, rules_path: Path) -> InstallOutcome:
"""Apply the MCP server entry and the recall/retain rule (the testable core)."""
server = build_http_server(config.hindsight_api_url, config.hindsight_api_token, config.bank_id)
mcp = apply_to_mcp(mcp_path, server)
@@ -44,7 +44,7 @@ def build_install(config: WindsurfConfig, mcp_path: Path, rules_path: Path) -> I
return InstallOutcome(mcp=mcp, rules_path=rules_path)
-def _resolve_config(args: argparse.Namespace) -> WindsurfConfig:
+def _resolve_config(args: argparse.Namespace) -> DevinDesktopConfig:
cfg = load_config(config_file=_user_config_path(args))
if args.api_url:
cfg.hindsight_api_url = args.api_url
@@ -67,7 +67,7 @@ def _rules_path(args: argparse.Namespace) -> Path:
return Path(args.rules_path) if args.rules_path else default_rules_path()
-def _scaffold_user_config(cfg: WindsurfConfig, path: Path) -> None:
+def _scaffold_user_config(cfg: DevinDesktopConfig, path: Path) -> None:
if path.is_file():
return
data = {"hindsightApiUrl": cfg.hindsight_api_url, "bankId": cfg.bank_id}
@@ -86,11 +86,11 @@ def cmd_init(args: argparse.Namespace) -> None:
if args.print_only:
print("Add this to your ~/.codeium/windsurf/mcp_config.json:\n")
print(render_snippet(server))
- print("\nAnd save this rule as .windsurf/rules/hindsight.md:\n")
+ print("\nAnd save this rule as .devin/rules/hindsight.md:\n")
print(RULE_TEXT)
return
- print("Setting up Hindsight for Windsurf ...")
+ print("Setting up Hindsight for Devin Desktop ...")
_scaffold_user_config(cfg, _user_config_path(args))
outcome = build_install(cfg, mcp_path, rules_path)
@@ -102,7 +102,7 @@ def cmd_init(args: argparse.Namespace) -> None:
verb = {"created": "Created", "merged": "Updated", "unchanged": "Already configured in"}[outcome.mcp.action]
print(f" {verb} {outcome.mcp.path} (MCP server: hindsight -> bank '{cfg.bank_id}')")
print(f" Wrote always-on recall/retain rule to {outcome.rules_path}")
- print("\nDone. Reload Windsurf (or refresh MCP servers in Cascade) and the")
+ print("\nDone. Reload Devin Desktop (or refresh MCP servers) and the")
print("hindsight MCP tools (recall/retain/reflect) are available + used automatically.")
@@ -131,21 +131,21 @@ def _add_overrides(parser: argparse.ArgumentParser) -> None:
parser.add_argument(
"--mcp-path", default=None, help="mcp_config.json path (default: ~/.codeium/windsurf/mcp_config.json)"
)
- parser.add_argument("--rules-path", default=None, help="rule file path (default: ./.windsurf/rules/hindsight.md)")
+ parser.add_argument("--rules-path", default=None, help="rule file path (default: ./.devin/rules/hindsight.md)")
parser.add_argument("--user-config-path", default=None, help=argparse.SUPPRESS)
def main(argv: Optional[list[str]] = None) -> int:
parser = argparse.ArgumentParser(
- prog="hindsight-windsurf", description="Hindsight memory for Windsurf (Codeium, via MCP)"
+ prog="hindsight-devin-desktop", description="Hindsight memory for Devin Desktop (formerly Windsurf), via MCP"
)
- parser.add_argument("--version", action="version", version=f"hindsight-windsurf {__version__}")
+ parser.add_argument("--version", action="version", version=f"hindsight-devin-desktop {__version__}")
sub = parser.add_subparsers(dest="command")
- init_p = sub.add_parser("init", help="Configure Windsurf's MCP server + recall/retain rule")
+ init_p = sub.add_parser("init", help="Configure Devin Desktop's MCP server + recall/retain rule")
init_p.add_argument("--api-url", default=None, help="Hindsight API URL (default: cloud)")
init_p.add_argument("--api-token", default=None, help="Hindsight API token (for Cloud)")
- init_p.add_argument("--bank-id", default=None, help="Memory bank for the MCP server (default: windsurf)")
+ init_p.add_argument("--bank-id", default=None, help="Memory bank for the MCP server (default: devin-desktop)")
init_p.add_argument("--print-only", action="store_true", help="Print the config to add manually; write nothing")
_add_overrides(init_p)
init_p.set_defaults(func=cmd_init)
diff --git a/hindsight-integrations/windsurf/hindsight_windsurf/config.py b/hindsight-integrations/devin-desktop/hindsight_devin_desktop/config.py
similarity index 68%
rename from hindsight-integrations/windsurf/hindsight_windsurf/config.py
rename to hindsight-integrations/devin-desktop/hindsight_devin_desktop/config.py
index 7644a41bd..5f6caab95 100644
--- a/hindsight-integrations/windsurf/hindsight_windsurf/config.py
+++ b/hindsight-integrations/devin-desktop/hindsight_devin_desktop/config.py
@@ -1,13 +1,15 @@
-"""Configuration for the Hindsight Windsurf integration.
+"""Configuration for the Hindsight Devin Desktop integration.
-Settings layer (later wins): built-in defaults -> ``~/.hindsight/windsurf.json``
--> environment variables. Resolved into a typed :class:`WindsurfConfig`.
+Devin Desktop is the editor formerly known as Windsurf (Codeium).
+
+Settings layer (later wins): built-in defaults -> ``~/.hindsight/devin-desktop.json``
+-> environment variables. Resolved into a typed :class:`DevinDesktopConfig`.
The integration is configuration-only: it wires the Hindsight MCP server into
-Windsurf's ``~/.codeium/windsurf/mcp_config.json`` and writes an always-on
-recall/retain rule into ``.windsurf/rules/hindsight.md`` (which Cascade applies
-to every request in the workspace). Memory operations run through the MCP server
-at runtime.
+Devin Desktop's ``~/.codeium/windsurf/mcp_config.json`` and writes an always-on
+recall/retain rule into ``.devin/rules/hindsight.md`` (which Devin applies to
+every request in the workspace). Memory operations run through the MCP server at
+runtime.
"""
from __future__ import annotations
@@ -19,14 +21,14 @@
from typing import Optional
DEFAULT_HINDSIGHT_API_URL = "https://api.hindsight.vectorize.io"
-DEFAULT_BANK_ID = "windsurf"
+DEFAULT_BANK_ID = "devin-desktop"
-USER_CONFIG_FILE = Path.home() / ".hindsight" / "windsurf.json"
+USER_CONFIG_FILE = Path.home() / ".hindsight" / "devin-desktop.json"
@dataclass
-class WindsurfConfig:
- """Resolved configuration for the Windsurf MCP setup."""
+class DevinDesktopConfig:
+ """Resolved configuration for the Devin Desktop MCP setup."""
hindsight_api_url: str = DEFAULT_HINDSIGHT_API_URL
hindsight_api_token: Optional[str] = None
@@ -44,13 +46,13 @@ class WindsurfConfig:
_ENV_KEYS = {
"HINDSIGHT_API_URL": "hindsight_api_url",
"HINDSIGHT_API_TOKEN": "hindsight_api_token",
- "HINDSIGHT_WINDSURF_BANK_ID": "bank_id",
+ "HINDSIGHT_DEVIN_DESKTOP_BANK_ID": "bank_id",
}
-def load_config(config_file: Optional[Path] = None, env: Optional[dict] = None) -> WindsurfConfig:
+def load_config(config_file: Optional[Path] = None, env: Optional[dict] = None) -> DevinDesktopConfig:
"""Load and resolve configuration from file then environment."""
- cfg = WindsurfConfig()
+ cfg = DevinDesktopConfig()
env = os.environ if env is None else env
path = config_file if config_file is not None else USER_CONFIG_FILE
diff --git a/hindsight-integrations/windsurf/hindsight_windsurf/mcp_config.py b/hindsight-integrations/devin-desktop/hindsight_devin_desktop/mcp_config.py
similarity index 82%
rename from hindsight-integrations/windsurf/hindsight_windsurf/mcp_config.py
rename to hindsight-integrations/devin-desktop/hindsight_devin_desktop/mcp_config.py
index 62c51a650..28f718370 100644
--- a/hindsight-integrations/windsurf/hindsight_windsurf/mcp_config.py
+++ b/hindsight-integrations/devin-desktop/hindsight_devin_desktop/mcp_config.py
@@ -1,9 +1,11 @@
-"""Wire Hindsight into Windsurf's MCP config (``~/.codeium/windsurf/mcp_config.json``).
+"""Wire Hindsight into Devin Desktop's MCP config (``~/.codeium/windsurf/mcp_config.json``).
-Windsurf's Cascade reads MCP servers from ``~/.codeium/windsurf/mcp_config.json``
-under the ``mcpServers`` key. For a remote server it uses a ``serverUrl`` field
-(plus optional ``headers``), so the Hindsight MCP endpoint connects with no
-bridge::
+Devin Desktop (formerly Windsurf) reads MCP servers from
+``~/.codeium/windsurf/mcp_config.json`` under the ``mcpServers`` key — the path
+still carries the legacy ``windsurf`` segment, which is the app's on-disk data
+directory and is unchanged by the rebrand. For a remote server it uses a
+``serverUrl`` field (plus optional ``headers``), so the Hindsight MCP endpoint
+connects with no bridge::
{
"mcpServers": {
@@ -14,9 +16,9 @@
}
}
-Unlike VS Code, Windsurf has no project-local MCP file — ``mcp_config.json`` is
-a single global file. We only edit it in place when it parses as strict JSON;
-otherwise we return the exact snippet to paste, never risking the user's file.
+Devin Desktop has no project-local MCP file — ``mcp_config.json`` is a single
+global file. We only edit it in place when it parses as strict JSON; otherwise
+we return the exact snippet to paste, never risking the user's file.
"""
from __future__ import annotations
@@ -30,7 +32,7 @@
def default_mcp_path() -> Path:
- """The global Windsurf MCP config (``~/.codeium/windsurf/mcp_config.json``)."""
+ """The global Devin Desktop MCP config (``~/.codeium/windsurf/mcp_config.json``)."""
return Path.home() / ".codeium" / "windsurf" / "mcp_config.json"
diff --git a/hindsight-integrations/windsurf/hindsight_windsurf/py.typed b/hindsight-integrations/devin-desktop/hindsight_devin_desktop/py.typed
similarity index 100%
rename from hindsight-integrations/windsurf/hindsight_windsurf/py.typed
rename to hindsight-integrations/devin-desktop/hindsight_devin_desktop/py.typed
diff --git a/hindsight-integrations/windsurf/hindsight_windsurf/rules.py b/hindsight-integrations/devin-desktop/hindsight_devin_desktop/rules.py
similarity index 73%
rename from hindsight-integrations/windsurf/hindsight_windsurf/rules.py
rename to hindsight-integrations/devin-desktop/hindsight_devin_desktop/rules.py
index 7c66184ed..28e6e6187 100644
--- a/hindsight-integrations/windsurf/hindsight_windsurf/rules.py
+++ b/hindsight-integrations/devin-desktop/hindsight_devin_desktop/rules.py
@@ -1,9 +1,10 @@
-"""Write Hindsight's recall/retain rule into ``.windsurf/rules/hindsight.md``.
+"""Write Hindsight's recall/retain rule into ``.devin/rules/hindsight.md``.
-Windsurf applies workspace rule files under ``.windsurf/rules/``. A file with
-``trigger: always_on`` frontmatter is included in every Cascade request in the
-workspace, so the rule tells Cascade to use the Hindsight MCP tools — recall
-relevant memory at the start of a task, and retain durable facts.
+Devin Desktop applies workspace rule files under ``.devin/rules/`` (with
+``.windsurf/rules/`` kept as a legacy fallback). A file with ``trigger: always_on``
+frontmatter is included in every Devin request in the workspace, so the rule
+tells the agent to use the Hindsight MCP tools — recall relevant memory at the
+start of a task, and retain durable facts.
The rule lives in its own dedicated file, so we own the whole file: a sentinel
comment marks it as ours for idempotent update/removal without touching any
@@ -14,7 +15,7 @@
from pathlib import Path
-SENTINEL = ""
+SENTINEL = ""
FRONTMATTER = "---\ntrigger: always_on\n---"
@@ -32,8 +33,8 @@
def default_rules_path() -> Path:
- """The workspace ``.windsurf/rules/hindsight.md`` (always-on in Cascade)."""
- return Path.cwd() / ".windsurf" / "rules" / "hindsight.md"
+ """The workspace ``.devin/rules/hindsight.md`` (always-on in Devin Desktop)."""
+ return Path.cwd() / ".devin" / "rules" / "hindsight.md"
def render_rule(rule_text: str = RULE_TEXT) -> str:
diff --git a/hindsight-integrations/windsurf/pyproject.toml b/hindsight-integrations/devin-desktop/pyproject.toml
similarity index 77%
rename from hindsight-integrations/windsurf/pyproject.toml
rename to hindsight-integrations/devin-desktop/pyproject.toml
index 7acb0693c..5df2801a2 100644
--- a/hindsight-integrations/windsurf/pyproject.toml
+++ b/hindsight-integrations/devin-desktop/pyproject.toml
@@ -1,12 +1,12 @@
[project]
-name = "hindsight-windsurf"
+name = "hindsight-devin-desktop"
version = "0.1.0"
-description = "Windsurf (Codeium) integration for Hindsight - persistent long-term memory via MCP"
+description = "Devin Desktop (formerly Windsurf) integration for Hindsight - persistent long-term memory via MCP"
readme = "README.md"
requires-python = ">=3.10"
license = { text = "MIT" }
authors = [{ name = "Vectorize", email = "support@vectorize.io" }]
-keywords = ["ai", "memory", "windsurf", "codeium", "cascade", "agents", "hindsight", "mcp"]
+keywords = ["ai", "memory", "devin", "devin-desktop", "windsurf", "agents", "hindsight", "mcp"]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
@@ -20,11 +20,11 @@ classifiers = [
dependencies = []
[project.scripts]
-hindsight-windsurf = "hindsight_windsurf.cli:main"
+hindsight-devin-desktop = "hindsight_devin_desktop.cli:main"
[project.urls]
Homepage = "https://github.com/vectorize-io/hindsight"
-Documentation = "https://github.com/vectorize-io/hindsight/tree/main/hindsight-integrations/windsurf"
+Documentation = "https://github.com/vectorize-io/hindsight/tree/main/hindsight-integrations/devin-desktop"
Repository = "https://github.com/vectorize-io/hindsight"
[build-system]
@@ -32,7 +32,7 @@ requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
-packages = ["hindsight_windsurf"]
+packages = ["hindsight_devin_desktop"]
[tool.ruff]
line-length = 120
diff --git a/hindsight-integrations/windsurf/tests/__init__.py b/hindsight-integrations/devin-desktop/tests/__init__.py
similarity index 100%
rename from hindsight-integrations/windsurf/tests/__init__.py
rename to hindsight-integrations/devin-desktop/tests/__init__.py
diff --git a/hindsight-integrations/windsurf/tests/test_cli.py b/hindsight-integrations/devin-desktop/tests/test_cli.py
similarity index 86%
rename from hindsight-integrations/windsurf/tests/test_cli.py
rename to hindsight-integrations/devin-desktop/tests/test_cli.py
index 615b12d2d..3253c7fe5 100644
--- a/hindsight-integrations/windsurf/tests/test_cli.py
+++ b/hindsight-integrations/devin-desktop/tests/test_cli.py
@@ -2,18 +2,18 @@
import json
-from hindsight_windsurf.cli import build_install, main
-from hindsight_windsurf.config import WindsurfConfig
-from hindsight_windsurf.mcp_config import SERVER_NAME
-from hindsight_windsurf.mcp_config import is_installed as server_installed
-from hindsight_windsurf.rules import is_installed as rule_installed
+from hindsight_devin_desktop.cli import build_install, main
+from hindsight_devin_desktop.config import DevinDesktopConfig
+from hindsight_devin_desktop.mcp_config import SERVER_NAME
+from hindsight_devin_desktop.mcp_config import is_installed as server_installed
+from hindsight_devin_desktop.rules import is_installed as rule_installed
class TestBuildInstall:
def test_writes_mcp_and_rule(self, tmp_path):
mcp = tmp_path / "mcp_config.json"
rules = tmp_path / "rules" / "hindsight.md"
- cfg = WindsurfConfig(
+ cfg = DevinDesktopConfig(
hindsight_api_url="https://api.hindsight.vectorize.io", hindsight_api_token="k", bank_id="proj"
)
outcome = build_install(cfg, mcp, rules)
diff --git a/hindsight-integrations/windsurf/tests/test_config.py b/hindsight-integrations/devin-desktop/tests/test_config.py
similarity index 71%
rename from hindsight-integrations/windsurf/tests/test_config.py
rename to hindsight-integrations/devin-desktop/tests/test_config.py
index 2233da5ee..8d57a32b0 100644
--- a/hindsight-integrations/windsurf/tests/test_config.py
+++ b/hindsight-integrations/devin-desktop/tests/test_config.py
@@ -2,7 +2,7 @@
import json
-from hindsight_windsurf.config import DEFAULT_BANK_ID, DEFAULT_HINDSIGHT_API_URL, load_config
+from hindsight_devin_desktop.config import DEFAULT_BANK_ID, DEFAULT_HINDSIGHT_API_URL, load_config
def test_defaults(tmp_path):
@@ -13,7 +13,7 @@ def test_defaults(tmp_path):
def test_file_values(tmp_path):
- p = tmp_path / "windsurf.json"
+ p = tmp_path / "devin-desktop.json"
p.write_text(json.dumps({"hindsightApiToken": "t", "bankId": "proj"}))
cfg = load_config(config_file=p, env={})
assert cfg.hindsight_api_token == "t"
@@ -21,14 +21,14 @@ def test_file_values(tmp_path):
def test_env_overrides_file(tmp_path):
- p = tmp_path / "windsurf.json"
+ p = tmp_path / "devin-desktop.json"
p.write_text(json.dumps({"bankId": "from-file"}))
- cfg = load_config(config_file=p, env={"HINDSIGHT_WINDSURF_BANK_ID": "from-env", "HINDSIGHT_API_TOKEN": "k"})
+ cfg = load_config(config_file=p, env={"HINDSIGHT_DEVIN_DESKTOP_BANK_ID": "from-env", "HINDSIGHT_API_TOKEN": "k"})
assert cfg.bank_id == "from-env"
assert cfg.hindsight_api_token == "k"
def test_malformed_file_falls_back(tmp_path):
- p = tmp_path / "windsurf.json"
+ p = tmp_path / "devin-desktop.json"
p.write_text("{ broken")
assert load_config(config_file=p, env={}).bank_id == DEFAULT_BANK_ID
diff --git a/hindsight-integrations/windsurf/tests/test_e2e.py b/hindsight-integrations/devin-desktop/tests/test_e2e.py
similarity index 89%
rename from hindsight-integrations/windsurf/tests/test_e2e.py
rename to hindsight-integrations/devin-desktop/tests/test_e2e.py
index 3c18311da..25eb1cc95 100644
--- a/hindsight-integrations/windsurf/tests/test_e2e.py
+++ b/hindsight-integrations/devin-desktop/tests/test_e2e.py
@@ -8,7 +8,7 @@
import pytest
-from hindsight_windsurf.mcp_config import mcp_endpoint_url
+from hindsight_devin_desktop.mcp_config import mcp_endpoint_url
HINDSIGHT_API_URL = os.getenv("HINDSIGHT_API_URL", "http://localhost:8888")
HINDSIGHT_API_TOKEN = os.getenv("HINDSIGHT_API_TOKEN")
@@ -40,7 +40,7 @@ def _rpc(url, payload, session=None):
def test_mcp_endpoint_lists_memory_tools():
- url = mcp_endpoint_url(HINDSIGHT_API_URL, "windsurf-e2e")
+ url = mcp_endpoint_url(HINDSIGHT_API_URL, "devin-desktop-e2e")
init = {
"jsonrpc": "2.0",
"id": 1,
@@ -48,7 +48,7 @@ def test_mcp_endpoint_lists_memory_tools():
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
- "clientInfo": {"name": "windsurf-e2e", "version": "0"},
+ "clientInfo": {"name": "devin-desktop-e2e", "version": "0"},
},
}
resp = _rpc(url, init)
diff --git a/hindsight-integrations/windsurf/tests/test_mcp_config.py b/hindsight-integrations/devin-desktop/tests/test_mcp_config.py
similarity index 98%
rename from hindsight-integrations/windsurf/tests/test_mcp_config.py
rename to hindsight-integrations/devin-desktop/tests/test_mcp_config.py
index 2c88d83b2..cc2b73752 100644
--- a/hindsight-integrations/windsurf/tests/test_mcp_config.py
+++ b/hindsight-integrations/devin-desktop/tests/test_mcp_config.py
@@ -2,7 +2,7 @@
import json
-from hindsight_windsurf.mcp_config import (
+from hindsight_devin_desktop.mcp_config import (
SERVER_NAME,
apply_to_mcp,
build_http_server,
diff --git a/hindsight-integrations/windsurf/tests/test_rules.py b/hindsight-integrations/devin-desktop/tests/test_rules.py
similarity index 76%
rename from hindsight-integrations/windsurf/tests/test_rules.py
rename to hindsight-integrations/devin-desktop/tests/test_rules.py
index a0810ce3e..bd73a206d 100644
--- a/hindsight-integrations/windsurf/tests/test_rules.py
+++ b/hindsight-integrations/devin-desktop/tests/test_rules.py
@@ -1,6 +1,21 @@
-"""Tests for the .windsurf/rules/hindsight.md rule writer."""
+"""Tests for the .devin/rules/hindsight.md rule writer."""
-from hindsight_windsurf.rules import RULE_TEXT, SENTINEL, clear_rule, is_installed, render_rule, write_rule
+from hindsight_devin_desktop.rules import (
+ RULE_TEXT,
+ SENTINEL,
+ clear_rule,
+ default_rules_path,
+ is_installed,
+ render_rule,
+ write_rule,
+)
+
+
+def test_default_path_is_devin_rules():
+ p = default_rules_path()
+ assert p.parent.name == "rules"
+ assert p.parent.parent.name == ".devin"
+ assert p.name == "hindsight.md"
def test_write_creates_dedicated_file(tmp_path):
diff --git a/hindsight-integrations/windsurf/uv.lock b/hindsight-integrations/devin-desktop/uv.lock
similarity index 78%
rename from hindsight-integrations/windsurf/uv.lock
rename to hindsight-integrations/devin-desktop/uv.lock
index 83b71a1eb..70a2ce5e3 100644
--- a/hindsight-integrations/windsurf/uv.lock
+++ b/hindsight-integrations/devin-desktop/uv.lock
@@ -24,7 +24,7 @@ wheels = [
]
[[package]]
-name = "hindsight-windsurf"
+name = "hindsight-devin-desktop"
version = "0.1.0"
source = { editable = "." }
@@ -98,27 +98,27 @@ wheels = [
[[package]]
name = "ruff"
-version = "0.15.18"
+version = "0.15.19"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/74/98/1295ad5a5aa9bc85bdcdfa5d82fe7b49c61af5657df4f227637ff9de0da6/ruff-0.15.18.tar.gz", hash = "sha256:2698a964c70e8bf402dcb99c8810472d270d141e7aa8c4e13599fd52033a2f33", size = 4761437, upload-time = "2026-06-18T18:25:39.224Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/d5/e6/15800dfde183a1a106594016c912b4c12d050a301989d1aca6cb63759fe8/ruff-0.15.19.tar.gz", hash = "sha256:edc27f7172a93b32b102687009d6a588508815072141543ae603a8b9b0823063", size = 4772071, upload-time = "2026-06-24T01:10:46.942Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/b9/d0/686e984941269621e2be72612d5c1e461f8f7b38415a2a7d7a81c8ae6715/ruff-0.15.18-py3-none-linux_armv6l.whl", hash = "sha256:8b6850172348c8381b8b3084c5915a4393c2373b9b54cd5b5e1ea15812bc10df", size = 10887308, upload-time = "2026-06-18T18:25:03.062Z" },
- { url = "https://files.pythonhosted.org/packages/ed/21/bc4123e3f5515ee99f8ce1eb93a14a0628fe4d1678663cd08f933ac16931/ruff-0.15.18-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:3fccc153a85417dcd976883160cacce486997b0a0058dd18f54b8aaaac7d1ce2", size = 11281305, upload-time = "2026-06-18T18:25:30.026Z" },
- { url = "https://files.pythonhosted.org/packages/51/93/4769464c25cf7ab2acb3c7dda9cad3d867eb41c59565b3e2a9d17249c90c/ruff-0.15.18-py3-none-macosx_11_0_arm64.whl", hash = "sha256:08d4c86a68f2c3ec2c9d56380a71fb4a4f65373055cbb8caabd645e9102f38d4", size = 10641215, upload-time = "2026-06-18T18:25:15.802Z" },
- { url = "https://files.pythonhosted.org/packages/6c/42/56926d17120db2c208d76bf60a1a019644dd9e91dc27f0f95c9caddb1366/ruff-0.15.18-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37e5108745c2c0705da916d7d4de533ddf547051ef45f62888c31bae73f66318", size = 10957224, upload-time = "2026-06-18T18:25:36.955Z" },
- { url = "https://files.pythonhosted.org/packages/22/4f/d43fab8d8189afde803103022d000a8ef9f230616d436d52a8b2b8d63b50/ruff-0.15.18-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:56949a6ce8b3abde54c0bcb22cebfe57e8771cadc84b407ae8b8eaf67ebdcd43", size = 10699024, upload-time = "2026-06-18T18:25:05.707Z" },
- { url = "https://files.pythonhosted.org/packages/63/42/1e3e4c68bd408b9768cf3e439acbe2c78245225faef253f7028a0cdb63e0/ruff-0.15.18-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01a754cd6a1b630d3f97e33eb452cf7a98040482318e870f8bc52a5a30e62657", size = 11491458, upload-time = "2026-06-18T18:25:20.275Z" },
- { url = "https://files.pythonhosted.org/packages/20/77/47a3484bea8521e14a203d98c389c5c97846675e4f02734672da4a69b52a/ruff-0.15.18-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6ba7a07e03a44dbf10bb086ee06705b173625014ec99f73a7e6836a5e5590a0c", size = 12383752, upload-time = "2026-06-18T18:25:22.535Z" },
- { url = "https://files.pythonhosted.org/packages/0a/ca/054159590787023d83b658a1a1819c4c8910114e7015069340b71c0961cb/ruff-0.15.18-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a2c40a41a4cadbcf5897b548ab29dfe248b20c540961c0247d98a3973c70403", size = 11577923, upload-time = "2026-06-18T18:25:10.702Z" },
- { url = "https://files.pythonhosted.org/packages/6d/ff/d353d6b7bbd73cc0ec37f4463d7540e45e894338abdd9964eee0de332708/ruff-0.15.18-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f0480ce690cbb6c4db6e5d08f19fce98e10ba131a8b60c1bcdac42771e3ae2d", size = 11583925, upload-time = "2026-06-18T18:25:32.391Z" },
- { url = "https://files.pythonhosted.org/packages/c1/4a/891f89b9c296ed3e5f3ece1a5629badc989d9a8fdaa30431aaf4774bc1c2/ruff-0.15.18-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:2330215f1f393fa8733f55edce04fcf94c36a2c460fcde31f78cc84e4951e9b1", size = 11582834, upload-time = "2026-06-18T18:25:27.309Z" },
- { url = "https://files.pythonhosted.org/packages/32/a3/ed9e370154bf85de360b93c03026157f02d4943b2d01ff4945f4429f8e8a/ruff-0.15.18-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a6aa6a3d979e48ae617578183674bf264fbe7d0114a796a26bd678d67963c7ff", size = 10927328, upload-time = "2026-06-18T18:25:34.676Z" },
- { url = "https://files.pythonhosted.org/packages/f5/d1/5cf5909329fedb5d39d555ee818ba5cf4638e1a301b89785d34f2905bfcb/ruff-0.15.18-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a81beadbbff2c9c245561ae3f77b16709d87f35eec650d0501679239d3449b22", size = 10693187, upload-time = "2026-06-18T18:25:08.245Z" },
- { url = "https://files.pythonhosted.org/packages/fd/44/ff6c635cf2c4f4e7b618b6640da057376baa36014695487d88aed4794268/ruff-0.15.18-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2186d9e940ae332ab293623a75b5f4fe49565f449954d50a72a046683aa6b809", size = 11208721, upload-time = "2026-06-18T18:25:41.327Z" },
- { url = "https://files.pythonhosted.org/packages/88/d9/5baa2a30861adfb7022cf33c1e35b2fc18085b08c16f83eff4c7b99a5f48/ruff-0.15.18-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5c2abf140438032bc77b2284a6c9944ecd8a19e5f1c7b52b1b8e4a0a80d19a7a", size = 11678599, upload-time = "2026-06-18T18:25:13.607Z" },
- { url = "https://files.pythonhosted.org/packages/c3/1a/0725a7cfdc32ff769efb96ee782bec882e16448c5d9e3be947ec4c04ce27/ruff-0.15.18-py3-none-win32.whl", hash = "sha256:02299e6e9fa5b297a3f6d5d10d7bcd655c925b028bb8b9d4588214549c6b9ec4", size = 10901903, upload-time = "2026-06-18T18:25:24.755Z" },
- { url = "https://files.pythonhosted.org/packages/f3/51/805d9f6fb7970505c3504794a5ec350f605361b807fef4dcf214ebd35e72/ruff-0.15.18-py3-none-win_amd64.whl", hash = "sha256:dac80dc8d26b2257dbefabed62f5d255c3937b4ccb122da1fc634794fa3578b3", size = 12041189, upload-time = "2026-06-18T18:25:17.915Z" },
- { url = "https://files.pythonhosted.org/packages/29/4c/67bb45e41609eb4726f1bfeb59e083cf91d14c696d4bd14c234a980be93d/ruff-0.15.18-py3-none-win_arm64.whl", hash = "sha256:b2c9257fcbd4a3e5b977a1904e6facca016bafe2edc17df24db67cfaee03b4e4", size = 11329958, upload-time = "2026-06-18T18:25:43.686Z" },
+ { url = "https://files.pythonhosted.org/packages/88/4c/9ded7626c39a0440c575bf69e2bf500d443388272c842662c59852ee7fcd/ruff-0.15.19-py3-none-linux_armv6l.whl", hash = "sha256:922d1eb283161564759bd49f507e91dc6112c15da8bd5b84ed714e086243cf86", size = 10950859, upload-time = "2026-06-24T01:10:38.491Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/ef/c211505ece1d00ef493d58e54e3b6383c946a21e9874774eb531f2512cf3/ruff-0.15.19-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:4d190d8f62a0b94aba8f721116538a9ee29b1e74d26650846ba9b99f0ae21c40", size = 11294529, upload-time = "2026-06-24T01:10:36.481Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/93/78d462e7d39968e58094dc57be7d09ffb14ce37da5b68ed70338a35a1f21/ruff-0.15.19-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5a2c86ba6870dd415a9d9eb8be94d7924ebec6a26ffc7958ec7ca29d4bff967d", size = 10641416, upload-time = "2026-06-24T01:10:48.923Z" },
+ { url = "https://files.pythonhosted.org/packages/76/c4/5cb66cfd1f865d5cca908b86c93ac785e7f572193d3c7426079ca6643e24/ruff-0.15.19-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82b432bc087264aea70fd25ac198918b70bd9e2aa0db4297b0bb91bbfbbc63ce", size = 11015582, upload-time = "2026-06-24T01:10:30.089Z" },
+ { url = "https://files.pythonhosted.org/packages/51/9f/8ecfaec10cf5eecd28fbc00ff4fb867db90a1be54bf3d39ebf93f893cd52/ruff-0.15.19-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8530a09d03b3a8c994f8b559a7dcdabc690bcd3f78ef276c38c83166798ebf56", size = 10744059, upload-time = "2026-06-24T01:10:32.48Z" },
+ { url = "https://files.pythonhosted.org/packages/35/6b/983249d04562bc2d590edd75f32455cdb473affb3ba4bc8d883e939c697d/ruff-0.15.19-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87bf21fb3875fe69f0eacc825411657e2e85589cce633c35c0adf1113649c62b", size = 11568461, upload-time = "2026-06-24T01:10:17.435Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/39/bc7794f127b18f492a3b4ee82bba5a900c985ff13b72b46f46e3c171ba34/ruff-0.15.19-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f9b229cb3ef56ecc2c1c8ebeca64b7a7740ccaef40a9eb097e78dde5a8560b83", size = 12429690, upload-time = "2026-06-24T01:10:40.638Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/3b/0de6859e698ed11c8a49e765196c8d333599b6a546c0715df39b6ba1aa2e/ruff-0.15.19-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6c754515be7b76afe6e7e62df7776709571bcfc1631183828afcf3bafa869e3", size = 11693067, upload-time = "2026-06-24T01:10:25.681Z" },
+ { url = "https://files.pythonhosted.org/packages/89/3d/0b1f30f84bee9ae6ae8d349c2ba8b6f4b040966744efdd3acc804ae7c024/ruff-0.15.19-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a498f82e0f4d8904c4e0aea5139cdfac1f39d19a3c51d491292f63a36e83b2e", size = 11616911, upload-time = "2026-06-24T01:10:44.809Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/eb/c90bd3dfc12eed9032c2c1bfe05105b93a1b2c8bce555db6308315b853ce/ruff-0.15.19-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:d48caa34488fb521fd0ef4aea2b0e8fe758298df044138f0d67b687a6a0d07ed", size = 11649343, upload-time = "2026-06-24T01:10:23.472Z" },
+ { url = "https://files.pythonhosted.org/packages/82/91/01caa13602a2f12fae5edbe8caf78b3c1e6db1293132aee6959eecce095c/ruff-0.15.19-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4171b6613effa9363cd46dd4f75bd1827b6d1b946b5e278ed0c600d305379445", size = 10977610, upload-time = "2026-06-24T01:10:50.892Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/51/acb817922feab9ecbb3201377d4dbe7a25f1395e46545820061973f03468/ruff-0.15.19-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:27c15b2a241dd4d995557949a094fe78b8ad99122a38ccae1595849bcc947b3f", size = 10744900, upload-time = "2026-06-24T01:10:42.726Z" },
+ { url = "https://files.pythonhosted.org/packages/84/bc/5c8ca46b8a7a3f2b16cfbec88721d772b1c93912904e8f8c2e49470fea63/ruff-0.15.19-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ed03b7862d68f0a8771d50ee129980cbf1b113f96e250b73954bc292f689e0bb", size = 11293560, upload-time = "2026-06-24T01:10:21.262Z" },
+ { url = "https://files.pythonhosted.org/packages/81/e0/4a888cbe4d5523b3f77a2b1fa043f46cfeba1b32eac35dcfadee0578fa8a/ruff-0.15.19-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:08143f0685ae278b30727ea72e90c61e5bd9c31b91aac4f5bb989538f73d24b8", size = 11696533, upload-time = "2026-06-24T01:10:53.046Z" },
+ { url = "https://files.pythonhosted.org/packages/98/43/c34b2fcd79262a85161764a97aaca89c3e4f574340ab61430cefa2bdd2c1/ruff-0.15.19-py3-none-win32.whl", hash = "sha256:8f47f0f92952af2557212bb10cf3e695cd4cf28b2c6e42cdb18ec6c9ebfa19da", size = 10986299, upload-time = "2026-06-24T01:10:55.185Z" },
+ { url = "https://files.pythonhosted.org/packages/22/e8/15fd23e02b2442b56b2026b455977bc3057aa34b26e6323d1e99e8531a9f/ruff-0.15.19-py3-none-win_amd64.whl", hash = "sha256:efeca47ee3f9d4a7162655a3b8e6ee4a878646044233978d4d2c1ff8cdd914f0", size = 12123473, upload-time = "2026-06-24T01:10:27.74Z" },
+ { url = "https://files.pythonhosted.org/packages/30/66/9a73695e31eaee04f35d8475998bf8ab354465f9c638936d76111603dcc5/ruff-0.15.19-py3-none-win_arm64.whl", hash = "sha256:6c6b607466e47349332eb1d9be52fb1467423fc07c217341af41cd0f3f0573be", size = 11376779, upload-time = "2026-06-24T01:10:34.465Z" },
]
[[package]]
diff --git a/hindsight-integrations/windsurf/README.md b/hindsight-integrations/windsurf/README.md
deleted file mode 100644
index 461a6e1b8..000000000
--- a/hindsight-integrations/windsurf/README.md
+++ /dev/null
@@ -1,79 +0,0 @@
-# hindsight-windsurf
-
-Long-term memory for **Windsurf** (Codeium), powered by [Hindsight](https://github.com/vectorize-io/hindsight).
-
-`hindsight-windsurf init` wires the Hindsight **MCP server** into Windsurf's
-`~/.codeium/windsurf/mcp_config.json` and adds an always-on recall/retain rule to
-`.windsurf/rules/hindsight.md`. Cascade then has `recall` / `retain` / `reflect`
-tools and — guided by the rule — recalls relevant memory at the start of a task
-and retains durable facts as it works.
-
-## How it works
-
-Windsurf supports two things this integration uses:
-
-- **MCP servers** in `~/.codeium/windsurf/mcp_config.json` under `mcpServers`,
- including **remote servers** via `serverUrl` with headers — so the Hindsight
- MCP endpoint connects directly:
-
- ```json
- {
- "mcpServers": {
- "hindsight": {
- "serverUrl": "https://api.hindsight.vectorize.io/mcp/my-project/",
- "headers": { "Authorization": "Bearer hsk_..." }
- }
- }
- }
- ```
-
-- **Workspace rules** in `.windsurf/rules/`. A rule file with `trigger: always_on`
- frontmatter is applied to every Cascade request in the workspace — that's where
- the recall/retain rule lives.
-
-## Install
-
-```bash
-pip install hindsight-windsurf
-cd your-project
-hindsight-windsurf init --api-token YOUR_HINDSIGHT_API_KEY --bank-id my-project
-```
-
-`init` merges the `mcpServers` entry into `~/.codeium/windsurf/mcp_config.json`
-(Windsurf's single global MCP config) and writes the rule into
-`./.windsurf/rules/hindsight.md`. Reload Windsurf (or refresh MCP servers in
-Cascade) and the `hindsight` tools are available.
-
-Use a [Hindsight Cloud](https://hindsight.vectorize.io) key, or a self-hosted
-server with `--api-url http://localhost:8888` (no token needed for an open local
-server). If `mcp_config.json` isn't plain JSON, `init` prints the snippet to
-paste instead of touching the file — or run `hindsight-windsurf init --print-only`
-anytime.
-
-## Commands
-
-| Command | Description |
-| --- | --- |
-| `hindsight-windsurf init` | Add the MCP server + recall/retain rule |
-| `hindsight-windsurf status` | Show whether the server + rule are configured |
-| `hindsight-windsurf uninstall` | Remove the server + rule |
-
-## Configuration
-
-| Setting | Env var | Default |
-| --- | --- | --- |
-| API URL | `HINDSIGHT_API_URL` | `https://api.hindsight.vectorize.io` |
-| API token | `HINDSIGHT_API_TOKEN` | _(none; required for Cloud)_ |
-| Bank id | `HINDSIGHT_WINDSURF_BANK_ID` | `windsurf` |
-
-## Development
-
-```bash
-uv sync
-uv run pytest tests -v -m 'not requires_real_llm' # deterministic suite
-uv run pytest tests -v -m requires_real_llm # gated MCP-endpoint check
-```
-
-## License
-
-MIT
diff --git a/hindsight-integrations/windsurf/hindsight_windsurf/__init__.py b/hindsight-integrations/windsurf/hindsight_windsurf/__init__.py
deleted file mode 100644
index 240f9af91..000000000
--- a/hindsight-integrations/windsurf/hindsight_windsurf/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-"""Hindsight memory integration for Windsurf (Codeium).
-
-Wires the Hindsight MCP server into Windsurf's ``~/.codeium/windsurf/mcp_config.json``
-and writes an always-on recall/retain rule into ``.windsurf/rules/hindsight.md``,
-so Cascade has ``recall``/``retain``/``reflect`` tools and uses them automatically.
-
-CLI::
-
- hindsight-windsurf init --api-token hsk_... --bank-id my-project
-"""
-
-__version__ = "0.1.0"
diff --git a/scripts/release-integration.sh b/scripts/release-integration.sh
index 67ae59c75..370387d17 100755
--- a/scripts/release-integration.sh
+++ b/scripts/release-integration.sh
@@ -13,7 +13,7 @@ print_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
print_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
print_error() { echo -e "${RED}[ERROR]${NC} $1"; }
-VALID_INTEGRATIONS=("ag2" "agent-framework" "agentcore" "agno" "aider" "ai-sdk" "autogen" "chat" "claude-agent-sdk" "claude-code" "cline" "cloudflare-oauth-proxy" "codex" "composio" "continue" "crewai" "cursor" "cursor-cli" "dify" "eve" "flowise" "gemini-spark" "github-copilot" "google-adk" "haystack" "langgraph" "litellm" "llamaindex" "n8n" "nemoclaw" "obsidian" "omo" "openai-agents" "openclaw" "opencode" "openhands" "paperclip" "pipecat" "pydantic-ai" "roo-code" "smolagents" "strands" "superagent" "vapi" "windsurf" "zed")
+VALID_INTEGRATIONS=("ag2" "agent-framework" "agentcore" "agno" "aider" "ai-sdk" "autogen" "chat" "claude-agent-sdk" "claude-code" "cline" "cloudflare-oauth-proxy" "codex" "composio" "continue" "crewai" "cursor" "cursor-cli" "devin-desktop" "dify" "eve" "flowise" "gemini-spark" "github-copilot" "google-adk" "haystack" "langgraph" "litellm" "llamaindex" "n8n" "nemoclaw" "obsidian" "omo" "openai-agents" "openclaw" "opencode" "openhands" "paperclip" "pipecat" "pydantic-ai" "roo-code" "smolagents" "strands" "superagent" "vapi" "zed")
usage() {
print_error "Usage: $0 "