From 32721264551bf1cd0727d86c655a55521f758e8a Mon Sep 17 00:00:00 2001 From: Jack Arturo Date: Sat, 29 Aug 2026 02:31:51 +0200 Subject: [PATCH 1/2] docs(development): reconcile local setup docs --- .superpowers/sdd/local-setup-report.md | 38 +++++++++++++ .../docs/docs/development/local-setup.md | 26 +++++---- tests/local-setup-docs.test.mjs | 54 +++++++++++++++++++ 3 files changed, 107 insertions(+), 11 deletions(-) create mode 100644 .superpowers/sdd/local-setup-report.md create mode 100644 tests/local-setup-docs.test.mjs diff --git a/.superpowers/sdd/local-setup-report.md b/.superpowers/sdd/local-setup-report.md new file mode 100644 index 00000000..7f3ddc71 --- /dev/null +++ b/.superpowers/sdd/local-setup-report.md @@ -0,0 +1,38 @@ +# Local setup reconciliation report + +## Source evidence + +- AutoMem `0.16.2` is pinned at `e147c352b100ebbf29e6555453fdde5152066138`. + - `docker-compose.yml` names the API service `flask-api` and exports + `FLASK_ENV: development` plus `FLASK_DEBUG: "1"`. + - `automem/config.py` defaults consolidation intervals to 86,400 seconds + (decay), 604,800 (creative), 2,592,000 (cluster), and 0 (forget). + - `automem/runtime_wiring.py` calls `app.run(..., debug=False)`. +- mcp-automem `0.16.0` is pinned at `9a0bbf754dd31db524da25638b0e97907e32ff37`. + - `package.json` declares Node `^20.19.0 || ^22.13.0 || >=24`. + - Its `prebuild` starts with `tsx scripts/sync-memory-policy.ts`; its + `postbuild` only runs the OpenClaw package builder. + +## Changes + +- Reconciled `src/content/docs/docs/development/local-setup.md` to those + source pins, including the Compose service name, scheduler sequence, + runtime debug explanation, Node engine range, and npm hooks. +- Added `tests/local-setup-docs.test.mjs`, a static guard covering every + corrected claim and rejecting the superseded values/text. +- Kept the unrelated `0.0.0.0` bind wording untouched, per scope. + +## Verification + +- `node --test tests/local-setup-docs.test.mjs` — 4 passed. +- `npm test` — 94 passed, 1 skipped, 0 failed. +- `npm run build` — passed; pre-existing Astro/Vite warnings only. +- `git diff --check` — passed. + +## Commit and self-review + +- Commit subject: `docs(development): reconcile local setup docs`. +- Reviewed the final diff against both pinned source revisions. It contains + only the assigned page, its focused test, and this implementation report; + no stale service name, schedule, debug/autoreload claim, engine range, or + `chmod +x` postbuild claim remains. diff --git a/src/content/docs/docs/development/local-setup.md b/src/content/docs/docs/development/local-setup.md index 2ccc76ad..5539e825 100644 --- a/src/content/docs/docs/development/local-setup.md +++ b/src/content/docs/docs/development/local-setup.md @@ -24,7 +24,7 @@ Before setting up the development environment, ensure the following tools are in | git | Any recent version | Source control | :::tip[One-shot bootstrap] -The repo now ships [`scripts/bootstrap_dev.sh`](https://github.com/verygoodplugins/automem/blob/ed36b98e3e1569dde71aa430417b6549520f7068/scripts/bootstrap_dev.sh), which creates a Python 3.12 virtualenv and installs dev requirements in one command. Prefer it over the manual steps below unless you need a custom setup. +The repo now ships [`scripts/bootstrap_dev.sh`](https://github.com/verygoodplugins/automem/blob/e147c352b100ebbf29e6555453fdde5152066138/scripts/bootstrap_dev.sh), which creates a Python 3.12 virtualenv and installs dev requirements in one command. Prefer it over the manual steps below unless you need a custom setup. ::: ### Repository Contents @@ -105,7 +105,7 @@ graph TB DC["docker-compose.yml"] Falkor["falkordb/falkordb:latest\nPort 6379\nVolume: ./data/falkordb"] Qdrant["qdrant/qdrant:latest\nPort 6333\nVolume: ./data/qdrant"] - APIContainer["memory-service\nPort 8001\nOptional"] + APIContainer["flask-api\nPort 8001\nOptional"] end subgraph "External Services (Optional)" @@ -137,7 +137,7 @@ This starts all services in the foreground (attached), rebuilding images if `Doc - **FalkorDB** on port `6379` with volume mount at `./data/falkordb` - **Qdrant** on port `6333` with volume mount at `./data/qdrant` -The `docker-compose.yml` defines these services with persistent storage, ensuring data survives container restarts. +The [`docker-compose.yml`](https://github.com/verygoodplugins/automem/blob/e147c352b100ebbf29e6555453fdde5152066138/docker-compose.yml) file defines these services with persistent storage, ensuring data survives container restarts. Its API service is named `flask-api`. ```bash # Stop services @@ -212,7 +212,7 @@ sequenceDiagram Embed->>Embed: "Begin batch accumulator" Flask->>Sched: "Initialize scheduler" - Sched->>Sched: "Schedule decay (1h)\ncreative (1h)\ncluster (6h)\nforget (1d)" + Sched->>Sched: "Schedule decay (1d)\ncreative (7d)\ncluster (30d)\nforget disabled" Flask->>Flask: "Bind to 0.0.0.0:8001" Flask-->>Dev: "Server ready" @@ -225,6 +225,8 @@ sequenceDiagram Flask-->>Dev: '{"status": "healthy"}' ``` +The [scheduler defaults](https://github.com/verygoodplugins/automem/blob/e147c352b100ebbf29e6555453fdde5152066138/automem/config.py) run decay daily, creative consolidation weekly, and clustering every 30 days. Forgetting defaults to `0` seconds, which disables it until explicitly configured. + --- ### Development Configuration @@ -263,17 +265,17 @@ AUTOMEM_API_TOKEN=your-dev-token | `ENRICHMENT_MAX_ATTEMPTS` | `3` | Enrichment retry limit | | `ENRICHMENT_SIMILARITY_LIMIT` | `5` | Semantic neighbors count | | `ENRICHMENT_SIMILARITY_THRESHOLD` | `0.8` | SIMILAR_TO edge threshold | -| `FLASK_ENV` | `production` | Flask mode (`development` enables debug) | +| `FLASK_ENV` | _unset_ | Docker Compose exports `development`; it does not control the runtime debug setting. | +| `FLASK_DEBUG` | _unset_ | Docker Compose exports `1`; it does not control the runtime debug setting. | | `LOG_LEVEL` | `INFO` | Logging verbosity | -**Enable development mode** for verbose logging and auto-reload: +**Enable verbose application logging** when diagnosing local behavior: ```bash -FLASK_ENV=development LOG_LEVEL=DEBUG ``` -The `FLASK_ENV=development` setting enables: detailed error pages with stack traces, auto-reload on file changes, and more verbose console output. +Docker Compose exports `FLASK_ENV=development` and `FLASK_DEBUG=1` for the `flask-api` container, but the [runtime entry point](https://github.com/verygoodplugins/automem/blob/e147c352b100ebbf29e6555453fdde5152066138/automem/runtime_wiring.py) hardcodes `debug=False`. Those exports therefore do not enable Flask debug mode or the autoreloader; restart the process or container after changing source files. --- @@ -383,7 +385,7 @@ sudo chown -R $(whoami) ./data/ ### Prerequisites -- **Node.js**: Version 20.0.0 or higher +- **Node.js**: `^20.19.0 || ^22.13.0 || >=24` - **npm**: Comes with Node.js - **git**: For version control - **AutoMem Service**: Running instance for integration testing (local or Railway-hosted) @@ -398,11 +400,13 @@ npm install # Also installs Husky git hooks via "prepare" lifecycle script ### npm Scripts Reference +At this release, the [`package.json`](https://github.com/verygoodplugins/mcp-automem/blob/9a0bbf754dd31db524da25638b0e97907e32ff37/package.json) scripts below run as shown. + | Script | Command | Purpose | |---|---|---| -| `prebuild` | `node scripts/sync-template-versions.mjs` | Sync template versions before build | +| `prebuild` | `tsx scripts/sync-memory-policy.ts && node scripts/sync-template-versions.mjs` | Sync memory policy and template versions before build | | `build` | `tsc` | Compile TypeScript to `dist/` | -| `postbuild` | `node scripts/build-openclaw-plugin-package.mjs && chmod +x dist/index.js` | Build OpenClaw plugin package and make binary executable | +| `postbuild` | `node scripts/build-openclaw-plugin-package.mjs` | Build OpenClaw plugin package | | `sync-versions` | `node scripts/sync-template-versions.mjs` | Manually sync template versions without triggering a build | | `dev` | `tsx watch src/index.ts` | Hot-reload development server | | `lint` | `eslint .` | Run ESLint static analysis | diff --git a/tests/local-setup-docs.test.mjs b/tests/local-setup-docs.test.mjs new file mode 100644 index 00000000..2319b7d0 --- /dev/null +++ b/tests/local-setup-docs.test.mjs @@ -0,0 +1,54 @@ +import assert from 'node:assert/strict'; +import { readFile } from 'node:fs/promises'; +import test from 'node:test'; +import { fileURLToPath } from 'node:url'; + +const pagePath = fileURLToPath( + new URL('../src/content/docs/docs/development/local-setup.md', import.meta.url), +); +const automemRelease = 'e147c352b100ebbf29e6555453fdde5152066138'; +const mcpAutomemRelease = '9a0bbf754dd31db524da25638b0e97907e32ff37'; + +async function readPage() { + return readFile(pagePath, 'utf8'); +} + +test('local setup is pinned to the validated AutoMem and MCP releases', async () => { + const page = await readPage(); + + assert.match(page, new RegExp(`automem/blob/${automemRelease}/docker-compose\\.yml`)); + assert.match(page, new RegExp(`automem/blob/${automemRelease}/automem/config\\.py`)); + assert.match(page, new RegExp(`automem/blob/${automemRelease}/automem/runtime_wiring\\.py`)); + assert.match(page, new RegExp(`mcp-automem/blob/${mcpAutomemRelease}/package\\.json`)); +}); + +test('local setup names the Compose API service and default consolidation schedule', async () => { + const page = await readPage(); + + assert.match(page, /APIContainer\["flask-api\\nPort 8001\\nOptional"\]/); + assert.doesNotMatch(page, /memory-service/i); + assert.match(page, /decay \(1d\)\\ncreative \(7d\)\\ncluster \(30d\)\\nforget disabled/); + assert.doesNotMatch(page, /decay \(1h\)\\ncreative \(1h\)\\ncluster \(6h\)\\nforget \(1d\)/); +}); + +test('local setup distinguishes Compose debug exports from the hardcoded Flask runtime', async () => { + const page = await readPage(); + + assert.match(page, /Docker Compose exports `FLASK_ENV=development` and `FLASK_DEBUG=1`/); + assert.match(page, /`debug=False`/); + assert.match(page, /do not enable Flask debug mode or the autoreloader/i); + assert.doesNotMatch(page, /FLASK_ENV=development setting enables/i); + assert.doesNotMatch(page, /auto-reload on file changes/i); +}); + +test('local setup documents the release-pinned Node engine and build hooks', async () => { + const page = await readPage(); + + assert.match(page, /\^20\.19\.0 \|\| \^22\.13\.0 \|\| >=24/); + assert.match( + page, + /`tsx scripts\/sync-memory-policy\.ts && node scripts\/sync-template-versions\.mjs`/, + ); + assert.match(page, /`node scripts\/build-openclaw-plugin-package\.mjs`/); + assert.doesNotMatch(page, /chmod \+x dist\/index\.js/); +}); From 9359b337c12919c2133a8236369543028d36bfa4 Mon Sep 17 00:00:00 2001 From: Jack Arturo Date: Sat, 29 Aug 2026 02:33:51 +0200 Subject: [PATCH 2/2] test(docs): cover local setup legacy claims --- .superpowers/sdd/local-setup-report.md | 11 +++++++++++ tests/local-setup-docs.test.mjs | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/.superpowers/sdd/local-setup-report.md b/.superpowers/sdd/local-setup-report.md index 7f3ddc71..dcd4eb1c 100644 --- a/.superpowers/sdd/local-setup-report.md +++ b/.superpowers/sdd/local-setup-report.md @@ -36,3 +36,14 @@ only the assigned page, its focused test, and this implementation report; no stale service name, schedule, debug/autoreload claim, engine range, or `chmod +x` postbuild claim remains. + +## SDD fix round 1 + +- Extended the static guard to require the e147 bootstrap-script source link + and reject the stale ed36 pin. +- Added negative checks for the old Flask configuration-table row, a + standalone `FLASK_ENV=development` shell instruction, the old Node minimum, + individual stale scheduler intervals, and the stale standalone prebuild + command. +- The deferred Mermaid `Optional` label remains unchanged because it is + outside the assigned #300 scope. diff --git a/tests/local-setup-docs.test.mjs b/tests/local-setup-docs.test.mjs index 2319b7d0..709fa670 100644 --- a/tests/local-setup-docs.test.mjs +++ b/tests/local-setup-docs.test.mjs @@ -16,10 +16,12 @@ async function readPage() { test('local setup is pinned to the validated AutoMem and MCP releases', async () => { const page = await readPage(); + assert.match(page, new RegExp(`automem/blob/${automemRelease}/scripts/bootstrap_dev\\.sh`)); assert.match(page, new RegExp(`automem/blob/${automemRelease}/docker-compose\\.yml`)); assert.match(page, new RegExp(`automem/blob/${automemRelease}/automem/config\\.py`)); assert.match(page, new RegExp(`automem/blob/${automemRelease}/automem/runtime_wiring\\.py`)); assert.match(page, new RegExp(`mcp-automem/blob/${mcpAutomemRelease}/package\\.json`)); + assert.doesNotMatch(page, /ed36b98e3e1569dde71aa430417b6549520f7068/); }); test('local setup names the Compose API service and default consolidation schedule', async () => { @@ -29,6 +31,7 @@ test('local setup names the Compose API service and default consolidation schedu assert.doesNotMatch(page, /memory-service/i); assert.match(page, /decay \(1d\)\\ncreative \(7d\)\\ncluster \(30d\)\\nforget disabled/); assert.doesNotMatch(page, /decay \(1h\)\\ncreative \(1h\)\\ncluster \(6h\)\\nforget \(1d\)/); + assert.doesNotMatch(page, /decay \(1h\)|creative \(1h\)|cluster \(6h\)|forget \(1d\)/); }); test('local setup distinguishes Compose debug exports from the hardcoded Flask runtime', async () => { @@ -37,6 +40,11 @@ test('local setup distinguishes Compose debug exports from the hardcoded Flask r assert.match(page, /Docker Compose exports `FLASK_ENV=development` and `FLASK_DEBUG=1`/); assert.match(page, /`debug=False`/); assert.match(page, /do not enable Flask debug mode or the autoreloader/i); + assert.doesNotMatch( + page, + /\| `FLASK_ENV` \| `production` \| Flask mode \(`development` enables debug\) \|/, + ); + assert.doesNotMatch(page, /```bash\s*FLASK_ENV=development\s*(?:\r?\nLOG_LEVEL=DEBUG)?\s*```/); assert.doesNotMatch(page, /FLASK_ENV=development setting enables/i); assert.doesNotMatch(page, /auto-reload on file changes/i); }); @@ -45,10 +53,12 @@ test('local setup documents the release-pinned Node engine and build hooks', asy const page = await readPage(); assert.match(page, /\^20\.19\.0 \|\| \^22\.13\.0 \|\| >=24/); + assert.doesNotMatch(page, /\*\*Node\.js\*\*: Version 20\.0\.0 or higher/); assert.match( page, /`tsx scripts\/sync-memory-policy\.ts && node scripts\/sync-template-versions\.mjs`/, ); assert.match(page, /`node scripts\/build-openclaw-plugin-package\.mjs`/); + assert.doesNotMatch(page, /\| `prebuild` \| `node scripts\/sync-template-versions\.mjs` \|/); assert.doesNotMatch(page, /chmod \+x dist\/index\.js/); });