Skip to content

Commit 9b5fa89

Browse files
committed
feat: cut over BM MCP client and add CI/release workflows
1 parent 118c22d commit 9b5fa89

File tree

14 files changed

+1319
-654
lines changed

14 files changed

+1319
-654
lines changed

.github/workflows/ci.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- main
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v4
16+
17+
- name: Setup Bun
18+
uses: oven-sh/setup-bun@v2
19+
with:
20+
bun-version: "1.3.8"
21+
22+
- name: Install dependencies
23+
run: bun install --frozen-lockfile
24+
25+
- name: Lint
26+
run: bun run lint
27+
28+
- name: Typecheck
29+
run: bun run check-types
30+
31+
- name: Unit tests
32+
run: bun test

.github/workflows/release.yml

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
name: Release
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
version:
7+
description: "Version bump (`patch`, `minor`, `major`) or explicit semver (`0.2.0`)"
8+
required: true
9+
default: "patch"
10+
11+
permissions:
12+
contents: write
13+
id-token: write
14+
15+
concurrency:
16+
group: release-${{ github.ref }}
17+
cancel-in-progress: false
18+
19+
jobs:
20+
release:
21+
runs-on: ubuntu-latest
22+
steps:
23+
- name: Checkout
24+
uses: actions/checkout@v4
25+
with:
26+
fetch-depth: 0
27+
28+
- name: Setup Bun
29+
uses: oven-sh/setup-bun@v2
30+
with:
31+
bun-version: "1.3.8"
32+
33+
- name: Setup Node
34+
uses: actions/setup-node@v4
35+
with:
36+
node-version: "20"
37+
registry-url: "https://registry.npmjs.org"
38+
39+
- name: Install dependencies
40+
run: bun install --frozen-lockfile
41+
42+
- name: Release checks
43+
run: bun run release:check
44+
45+
- name: Configure Git identity
46+
run: |
47+
git config user.name "github-actions[bot]"
48+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
49+
50+
- name: Bump version and create tag
51+
id: bump
52+
run: |
53+
set -euo pipefail
54+
55+
VERSION_INPUT="${{ github.event.inputs.version }}"
56+
57+
if [[ "$VERSION_INPUT" =~ ^(patch|minor|major)$ ]]; then
58+
npm version "$VERSION_INPUT" -m "chore(release): %s"
59+
elif [[ "$VERSION_INPUT" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
60+
npm version "$VERSION_INPUT" -m "chore(release): %s"
61+
else
62+
echo "Unsupported version input: $VERSION_INPUT" >&2
63+
echo "Use patch|minor|major or explicit semver like 0.2.0" >&2
64+
exit 1
65+
fi
66+
67+
TAG="$(git describe --tags --abbrev=0)"
68+
VERSION="$(node -p "require('./package.json').version")"
69+
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
70+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
71+
72+
- name: Push commit and tag
73+
run: |
74+
set -euo pipefail
75+
git push origin HEAD:${GITHUB_REF_NAME}
76+
git push origin "${{ steps.bump.outputs.tag }}"
77+
78+
- name: Publish to npm
79+
env:
80+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
81+
run: npm publish --access public
82+
83+
- name: Create GitHub release
84+
uses: softprops/action-gh-release@v2
85+
with:
86+
tag_name: ${{ steps.bump.outputs.tag }}
87+
name: ${{ steps.bump.outputs.tag }}
88+
generate_release_notes: true

README.md

Lines changed: 64 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,18 @@ Local-first knowledge graph plugin for OpenClaw — persistent memory with graph
77
The `openclaw-basic-memory` plugin integrates [Basic Memory](https://github.com/basicmachines-co/basic-memory) with OpenClaw to provide:
88

99
- **Composited `memory_search`** — queries MEMORY.md, the BM knowledge graph, and active tasks in parallel
10-
- **File watching via `bm watch`**automatically syncs workspace markdown files into the knowledge graph
10+
- **Persistent MCP stdio session**keeps a single `bm mcp --transport stdio --project <name>` process alive
1111
- **Auto-capture** — records agent conversations as structured daily notes
1212
- **Graph tools** — search, read, write, edit, delete, move, and navigate notes via `memory://` URLs
1313

1414
For a practical runbook, see [Memory + Task Flow](./MEMORY_TASK_FLOW.md).
1515

1616
## Requirements
1717

18-
1. **Basic Memory CLI** (`bm`) with `watch` command support and native tool commands:
19-
- `bm tool read-note --strip-frontmatter`
20-
- `bm tool edit-note --format json`
21-
- Pinned for testing to commit `f2683291e478568cdf1676759ed98c70d7cfdac3`
18+
1. **Basic Memory CLI** (`bm`) with MCP server support:
19+
- `bm mcp --transport stdio --project <name>`
20+
- MCP tools with JSON output mode: `read_note`, `write_note`, `edit_note`, `recent_activity`, `list_memory_projects`, `create_memory_project`, `delete_note`, `move_note`
21+
- Structured MCP tools: `search_notes`, `build_context`
2222
```bash
2323
uv tool install 'basic-memory[semantic] @ git+https://github.com/basicmachines-co/basic-memory.git@f2683291e478568cdf1676759ed98c70d7cfdac3' --with 'onnxruntime<1.24; platform_system == "Darwin" and platform_machine == "x86_64"'
2424

@@ -158,17 +158,17 @@ This uses sensible defaults: auto-generated project name, maps Basic Memory to y
158158

159159
Snake_case aliases (`memory_dir`, `memory_file`) are also supported.
160160

161-
On startup, the plugin ensures the configured BM project exists at `projectPath` by running `bm project add <project> <path> --default` when needed.
161+
On startup, the plugin ensures the configured BM project exists at `projectPath` via MCP `create_memory_project` in idempotent mode.
162162

163163
## How It Works
164164

165-
### File Watching
166-
On startup, the plugin spawns `bm watch --project <name>` as a long-running child process. This:
167-
1. Performs an initial sync of all files in the project directory
168-
2. Watches for file changes and re-indexes automatically
169-
3. Runs until the plugin stops (SIGTERM on shutdown)
165+
### MCP Session Lifecycle
166+
On startup, the plugin starts one persistent MCP stdio session:
167+
1. Spawns `bm mcp --transport stdio --project <name>`
168+
2. Verifies required MCP tool capabilities at connect time
169+
3. Uses bounded reconnect attempts (`500ms`, `1000ms`, `2000ms`) when the session drops
170170

171-
No custom file watcher needed — Basic Memory handles everything.
171+
Basic Memory MCP lifecycle handles sync and watch behavior for the project.
172172

173173
### Composited `memory_search`
174174
When the agent calls `memory_search`, three sources are queried in parallel:
@@ -202,7 +202,7 @@ This plugin works best if you treat memory as three lanes:
202202
Typical loop:
203203

204204
1. Capture or update notes/tasks with `bm_write` / `bm_edit`.
205-
2. `bm watch` syncs markdown updates into the BM project index.
205+
2. The persistent BM MCP process syncs markdown updates into the BM project index.
206206
3. `memory_search` queries:
207207
- `MEMORY.md` text snippets
208208
- BM search results (semantic + FTS)
@@ -213,7 +213,7 @@ Typical loop:
213213

214214
```mermaid
215215
flowchart LR
216-
A["Write/Update notes"] --> B["bm watch indexes changes"]
216+
A["Write/Update notes"] --> B["BM MCP indexes changes"]
217217
B --> C["memory_search(query)"]
218218
C --> D["MEMORY.md"]
219219
C --> E["Knowledge Graph"]
@@ -348,9 +348,9 @@ openclaw basic-memory status
348348
```bash
349349
which bm # Check if installed
350350
bm --version # Check version
351-
bm watch --help # Verify watch command exists
351+
bm mcp --help # Verify MCP server command exists
352352
```
353-
If `bm watch` doesn't exist, update Basic Memory to the latest version.
353+
If `bm mcp` doesn't exist, update Basic Memory to a newer version.
354354

355355
### `bm_edit` says `edit-note` is required
356356
Your installed `basic-memory` version is missing native `tool edit-note`.
@@ -363,17 +363,47 @@ openclaw gateway stop && openclaw gateway start
363363
```
364364

365365
### Search returns no results
366-
1. Check that `bm watch` is running (look for `[bm watch]` in logs)
366+
1. Check that the MCP session is connected (look for `connected to BM MCP stdio` in logs)
367367
2. Verify files exist in the project directory
368-
3. Try `bm tool search-notes "your query" --project <name>` directly
368+
3. Try `bm mcp --transport stdio --project <name>` and run `search_notes` through an MCP inspector/client
369369
4. Check project status: `bm project list`
370370

371+
## Integration Tests
372+
373+
This repo includes real end-to-end integration tests for `BmClient` in:
374+
375+
- `/Users/phernandez/dev/basicmachines/openclaw-basic-memory/integration/bm-client.integration.test.ts`
376+
377+
These tests launch a real `bm mcp --transport stdio --project <name>` process,
378+
run write/read/edit/search/context/move/delete calls, and assert actual filesystem/index results.
379+
380+
Run integration tests:
381+
382+
```bash
383+
bun run test:int
384+
```
385+
386+
By default this uses `./scripts/bm-local.sh`, which runs BM from a sibling
387+
`../basic-memory` checkout via `uv run --project ...` when present, and falls
388+
back to `bm` on `PATH` otherwise.
389+
390+
Optional overrides:
391+
392+
```bash
393+
# Use a non-default bm binary
394+
BM_BIN=/absolute/path/to/bm bun run test:int
395+
396+
# Use a specific basic-memory source checkout
397+
BASIC_MEMORY_REPO=/absolute/path/to/basic-memory bun run test:int
398+
```
399+
371400
## Development
372401

373402
```bash
374403
bun run check-types # Type checking
375404
bun run lint # Linting
376405
bun test # Run tests (156 tests)
406+
bun run test:int # Real BM MCP integration tests
377407
```
378408

379409
## Publish to npm
@@ -400,12 +430,26 @@ For a full release (version bump + publish + push tag):
400430
just release patch # or: minor, major, 0.2.0, etc.
401431
```
402432

433+
### GitHub Actions CI/CD
434+
435+
- CI workflow: `.github/workflows/ci.yml` runs on PRs and `main` pushes.
436+
- Release workflow: `.github/workflows/release.yml` runs manually (`workflow_dispatch`) and will:
437+
1. run release checks
438+
2. bump version and create a git tag
439+
3. push commit + tag
440+
4. publish to npm
441+
5. create a GitHub release
442+
443+
Repository secret required:
444+
445+
- `NPM_TOKEN` (npm publish token with package publish permissions)
446+
403447
### Project Structure
404448
```
405449
openclaw-basic-memory/
406-
├── index.ts # Plugin entry — spawns bm watch, registers tools
450+
├── index.ts # Plugin entry — manages MCP lifecycle, registers tools
407451
├── config.ts # Configuration parsing
408-
├── bm-client.ts # Basic Memory CLI wrapper
452+
├── bm-client.ts # Persistent Basic Memory MCP stdio client
409453
├── tools/ # Agent tools
410454
│ ├── search.ts # bm_search
411455
│ ├── read.ts # bm_read

0 commit comments

Comments
 (0)