Skip to content

Commit fcb2c95

Browse files
DK09876claude
andauthored
feat(devin-desktop): rename Windsurf→Devin Desktop + fix(continue) thread-safe adapter (#2410)
* feat(devin-desktop): rename windsurf integration to Devin Desktop Cognition rebranded Windsurf to Devin Desktop (June 2026); Cascade is EOL July 1. Rename the (unreleased) windsurf integration to devin-desktop before first publish: - Package hindsight-windsurf -> hindsight-devin-desktop (module hindsight_devin_desktop, CLI hindsight-devin-desktop, DevinDesktopConfig, bank default 'devin-desktop', HINDSIGHT_DEVIN_DESKTOP_BANK_ID) - Rule now writes to .devin/rules/hindsight.md (preferred path) instead of the legacy .windsurf/rules/; trigger: always_on unchanged - MCP config path stays ~/.codeium/windsurf/mcp_config.json (Devin Desktop's on-disk data dir, unchanged by the rebrand) - Official Devin logo; docs + integrations.json + README refreshed with the 'formerly Windsurf' framing - Registries updated: test.yml job, release-integration.sh, generate_changelog, integrations.json (strict JSON), docs page 26 unit tests + gated live-MCP E2E pass; ruff check+format clean; real-app smoke against local Hindsight verified (init writes both files; live recall returns seeded facts). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(continue): resolve a fresh Hindsight client per request (thread-safe) The adapter runs on a ThreadingHTTPServer (one worker thread per request) but shared a single Hindsight client across all of them. The client's aiohttp session is bound to the thread/event-loop that first used it, so the first @hindsight recall worked and every one after threw 'Timeout context manager should be used inside a task' — Continue then showed an error context item and the model answered with no memory. Resolve the client per request (test-injected clients still used as-is), and close per-request clients in a finally so the fresh aiohttp session doesn't leak a connector each call. Bump to 0.1.1. Found via a real in-editor VS Code test. Adds a regression test asserting per-request client resolution across the threaded server. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 758f346 commit fcb2c95

30 files changed

Lines changed: 329 additions & 249 deletions

File tree

.github/workflows/test.yml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ jobs:
6161
integrations-lockfiles: ${{ steps.filter.outputs.integrations-lockfiles }}
6262
integrations-openai-agents: ${{ steps.filter.outputs.integrations-openai-agents }}
6363
integrations-openhands: ${{ steps.filter.outputs.integrations-openhands }}
64-
integrations-windsurf: ${{ steps.filter.outputs.integrations-windsurf }}
64+
integrations-devin-desktop: ${{ steps.filter.outputs.integrations-devin-desktop }}
6565
integrations-pipecat: ${{ steps.filter.outputs.integrations-pipecat }}
6666
integrations-agentcore: ${{ steps.filter.outputs.integrations-agentcore }}
6767
integrations-smolagents: ${{ steps.filter.outputs.integrations-smolagents }}
@@ -196,8 +196,8 @@ jobs:
196196
- 'hindsight-integrations/openai-agents/**'
197197
integrations-openhands:
198198
- 'hindsight-integrations/openhands/**'
199-
integrations-windsurf:
200-
- 'hindsight-integrations/windsurf/**'
199+
integrations-devin-desktop:
200+
- 'hindsight-integrations/devin-desktop/**'
201201
integrations-pipecat:
202202
- 'hindsight-integrations/pipecat/**'
203203
integrations-agentcore:
@@ -3866,11 +3866,11 @@ jobs:
38663866
# (requires_real_llm) needs a live Hindsight server and runs separately.
38673867
run: uv run pytest tests -v -m "not requires_real_llm"
38683868

3869-
test-windsurf-integration:
3869+
test-devin-desktop-integration:
38703870
needs: [detect-changes]
38713871
if: >-
38723872
(github.event_name == 'workflow_dispatch' ||
3873-
needs.detect-changes.outputs.integrations-windsurf == 'true' ||
3873+
needs.detect-changes.outputs.integrations-devin-desktop == 'true' ||
38743874
needs.detect-changes.outputs.ci == 'true')
38753875
runs-on: ubuntu-latest
38763876
timeout-minutes: 30
@@ -3891,16 +3891,16 @@ jobs:
38913891
with:
38923892
python-version-file: ".python-version"
38933893

3894-
- name: Build windsurf integration
3895-
working-directory: ./hindsight-integrations/windsurf
3894+
- name: Build devin-desktop integration
3895+
working-directory: ./hindsight-integrations/devin-desktop
38963896
run: uv build
38973897

38983898
- name: Install dependencies
3899-
working-directory: ./hindsight-integrations/windsurf
3899+
working-directory: ./hindsight-integrations/devin-desktop
39003900
run: uv sync --frozen
39013901

39023902
- name: Run tests
3903-
working-directory: ./hindsight-integrations/windsurf
3903+
working-directory: ./hindsight-integrations/devin-desktop
39043904
# PR CI runs only the deterministic bucket; the real-LLM E2E bucket
39053905
# (requires_real_llm) needs a live Hindsight server and runs separately.
39063906
run: uv run pytest tests -v -m "not requires_real_llm"
@@ -4957,7 +4957,7 @@ jobs:
49574957
- test-llamaindex-integration
49584958
- test-openai-agents-integration
49594959
- test-openhands-integration
4960-
- test-windsurf-integration
4960+
- test-devin-desktop-integration
49614961
- test-agentcore-integration
49624962
- test-haystack-integration
49634963
- test-pip-slim

hindsight-dev/hindsight_dev/generate_changelog.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ class IntegrationMeta:
8282
"continue": IntegrationMeta("hindsight-continue", "Continue"),
8383
"zed": IntegrationMeta("hindsight-zed", "Zed"),
8484
"openhands": IntegrationMeta("hindsight-openhands", "OpenHands"),
85-
"windsurf": IntegrationMeta("hindsight-windsurf", "Windsurf"),
85+
"devin-desktop": IntegrationMeta("hindsight-devin-desktop", "Devin Desktop"),
8686
}
8787

8888
VALID_INTEGRATIONS = list(INTEGRATIONS.keys())
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
---
2+
sidebar_position: 7
3+
title: "Devin Desktop Persistent Memory with Hindsight | Integration"
4+
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."
5+
---
6+
7+
# Devin Desktop
8+
9+
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.
10+
11+
:::note
12+
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).
13+
:::
14+
15+
## How It Works
16+
17+
Devin Desktop supports two things this integration uses:
18+
19+
- **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.
20+
- **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.
21+
22+
## Setup
23+
24+
```bash
25+
pip install hindsight-devin-desktop
26+
cd your-project
27+
hindsight-devin-desktop init --api-token YOUR_HINDSIGHT_API_KEY --bank-id my-memory
28+
```
29+
30+
`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.
31+
32+
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.
33+
34+
## Commands
35+
36+
| Command | Description |
37+
| --- | --- |
38+
| `hindsight-devin-desktop init` | Add the MCP server + recall/retain rule |
39+
| `hindsight-devin-desktop status` | Show whether the server + rule are configured |
40+
| `hindsight-devin-desktop uninstall` | Remove the server + rule |
41+
42+
## Note
43+
44+
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.
45+
46+
See the [package README](https://github.com/vectorize-io/hindsight/tree/main/hindsight-integrations/devin-desktop) for full configuration options.

hindsight-docs/docs-integrations/windsurf.md

Lines changed: 0 additions & 42 deletions
This file was deleted.

hindsight-docs/src/data/integrations.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -571,14 +571,14 @@
571571
"icon": "/img/icons/openhands.png"
572572
},
573573
{
574-
"id": "windsurf",
575-
"name": "Windsurf",
576-
"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.",
574+
"id": "devin-desktop",
575+
"name": "Devin Desktop",
576+
"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.",
577577
"type": "official",
578578
"by": "hindsight",
579579
"category": "tool",
580-
"link": "/sdks/integrations/windsurf",
581-
"icon": "/img/icons/windsurf.svg"
580+
"link": "/sdks/integrations/devin-desktop",
581+
"icon": "/img/icons/devin-desktop.svg"
582582
},
583583
{
584584
"id": "epimetheus",
Lines changed: 1 addition & 0 deletions
Loading

hindsight-docs/static/img/icons/windsurf.svg

Lines changed: 0 additions & 1 deletion
This file was deleted.

hindsight-integrations/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Each integration lives in its own subdirectory with its own README, configuratio
1414
| [**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` |
1515
| [**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` |
1616
| [**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` |
17-
| [**Windsurf**](./windsurf) | Native MCP server config + always-on recall/retain rule for Windsurf (Codeium) Cascade. | `pip install hindsight-windsurf` |
17+
| [**Devin Desktop**](./devin-desktop) | Native MCP server config + always-on recall/retain rule for Devin Desktop (formerly Windsurf). | `pip install hindsight-devin-desktop` |
1818
| [**Roo Code**](./roo-code) | Persistent memory for Roo Code VS Code extension. | See README |
1919
| [**Hermes (OpenAI Agents SDK)**](./hermes) | Memory layer for OpenAI Agents SDK. | See README |
2020
| [**Grok Build**](./grok-build) | Hooks for Grok Build (xAI). | See README |

hindsight-integrations/continue/hindsight_continue/server.py

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,19 @@
2525
_MAX_BODY_BYTES = 1_000_000
2626

2727

28-
def make_handler(client: Hindsight, config: HindsightContinueConfig):
29-
"""Build a request-handler class bound to a client and config."""
28+
def make_handler(config: HindsightContinueConfig, client: Optional[Hindsight] = None):
29+
"""Build a request-handler class.
30+
31+
When ``client`` is None (production), a fresh Hindsight client is resolved
32+
**per request**. This is deliberate: the adapter runs on a
33+
:class:`ThreadingHTTPServer` (one worker thread per request), and the
34+
Hindsight client's underlying aiohttp session is bound to the thread /
35+
event loop that first used it. A single shared client therefore succeeds on
36+
the first request and then raises ``Timeout context manager should be used
37+
inside a task`` on every request after it. Resolving per request keeps each
38+
recall on its own thread's client. Tests may inject a client directly (they
39+
drive the handler single-threaded).
40+
"""
3041

3142
class _Handler(BaseHTTPRequestHandler):
3243
# Quiet the default per-request stderr logging; route through our logger.
@@ -66,8 +77,10 @@ def do_POST(self) -> None: # noqa: N802 - stdlib signature
6677
self._write_json(400, {"error": "request body must be a JSON object"})
6778
return
6879

80+
request_client = None
6981
try:
70-
items = build_context_items(payload, client=client, config=config)
82+
request_client = client if client is not None else resolve_client()
83+
items = build_context_items(payload, client=request_client, config=config)
7184
except HindsightError as e:
7285
# Surface the failure so it shows up in Continue's warnings rather
7386
# than silently returning no memory.
@@ -77,6 +90,15 @@ def do_POST(self) -> None: # noqa: N802 - stdlib signature
7790
logger.exception("Unexpected error handling context request")
7891
self._write_json(500, {"error": f"internal error: {e}"})
7992
return
93+
finally:
94+
# Close only a client we created here (a per-request client),
95+
# not a test-injected one. Otherwise the fresh aiohttp session
96+
# leaks a connector every request on the long-running server.
97+
if client is None and request_client is not None:
98+
try:
99+
request_client.close()
100+
except Exception: # pragma: no cover - best-effort cleanup
101+
logger.debug("client close failed", exc_info=True)
80102

81103
self._write_json(200, serialize(items))
82104

@@ -88,8 +110,10 @@ def build_server(
88110
) -> ThreadingHTTPServer:
89111
"""Create (but do not start) the adapter HTTP server."""
90112
config = config or get_config()
91-
client = client or resolve_client()
92-
handler = make_handler(client, config)
113+
# Do not pre-resolve a shared client: pass it through so the handler resolves
114+
# a fresh client per request (see make_handler). A test-injected client is
115+
# used as-is.
116+
handler = make_handler(config, client)
93117
return ThreadingHTTPServer((config.host, config.port), handler)
94118

95119

hindsight-integrations/continue/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "hindsight-continue"
3-
version = "0.1.0"
3+
version = "0.1.1"
44
description = "Continue.dev integration for Hindsight - persistent long-term memory via an HTTP context provider"
55
readme = "README.md"
66
requires-python = ">=3.10"

0 commit comments

Comments
 (0)