Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand All @@ -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"
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion hindsight-dev/hindsight_dev/generate_changelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
46 changes: 46 additions & 0 deletions hindsight-docs/docs-integrations/devin-desktop.md
Original file line number Diff line number Diff line change
@@ -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.
42 changes: 0 additions & 42 deletions hindsight-docs/docs-integrations/windsurf.md

This file was deleted.

10 changes: 5 additions & 5 deletions hindsight-docs/src/data/integrations.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
1 change: 1 addition & 0 deletions hindsight-docs/static/img/icons/devin-desktop.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion hindsight-docs/static/img/icons/windsurf.svg

This file was deleted.

2 changes: 1 addition & 1 deletion hindsight-integrations/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
34 changes: 29 additions & 5 deletions hindsight-integrations/continue/hindsight_continue/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand All @@ -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))

Expand All @@ -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)


Expand Down
2 changes: 1 addition & 1 deletion hindsight-integrations/continue/pyproject.toml
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
Loading
Loading