feat(devin-desktop): two-tier bank scoping + visible memory use (v0.2.0) - #2692
Merged
Conversation
Reworks the Devin Desktop integration from a single hardcoded `devin-desktop` bank (all projects share one memory pool) to per-project isolation plus a shared cross-project bank, and makes Hindsight usage visible in chat. Scoping (multi-bank mode): - Connect to the multi-bank `/mcp/` endpoint (was `/mcp/<bank>/`); the model routes `bank_id` per call, guided by the committed rule. - Global bank `devin-desktop` (user prefs/style) named in global_rules.md; per-project bank `devin-desktop-<slug>` derived from the git remote (stable across machines/teammates) named in the committed .devin/rules/hindsight.md. - `X-Bank-Id: <global>` header as the fallback bank when the model omits it. - Verified against live Cloud: bank_id routing + full isolation (no cross-bank leak) + read-after-write via sync_retain. Visibility (no sound, per product decision): - Rule now tells the agent to briefly acknowledge memory use in chat (reverses the prior "do not mention" line) and to use `reflect`/`sync_retain`. Audit fixes: - Write both documented MCP config locations (`~/.codeium/windsurf/` and `~/.codeium/`) since Devin's own docs disagree on the path. - Explicit "press Refresh in the MCP panel" step (config doesn't hot-reload). New modules: project.py (git-derivation), global_rules.py (global_rules.md managed block). Backward-compatible: legacy `bankId` config maps to the global bank. 55 tests pass; ruff clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WEHyNxWfn1miSWRW6NUtEW
DK09876
force-pushed
the
devin-desktop-multibank-0.2.0
branch
from
July 13, 2026 17:24
d7f477c to
c8d0ba8
Compare
Devin Desktop ships two agents with separate config, and the prior version only wired Cascade — so a user on Devin Local (the successor agent) got no memory. `init` now configures both: Cascade (unchanged): ~/.codeium/windsurf/mcp_config.json (serverUrl), .devin/rules/hindsight.md, ~/.codeium/windsurf/memories/global_rules.md. Devin Local (new): - ~/.config/devin/config.json — mcpServers.hindsight with `url` + `transport:"http"` + `headers` (Devin Local's schema, not Cascade's `serverUrl`); preserves other keys (e.g. version). - permissions.allow += "mcp__hindsight__*" — Devin Local prompts before every MCP tool by default; this makes recall/retain run automatically. - AGENTS.md always-on rules (Devin Local doesn't read .devin/rules/): repo-root AGENTS.md (per-project) + ~/.config/devin/AGENTS.md (global), each a fenced managed block that preserves user content. New modules: devin_local.py, managed_block.py (shared block writer, also used by global_rules.py). Same multi-bank + routing-rule design across both agents. status/uninstall cover both. README + docstrings updated. 74 tests pass; ruff clean (ruff 0.14.9 + root config). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WEHyNxWfn1miSWRW6NUtEW
…init Devin Local registers the MCP server from config.json but requires an explicit Connect click in the Devin MCP Marketplace (verified in-app). init output and README now spell out the per-agent activation step: Cascade = Refresh, Devin Local = Connect. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WEHyNxWfn1miSWRW6NUtEW
Two things for 0.2.0: 1. Windows paths: Devin Local config/AGENTS.md now resolve to %APPDATA%\devin on Windows (was ~/.config/devin unconditionally, which is wrong there). Cascade's ~/.codeium/windsurf is already cross-platform. 2. Deterministic auto-recall (Devin Local only): init adds a SessionStart hook to config.json that recalls project + global memory and returns it as `additionalContext`, which Devin injects into the agent's context before the model acts — so memory loads even if the model forgets to call recall. The hook (hindsight_devin_desktop.hook) reads the connection from config.json and derives the project bank from DEVIN_PROJECT_DIR; it's dependency-free (stdlib urllib MCP call), times out fast, and fails silently so it never breaks a session. Opt out with `init --no-hooks`. Cascade gets no hook (its hooks can't inject context). Auto-retain is intentionally not added (SessionEnd can't see the transcript); retain stays model-driven via the MCP tool. Verified live against Cloud: the hook recalls a stored fact and emits correct additionalContext JSON. 89 tests pass; ruff clean. README documents both. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WEHyNxWfn1miSWRW6NUtEW
…ibility banner Round out the hooks/visibility work for 0.2.0: - Retain-nudge (Devin Local, default on): a `Stop` hook forces one retain pass before the agent stops (loop-guarded via stop_hook_active) — deterministic *trigger*; the model decides what's durable and calls retain. Devin's hooks can't hand a script the transcript, so this is the closest to deterministic retain. Opt out with --no-retain-hook; --no-hooks disables both hooks. - No silent failures (recall hook): the SessionStart hook now ALWAYS reports status via additionalContext — loaded N / empty / unavailable(reason) — and tells the model to surface it. Never exits non-zero (never breaks a session). - Cascade visibility banner: init adds a `post_mcp_tool_use` hook to ~/.codeium/windsurf/hooks.json with show_output:true that prints "🧠 Hindsight: <tool> used" (filtered in-script to the hindsight server, since Cascade hooks have no matcher). Makes Cascade's recall/retain visibly obvious. New module cascade_hooks.py; hook.py gains retain-nudge + banner subcommands. README documents both hooks, the honest retain limitation, and the banner. 102 tests pass; ruff clean. Recall + retain-nudge output verified. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WEHyNxWfn1miSWRW6NUtEW
…facts Real in-app testing showed the Stop retain-nudge caused the model to (a) retain facts ABOUT the memory system/instructions as 'user preferences', and (b) re-retain things already saved this session. Tighten both the nudge and the always-on rule: retain ONLY real facts about the code/project/user's actual preferences, NEVER facts about Hindsight/memory/hooks/these instructions, and don't re-retain what's already stored. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WEHyNxWfn1miSWRW6NUtEW
In-app testing showed the model firing sync_retain per-fact (and re-saving), producing duplicate memories. Reframe the rule: retain (async) is the default; retain each distinct fact EXACTLY ONCE in a single call (batch same-subject facts); sync_retain only for same-task read-after-write. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WEHyNxWfn1miSWRW6NUtEW
…log) Devin Local hooks are silent (no output panel), so it's hard to tell whether a hook actually fired vs the model just following the always-on rule. Each hook invocation now appends one line (recall loaded/empty/error, retain-nudge blocked/skipped, banner shown/skipped) with the resolved banks — proof-of-life so users (and we) can confirm the hooks run. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WEHyNxWfn1miSWRW6NUtEW
Add a local-only mode so users can opt out of the shared cross-project bank: everything (project facts + the user's preferences) goes to the single project bank, the global rule files are removed instead of written, and the recall + retain-nudge hooks run with --local-only (recall only the project bank, nudge routes everything there). The rule becomes a single-bank variant. Cascade banner + MCP config unchanged. For people who don't want a shared profile (e.g. work vs personal machines). 108 tests pass; ruff clean. Verified end-to-end: no global files written, hooks carry --local-only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WEHyNxWfn1miSWRW6NUtEW
The proof-of-life hook log wrote ~/.hindsight/devin-hook.log unconditionally, so running the tests (which call the hook functions) polluted the real user log. Make the path env-overridable (HINDSIGHT_HOOK_LOG, 'off' disables) and add a conftest that sets it off during tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WEHyNxWfn1miSWRW6NUtEW
The SessionStart hook's additionalContext now tells the model to OPEN its reply by announcing that memory was preloaded (e.g. '🧠 Hindsight preloaded N memories for this session'), and that it doesn't need to re-call recall for the baseline — making the deterministic preload visible to the user and cutting redundant recall calls. Empty/error variants also lead with a user-facing status line. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WEHyNxWfn1miSWRW6NUtEW
…ows notes Help new users get started with both agents: a 'Verify it's working' section (the preload status line / hook log / Cascade banner / status command), a note on the agent selector, and the Windows config path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WEHyNxWfn1miSWRW6NUtEW
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The Devin Desktop integration hardcoded a single shared bank (
devin-desktop), so every project the user worked on wrote into one memory pool — architecture/decisions from repo A bled into repo B's reasoning (banks isolate the synthesized layer too: observations + mental models are computed per-bank). This reworks it into proper per-project isolation + a shared cross-project bank, and makes Hindsight usage visible in chat (no sound — an explicit product decision).Follow-up to the just-published 0.1.0; this is 0.2.0.
What changed
Two-tier bank scoping (multi-bank mode)
/mcp/endpoint (was/mcp/<bank>/); the model routesbank_idper call, guided by the committed rule.devin-desktop(user prefs/style) — named in~/.codeium/windsurf/memories/global_rules.md.devin-desktop-<slug>—<slug>derived from the repo's git remote (stable across machines and identical for teammates) — named in the committed.devin/rules/hindsight.md.X-Bank-Id: <global>header as the fallback bank when a call omitsbank_id.Visible memory use (no sound)
reflect/sync_retain.Audit fixes (from a docs review of current Devin Desktop)
~/.codeium/windsurf/mcp_config.jsonand~/.codeium/mcp_config.json) — Devin's own docs disagree on the path.New modules:
project.py(git-derivation),global_rules.py(managed block inglobal_rules.md).Backward-compatible: legacy
bankIdin~/.hindsight/devin-desktop.jsonmaps to the global bank.Verification
ruff check+ruff formatclean.initin a git repo → all three files generate correctly, project bank derived from the git remote.sync_retain→recallacross two banks): each bank returns only its own fact — zero cross-bank leak — confirming multi-bank routing + isolation + read-after-write on production. (Multi-bank mode +X-Bank-Idalso verified live on Hindsight Cloud.)Reliability note
Routing depends on the model passing the correct
bank_idper the always-on rule — inherent to Devin's global-only MCP config (no per-workspace MCP file). TheX-Bank-Idheader defaults omitted calls to the global bank as a safety net; the committed rule (which names the exact banks) is the primary lever.Deferred (separate follow-up)
Auto-bootstrapping an auto-refreshing mental model per bank ("Project architecture" / "User style").
🤖 Generated with Claude Code