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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ node_modules/
dist/
*.vsix
site/
.memory/cleanup.log
10 changes: 0 additions & 10 deletions .memory/cleanup.log

This file was deleted.

6 changes: 2 additions & 4 deletions .memory/decisions.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,10 @@ Memories stored by HackLM Memory.

- [docs-site-zensical] Docs site uses Zensical (pip install zensical). Config in zensical.toml at repo root. Serve: .venv/Scripts/zensical.exe serve. Build: zensical build → site/. Deploys to GitHub Pages via .github/workflows/docs.yml on push to main.


- [globalstate-keys-file] All globalState keys live in extension/src/globalStateKeys.ts as named exports. Never use bare string literals for globalState keys elsewhere.

- [category-limits-source] CATEGORY_LIMITS constant removed from markdownStore.ts. Category limits come from VS Code config only (package.json defaults via config.get). Default fallback is hardcoded as 20 in utils.ts.

- [stale-slug-pruner-removed] pruneStaleEntries removed from cleanupMemory.ts. Stale slugs last-cleanup and last-session-debrief no longer exist. ADRs 0001 and 0013 deleted from docs/decisions/ as they documented completed migration periods.


- [adr-location] ADRs live in docs/decisions.md but are NOT in the Zensical nav. The nav has an ADR page (docs/adr.md) instead. That page links back to docs/decisions.md on GitHub.

- [category-limits-defaults] Category defaults doubled: Instruction/Security = 30, Quirk/Preference/Decision = 40. Schema maximum raised to 100. Fallback in utils.ts and UI validation cap updated to match.
2 changes: 2 additions & 0 deletions .memory/quirks.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ Memories stored by HackLM Memory.
- [empty-justification] Passing an empty options object to sendRequest suppresses the justification string in the VS Code permission prompt. The user sees a blank reason. Always pass a justification.

- [adr-location] ADRs live in docs/decisions.md (a single flat file, not a directory). No separate per-ADR files. Add new ADRs as new H2 sections at the bottom of that file.

- [wx-flag-advisory-lock] The outer cross-process lock uses fs.open with the wx flag to create the lockfile exclusively. If the file already exists the open fails, signaling another process holds the lock. Never use a different open mode for this file.
14 changes: 13 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.1.0] - 2026-02-28

### Added

- Two-tier write locking: cross-process advisory lockfile (`crossProcessLock.ts`) stacked over per-file in-process promise queue — prevents concurrent writes from multiple VS Code windows
- Plan agent patching: `patchPlanAgent()` injects `queryMemory` + `storeMemory` into the Copilot Chat Plan agent on every activation (idempotent)

### Changed

- Default category limits doubled: Instruction/Security 15→30, Quirk/Preference/Decision 20→40
- Configurable maximum raised from 50 to 100

## [1.0.0] - 2026-02-27

### Added
Expand All @@ -30,7 +42,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Per-category entry limit settings
- Getting Started walkthrough (5 steps)
- esbuild single-file bundle (`dist/extension.js`) — no webpack
- Publishes to VS Marketplace and Open VSX (compatible with VS Code and Google Antigravity)
- Publishes to VS Marketplace and Open VSX

[Unreleased]: https://github.com/hacklmdev/memory/compare/v1.0.0...HEAD
[1.0.0]: https://github.com/hacklmdev/memory/releases/tag/v1.0.0
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Thank you for your interest in contributing.
## Prerequisites

