Skip to content

feat(zed): automatic memory for the Zed editor's AI assistant#2153

Open
DK09876 wants to merge 9 commits into
mainfrom
feat/zed-integration
Open

feat(zed): automatic memory for the Zed editor's AI assistant#2153
DK09876 wants to merge 9 commits into
mainfrom
feat/zed-integration

Conversation

@DK09876

@DK09876 DK09876 commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Closes #2096 — a user requested a native, automatic Zed integration (like the OpenClaw / oh-my-openagent plugins), not the manual MCP path.

What it does

When you chat with Zed's Agent Panel, relevant memory from past sessions on that project is injected automatically — no manual tool calls — and conversations are retained so the next session builds on them. Per-project banks by default.

Why a daemon (and how it was validated)

Zed exposes no AI-conversation hook and no prompt-injection extension point (verified against zed-industries/zed source). The only always-on mechanism is Zed's instruction files (.rules / AGENTS.md / …), which Zed includes in every conversation; transcripts live in a local threads.db. So hindsight-zed is a small background daemon (launchd/systemd) that:

  • Auto-recall: on thread update, recalls memory for the project and rewrites a fenced <!-- HINDSIGHT --> block in the instruction file Zed actually reads — without hijacking an existing AGENTS.md/CLAUDE.md (writes the block into that file instead of creating a higher-priority .rules that would suppress it).
  • Auto-retain: reads new/updated threads from threads.db and retains transcripts.

Both core assumptions were validated against a real Zed install before building:

  • The threads.db reader was run against a live database — which surfaced and fixed a real bug (Zed's zstd frames omit the content-size header, so one-shot decompress fails; the reader now streams). Synthetic fixtures had masked it.
  • .rules auto-injection was confirmed end-to-end: a canary memory block showed up in a fresh Zed conversation with zero manual steps.

Scope / packaging

  • Per-project memory (one bank per git repo); --fixed-bank-id for a shared bank.
  • hindsight-zed init/run/status/uninstall. Runtime dep: zstandard (Zed compresses threads).
  • The reader handles all 4 on-disk thread formats (current 0.3.0 externally-tagged enums + 3 legacy shapes) and the bare-string Resume edge case.

Tests

  • 58 deterministic tests (threads.db reader across all formats, instruction-file writer incl. the don't-hijack case, config/bank/content/state, and a full daemon poll→recall→write-block→retain flow against a synthetic threads.db + fake client). Ruff clean.
  • A gated requires_real_llm e2e (retain → recall roundtrip against a live server), excluded from PR CI.

Known limitation

Zed has no per-prompt hook, so injection is periodic (refreshed on conversation update), not recomputed per keystroke. The relevant project memory is present in context every turn; it just isn't query-aware on the exact message instant — unavoidable in Zed today.

DK09876 added 7 commits June 11, 2026 12:06
… real Zed)

Core of the Zed integration, both validated against a real Zed install:
- threads_db.py: reads Zed's SQLite threads.db (all 4 on-disk formats, zstd
  streaming frames, folder_paths->project). Caught/fixed a real zstd frame bug
  that synthetic fixtures had masked.
- rules_file.py: writes a fenced HINDSIGHT memory block into the instruction
  file Zed actually reads (.rules / AGENTS.md / ...), without hijacking a user's
  existing file. Verified Zed auto-injects it into every conversation.
27 unit tests; reader additionally verified against a live threads.db.
Completes the Zed integration: a background daemon (launchd/systemd) that polls
Zed's threads.db and, per project, keeps a recalled-memory block fresh in the
instruction file Zed always reads (auto-recall) and retains conversations
(auto-retain). Per-project banks by default.

- daemon.py / state.py: poll -> recall -> write block; retain w/ dedup
- client.py / config.py / bank.py / content.py: HTTP client, typed config,
  per-git-repo bank derivation, transcript+memory formatting
- cli.py: hindsight-zed init/run/status/uninstall (launchd + systemd)
- pyproject (hindsight-zed, zstandard runtime dep), README, settings.json
- CI job + detect-changes filter, VALID_INTEGRATIONS, docs page + gallery entry
- 58 deterministic tests + a gated requires_real_llm e2e; ruff clean

Closes #2096
Replace the placeholder SVG with Zed's official logo (assets/images/zed_logo.svg
from zed-industries/zed).
# Conflicts:
#	scripts/release-integration.sh
The /changelog/integrations/zed page is generated by the release script when a
version is cut; linking it before release broke the docs build (broken link).
Recall/retain errors were swallowed at DEBUG, so a wrong API token or an
unreachable server failed silently — the user just saw no memory in Zed with no
hint why. Now auth (401/403) and connection/5xx errors escalate to WARNING in
the daemon log, deduped per bank (the 5s poll loop won't spam) and re-armed on a
later success. Client raises a typed HindsightHTTPError carrying the status code.
verify-generated-files runs 'ruff format' across the repo (separate from 'ruff
check'); reformat the 5 files it rewrote so the no-uncommitted-changes gate
passes.
DK09876 and others added 2 commits June 11, 2026 15:37
Zed has no 'thread finished' event, so the daemon previously retained on every
threads.db update — re-retaining the full transcript each turn and risking
mid-stream snapshots. Add RetainDebouncer: a thread is retained once its
updated_at has been stable for retain_idle_seconds (default 45s), collapsing a
multi-turn conversation into a single retain of its settled state. Recall stays
eager (memory should be as fresh as Zed allows); only retain is debounced.

+3 tests (idle hold, timer reset on new revision, poll-level debounce).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Native ZED Editor integration (like oh-my-openagent / OpenClaw plugins)

1 participant