- [Node.js](https://nodejs.org/) 20+
- [VS Code](https://code.visualstudio.com/) 1.99+ (or any Open VSX-compatible editor, e.g. Google Antigravity)
- [VS Code](https://code.visualstudio.com/) 1.99+
- Git

## Build
Expand Down
28 changes: 21 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,27 @@ A long-term memory layer for VS Code Copilot — learn from interactions, retain

## Compatibility

Works in any Open VSX-compatible editor:
Requires [VS Code](https://code.visualstudio.com/) 1.99+.

- [VS Code](https://code.visualstudio.com/) 1.99+
- [Google Antigravity](https://antigravity.google/) (Open VSX)
- [Gitpod](https://gitpod.io/) (Open VSX)
Also published to [Open VSX](https://open-vsx.org/extension/hacklm/hacklm-memory) for editors that use the Open VSX registry.

> **Note:** The memory LM tools (`storeMemory`, `queryMemory`) require the editor to implement the VS Code LM Tool API. Editors that do not implement this API will install the extension but the tools will not be available in chat.
### Open VSX editors

In Open VSX-compatible editors the extension installs and activates. What works depends on whether the editor implements the VS Code LM Tool API:

| Feature | Available |
|---------|----------|
| `.memory/*.md` files created on first open | Always |
| `copilot-instructions.md` reference block injected | Always |
| `storeMemory` / `queryMemory` LM tools | VS Code LM Tool API required |
| Tree view, status bar, control panel | VS Code only |
| LM deduplication and gap analysis | VS Code LM Tool API required |

The `.memory/` files and `copilot-instructions.md` pointer are set up regardless of editor. Once those exist, any AI agent that reads instruction files can access the memory store directly — even without the LM tools.

The full experience (LM tools, UI) requires VS Code 1.99+.

Support for additional editors via MCP is planned — see the [Roadmap](docs/roadmap.md).

## Architecture

Expand Down Expand Up @@ -78,7 +92,7 @@ npm run build
| `hacklm-memory.lmFamily` | `gpt-5-mini` | Copilot model family for LM operations |
| `hacklm-memory.autoApproveStore` | `false` | Skip confirmation prompt when saving memories |
| `hacklm-memory.manageInstructionFile` | `true` | Allow the extension to manage `.github/copilot-instructions.md` |
| `hacklm-memory.categoryLimit.*` | varies | Per-category max entry counts |
| `hacklm-memory.categoryLimit.*` | varies (30–40) | Per-category max entry counts |

## Privacy

Expand All @@ -94,7 +108,7 @@ Contributions are welcome. Please read [CONTRIBUTING.md](CONTRIBUTING.md) before
- [Architecture](docs/architecture.md) — module map, data flow, key design decisions
- [API Reference](docs/api-reference.md) — LM tool schemas, memory file format
- [Developer Guide](docs/contributing.md) — how to add categories, tools, and tests
- [Architecture Decision Records](docs/decisions.md) — 16 ADRs covering every major decision
- [Architecture Decision Records](docs/decisions.md) — 17 ADRs covering every major decision
- [Roadmap](docs/roadmap.md) — planned work and open contribution areas

## License
Expand Down
4 changes: 2 additions & 2 deletions docs/adr.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ This makes the codebase predictable. When LM behaviour changes, you edit one fil

## 4. Editor-agnostic storage

The `.memory/*.md` file format is the stable contract — not VS Code, not TypeScript, not this extension. A future JetBrains plugin or Neovim integration must read and write the same format for memory to be shareable across editors.
The `.memory/*.md` file format is the stable contract — not VS Code, not TypeScript, not this extension. Any future port (JetBrains plugin, Neovim integration, MCP server for Google Antigravity) must read and write the same format for memory to be shareable across editors.

The storage layer (`dedup.ts`, `scoring.ts`, `search.ts`, `markdownStore.ts`) has no VS Code dependency and must stay that way.
The storage layer (`dedup.ts`, `scoring.ts`, `search.ts`, `markdownStore.ts`) has no VS Code dependency and must stay that way. When additional editor support is built, this layer is extracted to `packages/storage` and shared — not copied.

---

Expand Down
10 changes: 5 additions & 5 deletions docs/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,11 @@ Returns `"No memories found."` if no entries match.

| Category | File | Default Limit | What It Stores |
|----------|------|---------------|----------------|
| `Instruction` | `.memory/instructions.md` | 15 | How Copilot should behave |
| `Quirk` | `.memory/quirks.md` | 20 | Project-specific weirdness — non-obvious gotchas |
| `Preference` | `.memory/preferences.md` | 20 | Style, tone, and design choices |
| `Decision` | `.memory/decisions.md` | 20 | Architectural commitments |
| `Security` | `.memory/security.md` | 15 | Rules that must never be broken |
| `Instruction` | `.memory/instructions.md` | 30 | How Copilot should behave |
| `Quirk` | `.memory/quirks.md` | 40 | Project-specific weirdness — non-obvious gotchas |
| `Preference` | `.memory/preferences.md` | 40 | Style, tone, and design choices |
| `Decision` | `.memory/decisions.md` | 40 | Architectural commitments |
| `Security` | `.memory/security.md` | 30 | Rules that must never be broken |

Limits are configurable per-category via `hacklm-memory.categoryLimit.<Category>` settings.

Expand Down
14 changes: 11 additions & 3 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,17 @@ flowchart TD

## Key Design Decisions

### Per-file Mutex Locks
### Two-tier Write Locks

`markdownStore.ts` maintains a `Map<filePath, Promise<void>>` as a chained promise queue. Every read-then-write operation on a `.memory/*.md` file acquires the lock for that specific file. This prevents concurrent `storeMemory` calls and background cleanup from corrupting the same file simultaneously.
Every write to `.memory/*.md` goes through two stacked locks:

1. **Outer — cross-process advisory lockfile** (`crossProcessLock.ts`): `withCrossProcessLock(memoryDir, fn)` creates `.memory/.lock` with an exclusive `fs.open('wx')` — an atomic OS primitive that works on POSIX and NTFS. Only one process can hold this file at a time. All other processes spin (with linear back-off, max 20 retries) until the holder removes it. Stale locks (dead PID or age > 10 s) are automatically removed, including on extension startup via `clearStaleLockOnStartup()`.

2. **Inner — per-file in-process promise queue** (`markdownStore.ts`): `withFileLock(filePath, fn)` chains a `Promise<void>` per file path. This serialises concurrent async calls within the same extension host process (e.g. `storeMemory` + background cleanup hitting the same category file).

Callers outside `markdownStore.ts` never interact with either lock directly. The combined wrapper `withMemoryWriteLock(filePath, fn)` is the only entry point used by `appendMemory`, `upsertMemory`, `deleteMemory`, and `migrateFiles`.

See [ADR 0018](decisions.md#0018--two-tier-write-locking-for-memory-files) for the full decision record.

### Centralised LM Access

Expand Down Expand Up @@ -99,7 +107,7 @@ This extension uses:
- `vscode.lm.selectChatModels` — to select a Copilot model for redundancy checks and gap analysis
- `vscode.lm.onDidChangeChatModels` — to refresh the status bar when available models change

These APIs require **VS Code 1.99+** (or any Open VSX-compatible editor that implements the VS Code LM Tool API at the same version level). Editors that do not implement `vscode.lm.registerTool` will install the extension but the memory tools will not be available in chat.
These APIs require **VS Code 1.99+**. The extension publishes to Open VSX; the memory tools function in any editor that implements the VS Code LM Tool API. A separate MCP-based implementation for additional editors is planned (see [ADR 0017](decisions.md#0017--additional-editor-support-via-mcp)).

## Future: JetBrains Support

Expand Down
75 changes: 67 additions & 8 deletions docs/decisions.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,11 +251,11 @@ Each memory category has a maximum entry count enforced during cleanup. Limits a

| Category | Limit | Rationale |
|----------|-------|-----------|
| Instruction | 15 | Low count, high value. Instructions should be crisp. |
| Decision | 20 | Grows fast on active projects. |
| Quirk | 20 | Accumulates over time. Cleanup keeps it relevant. |
| Preference | 20 | Style choices accumulate. |
| Security | 15 | Should be small and authoritative. |
| Instruction | 30 | Low count, high value. Instructions should be crisp. |
| Decision | 40 | Grows fast on active projects. |
| Quirk | 40 | Accumulates over time. Cleanup keeps it relevant. |
| Preference | 40 | Style choices accumulate. |
| Security | 30 | Should be small and authoritative. |

All limits are user-configurable via `hacklm-memory.categoryLimit.<Category>` settings.

Expand Down Expand Up @@ -315,11 +315,70 @@ HackLM Memory could theoretically support multiple editors. JetBrains requires a

### Decision

The initial release targets **VS Code-based editors only**: VS Code and any Open VSX-compatible editor. JetBrains support is deferred until a maintainer with JetBrains plugin experience volunteers.
The initial release targets **VS Code**. JetBrains support is deferred until a maintainer with JetBrains plugin experience volunteers. Support for additional editors will be delivered via MCP (see ADR 0017).

### Consequences

- The extension is written in TypeScript against the VS Code extension API exclusively.
- The VS Code LM Tool API (`vscode.lm.registerTool`, `vscode.lm.selectChatModels`) has no JetBrains equivalent.
- The storage layer (`dedup.ts`, `scoring.ts`, `search.ts`, `markdownStore.ts`) has no `vscode` dependency and could be extracted into a `core/` package for a future JetBrains port.
- The storage layer (`dedup.ts`, `scoring.ts`, `search.ts`, `markdownStore.ts`) has no `vscode` dependency and could be extracted into a `packages/storage` package for future ports.
- The `.memory/*.md` file format (documented in [`api-reference.md`](api-reference.md)) is the stable, editor-agnostic contract any future implementation must honour.

---

## 0017 — Additional Editor Support via MCP

**Status:** Accepted (not yet implemented)

### Context

Some editors (e.g. Google Antigravity) support MCP (Model Context Protocol), which allows agents to call external tools. These editors do not share the VS Code extension API surface.

### Decision

Support for MCP-capable editors will be delivered as a **separate MCP server** (`mcp/`) rather than by modifying the existing extension. The current extension remains VS Code-focused with no changes.

When the MCP server is built:
- The storage layer is extracted to `packages/storage` (shared by both `extension/` and `mcp/`).
- The MCP server accepts `workspaceRoot` as a per-call parameter (no VS Code workspace context).
- LM-based redundancy checks are omitted — Jaccard fuzzy matching is sufficient without a second LM pass.
- Gap analysis and session review are omitted — no user-prompt UI exists in the MCP context.

### Consequences

- Zero changes to the existing VS Code extension.
- No code duplication — storage logic lives once in `packages/storage`.
- The MCP server is a clean, dependency-light Node.js process.
- Feature parity is intentionally incomplete: gap analysis and LM dedup are VS Code-only features.

---

## 0018 — Two-tier Write Locking for Memory Files

**Status:** Accepted

### Context

The original in-process `withFileLock` (a chained-promise mutex keyed by file path) only protects concurrent calls within a single extension host process. When multiple agents run in the same worktree — each in its own process — simultaneous read-modify-write operations on the same `.memory/*.md` file produce last-writer-wins corruption. Reddit usage data shows parallel agents on the same worktree is a real pattern (e.g. 8 parallel code-review sub-agents, parallel feature agents).

### Decision

Add a second, outer lock layer: `crossProcessLock.ts` implements a cross-process advisory lockfile at `.memory/.lock`. All writes first acquire this lock, then fall through to the existing per-file in-process lock.

Key choices:

- **One directory-level lock, not per-file lockfiles.** Write frequency is low. A single `.lock` file avoids proliferating 5+ lockfiles and is simpler to reason about.
- **Pure Node.js — no runtime dependencies.** `fs.open(path, 'wx')` is the atomic exclusive-create primitive; it is one line. The extension has zero runtime npm dependencies and must stay that way.
- **Stale detection: PID liveness + age fallback.** `process.kill(pid, 0)` checks PID existence without sending a signal. If the PID is gone the lock is stale. Age > 10 s is a fallback for cross-machine or PID-reuse edge cases.
- **`clearStaleLockOnStartup()` called from `ensureMemoryDir`.** Cleans up any lock file left behind by a crashed process on the first write of a new session.

### Alternatives Rejected

- `proper-lockfile` npm package: correct, but adds a runtime dependency. Not worth it given the core primitive is trivial to implement.
- Per-file lockfiles: more granular but multiplies file clutter and adds complexity for no practical benefit at current write rates.

### Consequences

- Parallel agents writing memories to the same worktree are serialised. No data loss.
- Zero new npm dependencies.
- The `.lock` file is visible in the `.memory/` folder during writes. It is ephemeral (removed on release) and should be added to `.gitignore` by projects that track `.memory/`.
- `withMemoryWriteLock(filePath, fn)` in `markdownStore.ts` is the only call site — neither lock is accessible outside this module.
4 changes: 3 additions & 1 deletion docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ Open VS Code. Press `Ctrl+Shift+X` to open Extensions. Search for **HackLM Memor
Or click one of these links:

- [Install from VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=hacklm.hacklm-memory)
- [Install from Open VSX](https://open-vsx.org/extension/hacklm/hacklm-memory) *(for Google Antigravity, Gitpod, and other VS Code-based IDEs)*
- [Install from Open VSX](https://open-vsx.org/extension/hacklm/hacklm-memory)

> **Using an Open VSX-compatible editor?** The extension installs and sets up the `.memory/` files and `copilot-instructions.md` reference block in any editor. The `storeMemory` and `queryMemory` LM tools, tree view, and status bar require the VS Code LM Tool API and are only available in VS Code 1.99+. See the [compatibility table](../README.md#open-vsx-editors) for details.

---

Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Free. No cloud. No sign-up. Works in VS Code out of the box.

[Get started →](getting-started.md)

Also on [Open VSX](https://open-vsx.org/extension/hacklm/hacklm-memory) for Google Antigravity, Gitpod, and other VS Code-based IDEs.
Also on [Open VSX](https://open-vsx.org/extension/hacklm/hacklm-memory). Support for additional editors is [planned](roadmap.md).

---

Expand Down
Loading