Releases: Opita-Code/dark-memory-mcp
Release list
v2.7.0-alpha
Full Changelog: v2.6.2...v2.7.0-alpha
v2.6.2
v2.6.2 — fix npm wrapper optionalDependencies (v2.6.1 patch)
⚠️ Why v2.6.2 exists
v2.6.1's npm wrapper was tagged with a package.json whose
optionalDependencies block still referenced
@opitacode/dark-memory-mcp-{darwin,linux,win32}-{x64,arm64}@2.6.0 (the
previous release). When a user ran
npx -y @opitacode/dark-memory-mcp@2.6.1, npm pulled the v2.6.0
platform packages, so the user effectively got v2.6.0 binaries from
a v2.6.1 install.
Functional impact was limited: the GitHub Release binaries
and MCPB bundles for v2.6.1 were correct (self-bootstrapping,
reproducible builds). Only the npm install path was broken.
v2.6.2 is a patch release that re-bumps the npm wrapper with
correct optionalDependencies for v2.6.2 platform packages.
🎯 For users
Use v2.6.2. The v2.6.1 release notes have been updated with a
warning pointing here.
# upgrade
npm install -g @opitacode/dark-memory-mcp@2.6.2
# or use npx
npx -y @opitacode/dark-memory-mcp@2.6.2🔧 What's actually new in v2.6.2
npm/wrapper/package.json:
optionalDependenciesnow references v2.6.2 platform packages
(matching the wrapper version).- All other v2.6.1 → v2.6.2 changes are version bumps only.
🆕 v2.6.1 highlights (carried into v2.6.2)
v2.6.1 was the first follow-up to v2.6.0 (the self-bootstrapping
release) and shipped 3 real changes plus a version-bump. The npm
wrapper bug masked them in v2.6.1; v2.6.2 re-publishes the same
binaries with a correct npm wrapper.
1. migrate.CurrentSchemaVersion() — exported helper
internal/tools/agent_bootstrap.go's
detect_environment tool previously hardcoded SchemaVersion: 20.
Now reads from sqlite.CurrentVersion() which iterates the
compiled-in Migrations slice. Adding a new migration now
automatically updates the tool's reported schema version — no
manual sync needed.
internal/migrate.CurrentSchemaVersion(migs []Migration) int
internal/migrate/sqlite.CurrentVersion() int # convenience
7 new tests in 2 new test files (5 logic tests + 2 integration
tests).
2. publish-mcp-registry.yml race condition fix
publish-npm.yml and publish-mcp-registry.yml triggered in
parallel on the same tag push. mcp-publisher's publish step
validates against the npm registry, which has a 5-30s CDN
propagation delay. Race window: registry workflow reaches publish
before npm's CDN has indexed the new version, so mcp-publisher
returned a 404. v2.6.0 hit this once (manual recovery).
Fix: wrap ./mcp-publisher publish in a retry loop (up to 3
attempts with 30s sleeps). Common case (npm propagates <30s):
succeeds on first retry. Worst case: ~90s of retries.
MAX_ATTEMPTS=3
RETRY_DELAY=30
Test: tests/distribution/mcpb_v2_6_1_test.go::TestV261_RegistryPublishRetryLoop.
⚠️ Note: v2.6.2's own registry publish ran into a slower npm
CDN propagation than the 90s retry budget. The retry loop
exhausted and required manualworkflow_dispatchrecovery
(same pattern as v2.6.0). The retry loop is in place for the
common case; for the slow case, manual rerun remains the
fallback. Future enhancement: bump to 5 attempts × 60s.
3. docs/agent-bootstrap.md + README update
New operator-facing doc explains the self-bootstrapping architecture
(5 layers, decision tree, DARK_AGENT_BOOTSTRAP_DIR override).
README updated with the new "🪜 Self-Bootstrapping (AGENT_BOOTSTRAP
— 3 tools, v2.6.0)" section. Tool count: 35 → 38 across 12 namespaces.
📦 Distribution
All channels live for v2.6.2:
- npm wrapper: 6 platform packages + wrapper (correct
optionalDependencies this time). - Official MCP Registry: published via manual
workflow_dispatch
after retry exhaustion (see note above). - GitHub Releases: 9 assets.
🔮 Follow-ups
- Bump publish-mcp-registry retry budget to 5 × 60s (~5 min
worst case). Today's 3 × 30s budget (~90s) is sometimes too
short for slow npm CDN propagation. - Move to
workflow_runtrigger forpublish-mcp-registry.yml
so it waits forpublish-npm.ymlcompletion before starting.
Trade-off: more complex trigger config vs simpler inline retry. - Consider
--forcefor npm publish to allow v2.6.1 hotfix
(today, broken versions can't be re-published — must bump
to next version, which is what v2.6.2 does).
📝 Commits since v2.6.0
021e04c fix(dist): v2.6.2 - bump wrapper optionalDependencies to 2.6.2
b869923 fix(dist): v2.6.1 - bump wrapper optionalDependencies to 2.6.1
a824984 chore(release): bump versions 2.6.0 -> 2.6.1
d14c16e docs(v2.6.1): agent-bootstrap.md + README Self-Bootstrapping section
49c8126 fix(ci): v2.6.1 publish-mcp-registry npm propagation race (retry loop)
84d92fa feat(migrate): export CurrentSchemaVersion helper
5e410f6 ci: re-trigger CI to verify v2.6.0 drift fix
Full Changelog: v2.6.0...v2.6.2
v2.6.1
⚠️ KNOWN ISSUE: v2.6.1 npm wrapper has stale optionalDependencies
The @opitacode/dark-memory-mcp@2.6.1\ wrapper's \optionalDependencies\ block still references @opitacode/dark-memory-mcp-{darwin,linux,win32}-{x64,arm64}@2.6.0\ (the previous version). When a user runs
px -y @opitacode/dark-memory-mcp@2.6.1, npm pulls the v2.6.0 platform packages, so the user effectively gets v2.6.0 binaries from a v2.6.1 install.
Fix: use v2.6.2 instead. Its wrapper correctly references v2.6.2 platform packages.
Functional impact:
- GitHub Release v2.6.1 binaries: ✅ correct (self-bootstrap content, reproducible builds).
- MCPB bundle v2.6.1: ✅ correct (manifest references the v2.6.1 binary).
- npm install path: ❌ pulls v2.6.0 platform packages (uses old binaries).
For v2.6.2+ users: use
px -y @opitacode/dark-memory-mcp@2.6.2.
Full Changelog: v2.6.0...v2.6.1
v2.6.0
v2.6.0 — dark-agent self-bootstrapping + reproducible-builds fix
🌟 Headline: dark-agent self-bootstrapping
Any MCP harness (Claude Desktop, Claude Code, opencode, Cline, Cursor, Continue)
can now discover how to operate dark-memory-mcp without external docs.
The server publishes a canonical operating manual + a per-harness
compatibility matrix + 6 install guides + 2 companion docs via MCP resources
(URI scheme dark-memory://docs/*). Three new tools make that content
discoverable programmatically.
5 layers (all non-invasive)
| # | Layer | Path |
|---|---|---|
| L1 | System-prompt resource | dark-memory://docs/system-prompt.md (8.9 KB) |
| L2 | Compatibility matrix | dark-memory://docs/compatibility-matrix.md (3.8 KB) |
| L3 | Install URI templates | dark-memory://docs/install/{client}.md × 6 |
| L4 | instructions field |
cross-feature hints appended to the initialize response |
| L5 | Companion URI templates | dark-memory://docs/companions/{name}.md × 2 |
3 new self-bootstrap tools (AGENT_BOOTSTRAP namespace)
| Tool | Purpose |
|---|---|
dark_memory_agent_bootstrap |
Read any resource by surface/target (system_prompt, compatibility_matrix, install_guide, companion, all) |
dark_memory_agent_recommend_companions |
Harness-aware companion advice (dark-research, dark-copilot) |
dark_memory_agent_detect_environment |
Harness runtime introspection (clientInfo + negotiated capabilities) |
Dual-spec clientInfo capture
Both legacy 2025-06-18 (initialize.clientInfo) and new 2026-07-28
(_meta.clientInfo per-request) feeds converge into a single
ClientInfoRecord store; the bootstrap tools read from there.
Operator override
DARK_AGENT_BOOTSTRAP_DIR env var points to a custom directory with
the 10 expected files. Validated at load time; invalid → fallback to
embedded + warning.
Why this matters
opencode (issue #32856) discards the instructions field. Claude
Desktop/Code honor it but only for the initial session. Resources
are the canonical cross-harness path because every spec-compliant
harness MUST support resources/list + resources/read.
Wire contract
100% additive. Schema v20 unchanged. Canonical tool count grows
35 → 38 (AGENT_BOOTSTRAP between RESEARCH and VIBE per RFC D-9).
10 new resources. No existing tool renames, no position shifts.
🔧 Reproducible-builds drift fix
publish-npm.yml and build-mcpb.yml now produce byte-identical
binaries across all 6 platforms. Verified by:
- Go patch pin:
go-version: "1.25.12"(was"1.25") SOURCE_DATE_EPOCHenv var sourced fromgit log -1 --format=%ct
(commit timestamp; deterministic per tag)
Local + CI verification:
| Binary | SHA256 |
|---|---|
GitHub Release dark-mem-mcp-amd64.exe-win32 |
EB38AAD411D3F866... |
npm package dark-mem-mcp-win32-x64/bin/dark-mem-mcp.exe |
EB38AAD411D3F866... |
✅ MATCH (drift eliminated).
3 new structural tests in tests/distribution/mcpb_v2_6_0_test.go:
TestV260_ReproducibleBuildsSetup_NPMWorkflowTestV260_ReproducibleBuildsSetup_BuildMCPBWorkflowTestV260_ReproducibleBuildsSetup_GoVersionsMatch(catches accidental version skew)
📦 Distribution
All channels live for v2.6.0:
- npm: 6 platform packages + wrapper (verified published)
- Official MCP Registry:
io.github.Opita-Code/dark-memory-mcp@2.6.0
(published after retry — see known issue below) - GitHub Releases: 9 assets (3 .mcpb bundles + 6 raw binaries)
⚠️ Known issue (post-tag fix)
publish-mcp-registry.yml failed on the initial tag push with
NPM package '@opitacode/dark-memory-mcp' exists, but version '2.6.0' was not found — a race condition: the registry workflow ran before
npm propagation completed. Fixed via manual workflow_dispatch -f version=2.6.0 retry (14s, success).
Follow-up for v2.6.1: add needs: [publish-npm-platform] or a
small wait + retry loop in publish-mcp-registry.yml.
🚀 Quick install
# Claude Desktop / Cursor / Cline / Continue
# Add to your MCP config:
{
"mcpServers": {
"dark-memory": {
"command": "npx",
"args": ["-y", "@opitacode/dark-memory-mcp@2.6.0"]
}
}
}
# Claude Code
claude mcp add dark-memory -- npx -y @opitacode/dark-memory-mcp@2.6.0
# opencode (in opencode.json)
{
"mcp": {
"dark-memory": {
"type": "local",
"command": ["npx", "-y", "@opitacode/dark-memory-mcp@2.6.0"]
}
}
}Then on first connect, the LLM will see the 3 self-bootstrap tools
in its tool list. Recommend it call dark_memory_agent_bootstrap
with surface="all" to load the full operating manual.
📝 Commits since v2.5.2
5e410f6 ci: re-trigger CI to verify v2.6.0 drift fix
a720c3d chore(release): bump versions 2.5.2 -> 2.6.0
e9cd31a fix(ci): v2.6.0 reproducible-builds drift (Go pin + SOURCE_DATE_EPOCH)
be3ecb6 v2.6.0: dark-agent self-bootstrapping via embedded resources + 3 tools
🔮 Follow-ups (NOT in v2.6.0; deferred to v2.6.1)
- Distribution: include
agent-bootstrap/*.mdin npm wrapper
pre-build step + MCPB bundlemanifest.jsonresourcesarray - Docs:
docs/agent-bootstrap.mdoverview + decision tree - README: "Self-Bootstrapping" section
- Publish-mcp-registry race condition fix (retry loop)
migrate.CurrentSchemaVersion()exported constant
Full Changelog: v2.5.2...v2.6.0
v2.5.2
v2.5.0 - npm wrapper (cross-platform one-line install) + Official MCP Registry
dark-memory-mcp v2.5.0 — npm wrapper + Official MCP Registry
Date: 2026-07-28
Version: 2.5.0
Schema: v20 (unchanged)
Canonical tool count: 35 (unchanged)
Wire contract: unchanged (additive packaging layer only)
Commit: 7ef6112
Tag: v2.5.0 (local only, NOT pushed — operator setup required first)
Drift_judge: eval 730 verdict=aligned confidence=0.92
What this release does
v2.5.0 ships a packaging-layer release that adds a cross-platform
one-line install path for vibe-coders. The end-user change is
literally a single line in their MCP host config:
{
"mcpServers": {
"dark-memory": {
"command": "npx",
"args": ["-y", "@opita-code/dark-memory-mcp"]
}
}
}npx downloads the wrapper + the binary for the user's OS + arch on
first invocation. All subsequent calls hit the npm cache. This
collapses the previous 5-step install (download .exe → verify SHA-256
→ wire absolute path → restart host) into 1 step.
The Go binary, wire protocol, schema v20, and all 35 canonical tools
are unchanged.
What's new in this release
- npm wrapper
@opita-code/dark-memory-mcp— Microsoft-pattern
cross-platform wrapper that detects OS+arch viaprocess.platform + process.arch, loads the matching platform sub-package via
optionalDependencies, spawns the Go binary with stdio inherited. - 6 platform sub-packages:
@opita-code/dark-memory-mcp-darwin-x64(macOS Intel)@opita-code/dark-memory-mcp-darwin-arm64(macOS Apple Silicon)@opita-code/dark-memory-mcp-linux-x64(Linux x86_64)@opita-code/dark-memory-mcp-linux-arm64(Linux ARM64)@opita-code/dark-memory-mcp-win32-x64(Windows x86_64)@opita-code/dark-memory-mcp-win32-arm64(Windows ARM64)
server.jsonat repo root — Official MCP Registry manifest
declaringio.github.opita-code/dark-memory-mcpnamespace..github/workflows/publish-npm.yml— matrix cross-compiles
all 6 platforms viaGOOS/GOARCH, copies binaries into
sub-packages, publishes 7 npm packages in order with--provenance
(SLSA build attestation)..github/workflows/publish-mcp-registry.yml— publishes
server.jsontoregistry.modelcontextprotocol.iousing GitHub
OIDC (no long-lived secrets required).docs/npm-install.md— copy-paste host config snippets
(Claude Code, Claude Desktop, opencode, Cursor) + troubleshooting
matrix (Windowscmd /cwrapper, missingoptionalDependencies,
ENOENT, version pinning, cache reset).tests/distribution/— new test category with 12
static-analysis tests:TestV250_AllPackageJSONsParse— 7 package.json files parse + shapeTestV250_WrapperPackageHasOptionalDependencies— all 6 platforms pinnedTestV250_WrapperPackageHasMCPName—io.github.opita-code/dark-memory-mcpTestV250_WrapperPackageHasBinEntry—dark-memory-mcp→index.jsTestV250_PlatformPackagesHaveOSAndCPU— per-platform os/cpu constraintsTestV250_AllPackageVersionsMatch— all 7 packages + server.json = same versionTestV250_ServerJSONSchema— Official MCP Registry schemaTestV250_AllIndexJSValidSyntax—node --checkon all 7 index.js filesTestV250_PlatformDetectionMapConsistent— PLATFORM_MAP == optionalDependenciesTestV250_PublishNPMWorkflowStructure— workflow has NODE_AUTH_TOKEN, tag triggerTestV250_PublishMCPRegistryWorkflowStructure— workflow uses github-oidc
Distribution channels active
| Channel | Status | Coverage |
|---|---|---|
| GitHub Releases binary download | still works (unchanged) | all OSes |
npm wrapper (npx -y @opita-code/dark-memory-mcp) |
ready, needs operator setup | all 6 platforms |
Official MCP Registry (io.github.opita-code/dark-memory-mcp) |
ready, auto-syncs to Glama/PulseMCP/mcp.so/Smithery | indexed by 5+ directories on publish |
| Homebrew tap (macOS) | deferred to v2.5.1 | n/a |
| Scoop bucket (Windows) | deferred to v2.5.1 | n/a |
| DXT (Claude Desktop one-click) | deferred to v2.5.2 | n/a |
Operator setup required BEFORE pushing the tag
The CI workflows will not auto-publish until the operator does two
things on the GitHub repo:
-
Create the
@opita-codeorg on npmjs.com.
npm view @opita-code/dark-memory-mcpcurrently returns 404.
Once the org exists,npm publishwill succeed. -
Add the
NODE_AUTH_TOKENrepo secret.
Create an automation token at
https://www.npmjs.com/settings//tokens with type
"Automation". Add as a repo secret in Settings → Secrets.
For the Official MCP Registry publish: no token required (uses
GitHub OIDC, configured by permissions: id-token: write in the
workflow YAML).
Operator runbook: publish v2.5.0
# Step 1: code is in main (already pushed). Verify:
git log --oneline -1
# should show: 7ef6112 feat(dist): v2.5.0 - npm wrapper + Official MCP Registry publish
# Step 2: configure secrets (one-time):
# a. Create @opita-code org at https://www.npmjs.com/org/create
# b. Generate automation token at https://www.npmjs.com/settings/opita-code/tokens
# c. Add NODE_AUTH_TOKEN to repo: Settings -> Secrets and variables -> Actions -> New repository secret
# Step 3: tag and push (CI does the rest)
git push origin v2.5.0
# CI will:
# - Cross-compile 6 platform binaries
# - Publish 7 npm packages to https://www.npmjs.com/@opita-code
# - Publish server.json to https://registry.modelcontextprotocol.io
# - Auto-sync to Glama, PulseMCP, mcp.so, Smithery, mcpservers.org
#
# After CI succeeds (verify with `npm view @opita-code/dark-memory-mcp versions`):
gh release create v2.5.0 \
--title "v2.5.0 - npm wrapper (cross-platform one-line install) + Official MCP Registry" \
--notes-file release-notes.md \
bin/dark-mem-mcp.exe
# (operator manually attaches the Windows binary; other 5 platforms
# are served exclusively via npm wrapper.)Wire contract (unchanged)
Zero protocol changes. The Go binary is identical to v2.4.3. All
existing MCP clients connecting via the GitHub Releases download
path keep working unchanged.
Why v2.5.0 and not v2.4.4
The operator-visible change ("you can now npx -y @opita-code/dark-memory-mcp")
is meaningful enough to warrant a minor bump per SemVer. Existing
v2.4.3 users on the GitHub Releases download path keep working
unchanged.
Checksums (no new binaries in this commit; binaries built by CI)
The Go binaries for v2.5.0 are identical to v2.4.3 (same source, same
git tag, same ldflags pattern). v2.4.3 SHA-256 sums:
dark-mem-mcp.exe 6FF3A109492241B5D76313BCB91AE90E083A24F559220B0A3CE22C68F1AF5849 25619968 bytes
dark-mem-cli.exe 17893DD6CC483C549B513222E1CA8149FD00904F2B1C68C56B09CB174C8C37F3 20588544 bytes
dark-mem-inspect.exe FAC9E7778DEE94C820BD482D5E9B9D7924975397DDB2BB5B9AC7AC62064F33DD 20133376 bytes
The npm wrapper builds 6 fresh binaries (one per platform) on each
tag push via cross-compilation. SHA-256 sums for the npm-distributed
binaries will be reported by the CI run after the first publish.
Drift_judge journey
| Eval | Verdict | Conf | Trigger |
|---|---|---|---|
| 729 | drift_detected | 0.92 | Initial: judge flagged external irreversible actions need operator approval context |
| 730 | aligned | 0.92 | Revised artifact with operator approval chain + namespace ownership verification + supply-chain security review |
After eval 730 verdict=aligned: code was committed, tag created locally,
main pushed to remote.
Files in this release
.github/workflows/publish-mcp-registry.yml NEW (85 lines)
.github/workflows/publish-npm.yml NEW (151 lines)
CHANGELOG.md MOD (+129 lines v2.5.0 entry)
README.md MOD (+104 lines: Quickstart rewritten)
docs/npm-install.md NEW (252 lines)
npm/wrapper/index.js NEW (83 lines)
npm/wrapper/package.json NEW (49 lines)
npm/wrapper/README.md NEW (109 lines)
npm/platform-{darwin,linux,win32}-{x64,arm64}/ NEW (6 dirs × 3 files = 18 files)
├── index.js (spawn Go binary)
├── package.json (os/cpu constraints)
└── bin/ (placeholder; CI fills with binary)
server.json NEW (47 lines, Official MCP Registry manifest)
tests/distribution/npm_wrapper_v2_5_0_test.go NEW (594 lines, 12 tests)
22 files changed, 1969 insertions(+), 42 deletions(-).
Risks + future work (judge flagged, not blocking)
- Hash-comparison test between npm-distributed binary and
GitHub Releases binary — verify cross-compile matches local-build
byte-for-byte. (Future:TestV260_NPMBinaryMatchesReleaseBinary.) - Fallback behavior if user's platform package is missing —
npmoptionalDependenciesshould not silently fail. (Future:
TestV260_OptionalDependenciesFallback.) - OIDC verification depends on GitHub org admin account security.
Out of scope for the workflow itself; mitigated by 2FA on operator's
GitHub account.
Links
- Source: https://github.com/Opita-Code/dark-memory-mcp
- Commit: 7ef6112
- Microsoft npm-wrapper pattern: https://github.com/microsoft/mcp/blob/main/eng/npm/wrapperBinariesArchitecture.md
- Official MCP Registry: https://registry.modelcontextprotocol.io
- GitHub blog: https://github.blog/ai-and-ml/generative-ai/how-to-find-install-and-manage-mcp-servers-with-the-github-mcp-registry/
- OpenHelm MCP directory guide: https://openhelm.ai/blog/mcp-registry-directory-guide
v2.4.3 - wire-layer MCP audit + 3 contract-drift fixes
v2.4.3 — wire-layer MCP audit + 3 contract-drift fixes
Date: 2026-07-28
Schema: v20 (unchanged across v2.4.x; v2.4.3 is test cleanup only)
Canonical tool count: 35 (unchanged — zero production code changes)
Commit: 198b92b
What this release does
v2.4.3 is the wire-layer hygiene audit the operator-approved roadmap
originally scoped as "vibe_spec/vibe_publish MCP wrapper fix".
The audit found that the original Form B JSON re-parse bug was
already fixed in F36 (v1.2.1, 2026-07-16) — verified by the F36
wire tests passing against the v2.4.x binary. v2.4.3 ships the
actual hygiene fixes the audit revealed.
Three wire-layer bugs fixed
Bug A — TestWire_F37F38F39F40_BootAgainstDirtyDB schema drift
The dirty-boot test seeded a constitutions table with the OLDER
schema (is_active column instead of enabled). Production
migration v2 standardised on enabled. The watchdog SQL queries
enabled, so booting against the dirty DB crashed with
SQL logic error: no such column: enabled.
Fix: updated the test's constitutions schema to match the current
production schema (label, source, file_path, parsed_json,
sha256, enabled, activated_at, UNIQUE constraint). The test
still validates F37/F38/F39/F40 boot resilience scenarios.
Bug B — TestWire_HealthPingShape canonical count contract drift
Test asserted registry.canonical_tools == 29, frozen at v2.0.0
contract. v2.1.0 added AGENT_MEMORY namespace (5 tools); v2.3.0
added agent_memory_recall. Current canonical is 35.
Fix: updated assertion to expect 35. The contract documentation
was already updated in v2.3.0 — this propagates the contract update
to the remaining test.
Bug C — TestWire_RuntimeToolEnumeration tools/list contract drift
Test asserted tools/list returns 29 (un-armed) or 32 (armed),
frozen at v2.0.0. Current is 35 (un-armed) or 38 (armed).
Fix: updated wantUnarmed = 35 and wantArmed = 38. File-header
contract doc updated.
Why update tests, not production code (Bug A)
The dirty DB scenario is SIMULATED by the test. Real users always
run migrations in order; the production schema has been enabled-
based since v2 in early 2026. Adding a defensive fallback path
(enabled OR is_active) would mask future schema drift rather
than expose it. Minimal blast radius: update the test, keep
production code clean.
CHANGELOG cleanup
Updated the v2.3.0 "Process note" (describing the pre-F36 Form B
workaround) to reflect that F36 fixed it in v1.2.1 and the
workaround is no longer needed. Documentation drift fix.
Tests (all wire tests pass)
TestWire_F33_VibePublishHappyPath PASS
TestWire_INV8_DefaultDSNRespectsIsolation PASS
TestWire_F35_TypeMismatchSurfacesFieldPath PASS
TestWire_F36_VibeSpecAcceptsTasksAsArray PASS (regression guard for F36)
TestWire_F36_VibeSpecAcceptsTasksAsStringifiedArray PASS (regression guard for F36)
TestWire_F37F38F39F40_BootAgainstDirtyDB PASS (Bug A fix)
TestWire_F37_DuplicateColumnDuringBoot PASS
TestWire_HealthPingShape PASS (Bug B fix)
TestWire_HealthPingLatency PASS
TestWire_INFRA002_ParseTasksFieldSurfacesFormAndCause PASS
TestWire_RuntimeToolEnumeration PASS (Bug C fix)
TestBridge7_* (4 tests) flaky under load (transport timeout when
cold-booting stdio subprocess + full suite in flight). All pass in
isolation. Same flake as v2.4.0/1/2 — not related to v2.4.3.
Drift governance
dark_memory_judge(eval_type=drift_judge) returned verdict=aligned
confidence 0.95 (evaluation 423). Release approved.
What v2.4.3 does NOT do (deliberate scope)
- Does not change the watchdog SQL to be schema-tolerant.
Production code is clean; the dirty DB is a test scenario. - Does not refactor F36's parseTasksField. The F36 dual-form
dispatch (Form A vs Form B) is well-tested and stable. - Does not add new tools or schema migrations. Zero production
code changes. Tool count remains 35. Schema v20 unchanged.
Upgrade notes
- Wire contract unchanged. Tool count remains 35.
- Zero schema migration.
- Existing v2.4.2 callers see no behavioral change.
Checksums (SHA-256)
dark-mem-mcp.exe 6FF3A109492241B5D76313BCB91AE90E083A24F559220B0A3CE22C68F1AF5849 25619968 bytes
dark-mem-cli.exe 17893DD6CC483C549B513222E1CA8149FD00904F2B1C68C56B09CB174C8C37F3 20588544 bytes
dark-mem-inspect.exe FAC9E7778DEE94C820BD482D5E9B9D7924975397DDB2BB5B9AC7AC62064F33DD 20133376 bytes
Verified by dark-mem-inspect --version → dark-mem-inspect 2.4.3.
Carrying forward from v2.4.x
- 35 canonical tools (no new tool in v2.4.3)
- Schema v20 unchanged across v2.4.x
- v2.4.0 drift_judge enrichment unchanged
- v2.4.1 agent_id plumbing unchanged
- v2.4.2 brand/compliance enrichment unchanged
v2.4.2 - brand_match + compliance_check enrichment with agent_memory
v2.4.2 — brand_match + compliance_check enrichment with agent_memory
Date: 2026-07-28
Schema: v20 (unchanged from v2.4.1; v2.4.2 is additive integration)
Canonical tool count: 35 (unchanged — no new tools, no schema migration)
Commit: 36c9513
What this release fixes
v2.4.0 wired agent_memory into the vibe-loop (ContextRecap on
session_start, drift_judge enrichment on publish_vibe, PriorFindings
on research_topic). But the canonical LLM-as-judge path (Judge,
JudgeConsensus) — used by brand_match, compliance_check, pii_detect,
prompt_injection_scan, grounding_check — was still blind to prior
context. A brand voice LLM scored new copy without seeing the brand
canon. A compliance LLM scored EU marketing copy without seeing GDPR
Article 13. v2.4.2 closes the "judges are blind" debt for
brand_match + compliance_check.
Strategy: PINNED memories, not BM25
v2.4.0 drift_judge enrichment (in PublishVibe) uses BM25 search
against the artifact text. v2.4.2 brand_match + compliance_check
enrichment uses PINNED memories instead, because:
- Brand decisions are operator-curated: the operator pinned them
because they're the brand canon. Pinned = explicit operator
intent, not text similarity. - Compliance decisions + findings are similar: operator pinned them
because they're jurisdictional canon. - BM25 against the artifact text is fragile for these judges: a
compliance decision like "GDPR Article 13 disclosure" rarely
shares keywords with the artifact copy being reviewed. Pinned
gives predictable, curated context. - drift_judge keeps BM25 (in PublishVibe) because drift detection
benefits from SPEC-relevant context, not pinned canon.
What gets enriched (per eval_type)
| eval_type | Kinds injected | Why |
|---|---|---|
brand_match |
[decision] |
Brand canon = operator-pinned decisions |
compliance_check |
[decision, finding] |
Compliance rules + prior flags |
drift_judge |
(unchanged) | Lives in PublishVibe (v2.4.0) |
pii_detect |
(none) | Pattern-matching, not RAG |
prompt_injection_scan |
(none) | Pattern-matching, not RAG |
grounding_check |
(out-of-scope) | Future v2.4.4 candidate |
Wire contract (additive)
// dark_memory_judge (orchestrator.O5):
{
"eval_type": "brand_match" | "compliance_check" | ...,
"content": "...",
"agent_id": "...", // NEW v2.4.2 — same priority chain as v2.4.1
"no_enrich": false, // NEW v2.4.2 — opt-out escape hatch
// ... rest unchanged
}
// dark_memory_consensus (orchestrator.O8):
{
"eval_type": "...",
"content": "...",
"agent_id": "...", // NEW v2.4.2 — forwarded to all N samples
"no_enrich": false, // NEW v2.4.2 — forwarded to all N samples
"n": 3,
// ... rest unchanged
}AgentID priority chain (unchanged from v2.4.1)
- Caller-supplied
AgentIDon the Judge call. projects.default_agent_id(set at tenant provisioning).- Empty string — no agent filter; v2.4.0 backward compat.
NoEnrich opt-out
Operators who want raw, no-enrichment behavior (e.g., sensitive
audits where the brand canon must not leak into the verdict) can
pass no_enrich: true on the Judge call. The LLM receives the
raw content unchanged. Default false = enrichment on.
Operator procedure for stale canon
When brand voice or compliance rules evolve, the operator's
canonical workflow is:
- Identify stale canon:
agent_memory_list(kind=decision, pinned_only=true, scope=project). - Save new canon first:
agent_memory_save(kind=decision, pinned=true, tags=brand,voice,2026-q3). - Unpin stale canon (don't delete):
agent_memory_update(id=stale_id, pinned=false). - Verify new canon is the only one surfaced.
- Re-run brand_match verdicts if needed (use
no_enrich=trueduring transition).
Limitations: v2.4.2 does NOT provide automatic staleness detection
or canon-versioning. Operators manage canon lifecycle manually.
Tests (9 new defensive tests, all pass)
Orchestrator-level (in tests/orchestration/agent_memory_v2_4_2_test.go):
TestV242_BrandMatch_EnrichesWithBrandDecisions— kind=decision
surfaces; kind=finding + kind=link filtered out (all pinned to
isolate the kind filter).TestV242_ComplianceCheck_EnrichesWithDecisionsAndFindings—
both decision + finding surface; note is filtered.TestV242_BrandMatch_NoEnrich_RespectsOptOut—no_enrich=true
→ LLM sees raw content unchanged.TestV242_PIIDetect_NoEnrichment— pattern-matching eval_type
stays blind.TestV242_Consensus_PassesAgentIDToAllSamples— N=3 consensus:
each sample sees same agent-scoped enrichment.TestV242_Consensus_PassesNoEnrichToAllSamples—no_enrich=true
forwarded to all N consensus samples.TestV242_AgentID_PriorityChain_ResolvesInJudge— Judge resolves
AgentID via v2.4.1 priority chain.TestV242_DriftJudge_EnrichmentUnchangedInPublishVibe— regression
guard: drift_judge enrichment still in PublishVibe, NOT moved to
Judge in v2.4.2.
Store-level (in tests/dual_driver/agent_memory_v2_4_2_test.go):
TestV242_Store_SearchAgentMemory_FilterByKind_DefenseInDepth
— verifies the Store's Kind filter actually filters.
Full test suite green.
Drift governance
drift_judge evaluation converged in 3 iterations:
- Eval 420:
drift_detectedconfidence 0.78 (5 concerns,
including legitimate NoEnrich-on-consensus-path bug) - Eval 421:
drift_detectedconfidence 0.72 (concerns
addressed but operator message needed verbatim citation) - Eval 422:
alignedconfidence 0.82 (all 5 concerns
resolved; release approved)
The drift_judge artifact (rev3) cites the verbatim operator message,
provides operational impact analysis for stale pinned canon,
includes an explicit INV-1 recoverability matrix, and documents the
operator procedure for handling stale canon.
What v2.4.2 does NOT do (deliberate scope)
- Does not touch drift_judge enrichment — it still lives in
PublishVibe(auditable since v2.4.0). Operators using
dark_memory_judge(eval_type=drift_judge)directly without
PublishVibeget NO enrichment — they must go through
PublishVibefor enriched prompts. - Does not enrich pii_detect, prompt_injection_scan, or
grounding_check. Pattern-matching judges don't benefit from
RAG; grounding_check is out-of-scope for v2.4.2. - The enriched prompt is NOT persisted in the audit trail —
only the LLM response (SDDEvaluation.VerdictJSON) is.
Operators needing prompt-level audit get it in v2.4.4+. - Memory-RAG is best-effort. If
agent_memoryis broken, Judge
runs with raw content (same fail-safe as v2.4.0).
Upgrade notes
- Wire contract is additive only. Existing v2.4.1 callers see no
behavioral change unless they explicitly opt in to
brand_match/compliance_check enrichment (which is on by default). - Operators who want raw, no-enrichment behavior can pass
no_enrich: trueper call. - Operators must PIN important brand + compliance decisions for
them to surface as enrichment (pinned = operator-curated canon). - v2.4.0 drift_judge enrichment in PublishVibe is unchanged.
- Tool count remains 35 (additive integration, no new tools).
Checksums (SHA-256)
dark-mem-mcp.exe 6AC77E507CC448B53F76A66864768E6FE959FF8AE5DD9E6F07017ACDF408EC11 25619968 bytes
dark-mem-cli.exe 6905E52261D266F6774D5163E5BA81AF93BEA79F91049CAD59CB900DF494F4C4 20588544 bytes
dark-mem-inspect.exe 500F757672786973B1F0DDCE96919863AB69712612E95930CA447B3BAE2567A3 20133376 bytes
Verified by dark-mem-inspect --version → dark-mem-inspect 2.4.2.
Carrying forward from v2.4.1
- 35 canonical tools (no new tool in v2.4.2)
- Schema v20 unchanged (additive integration only)
- All v2.4.1 INV-10 backward compat preserved
- drift_judge enrichment path unchanged
v2.4.1 - agent_id plumbing end-to-end
v2.4.1 — agent_id plumbing end-to-end
Date: 2026-07-28
Schema: v20 (was v19 in v2.3.0/v2.4.0)
Canonical tool count: 35 (unchanged — additive integration, no new tools)
Commit: a706646
What this release fixes
v2.3.0 added the agent_id column to agent_memory (Mem0 agent_id
semantics: the LLM that owns each memory). v2.4.0 wired
agent_memory into the vibe-loop (ContextRecap on session_start,
drift_judge enrichment on publish_vibe, PriorFindings on
research_topic) but used project-wide scope. As a result, when
multiple LLMs shared a project, each LLM's recap and judge
enrichment surfaced the OTHER LLM's decisions and findings —
exactly the cross-agent leakage the agent_id column was designed
to prevent.
v2.4.1 closes the plumbing. Every VLP integration point now has
a consistent agent_id resolution chain and forwards the resolved
agent_id to the Store filter.
Resolution priority chain (canonical, applies to all VLP integration points)
- Caller-supplied AgentID on the request —
session_start.AgentIDorpublish_vibe.AgentID. - projects.default_agent_id — set at tenant provisioning via
project_create(default_agent_id="..."). - Empty string — no agent filter; v2.4.0 backward compat.
Helper: resolveActiveAgentID(ctx, requested) in
internal/orchestration/agent_id.go. Best-effort: Store errors
swallowed, falls through to empty string. Never panic.
Migration v20
ALTER TABLE projects ADD COLUMN default_agent_id TEXT;Idempotent (SQLite ADD COLUMN without DEFAULT is a no-op on
re-apply; Postgres uses ADD COLUMN IF NOT EXISTS). No index
needed — read once per session_start / publish_vibe.
What v2.4.1 does NOT do (honest trade-off framing)
The empty-string fallback (priority 3) preserves v2.4.0 backward
compatibility. Projects that have NOT set projects.default_agent_id
retain v2.4.0 behavior: their ContextRecap and drift_judge
enrichment show ALL LLMs' memories, not just the active agent's.
This is a deliberate trade-off — the alternative (making empty
agent_id an error) would be a breaking change for v2.4.0 callers.
Operators who want per-LLM isolation must opt in by either:
- calling
project_create(default_agent_id="your-llm-id")at tenant provisioning, OR - passing
agent_idexplicitly on everysession_start/publish_vibecall.
Wire contract (additive)
dark_memory_project_create: gains optionaldefault_agent_idinput (max 128 chars); echoed on idempotent replay.dark_memory_session_start: gains optionalagent_idinput +active_agent_idoutput.ContextRecap.PinnedMemoriesandOpenTodosare filtered by the resolved agent_id.dark_memory_publish_vibe: gains optionalagent_idinput +active_agent_idoutput.drift_judgeenrichment is filtered by the resolved agent_id.
Store-layer change (the structural fix)
Store.ListAgentMemory now treats AgentID as an ADDITIVE
filter that composes with any scope (Project, Session,
Operator, Agent). In v2.3.0, AgentID was only applied when
scope=agent; v2.4.1 applies it whenever non-empty. When AgentID
is empty, the filter is not applied (v2.4.0 backward compat).
This is the structural fix that mitigates the cross-agent leakage
at the data plane. The orchestrator-level integration just plumbs
the resolved agent_id into the filter; the actual prevention
happens at the Store boundary.
Checksums (SHA-256)
dark-mem-mcp.exe 769089F791ADEDDC32E320D3EEC4B56B191632CCC99AE7802923AFE64F81879E 25611776 bytes
dark-mem-cli.exe B84B7D881BE55BACCCD7D26FF78BDEAC794BDC8002D5320F8FA2745A807C92A9 20588544 bytes
dark-mem-inspect.exe 0F50F51017A6B2F4640F8234CFF1655280A47A579D3A6A94FABB314CA5190DDA 20133376 bytes
Verified by dark-mem-inspect --version → dark-mem-inspect 2.4.1.
Drift governance
dark_memory_judge(eval_type=drift_judge) returned verdict=aligned
confidence=0.96 (evaluation 419). Approved for canonical artifact
publication.
drift_judge evolution:
- Eval 417:
needs_human0.74 (initial; silent-fallback concern) - Eval 418:
drift_detected0.86 (after 3 defensive tests but before Store-level test + honest framing) - Eval 419:
aligned0.96 (final — Store-level test + honest "mitigates the debt" framing + INV-10 justification for empty fallback)
Tests
8 new defensive tests across 2 test files:
Orchestrator-level (helper + VLP integration) in
tests/orchestration/agent_memory_v2_4_1_test.go (7 tests):
TestV241_ContextRecap_RespectsAgentIDTestV241_ContextRecap_NoAgentID_FallsBackToProjectWideTestV241_DriftJudge_EnrichesByActiveAgentIDTestV241_DefaultAgentID_ResolvesOnSessionStartTestV241_AgentID_SessionStart_CallerWinsOverProjectDefaultTestV241_AgentID_PublishVibe_CallerWinsOverProjectDefaultTestV241_AgentID_EmptyChain_NoPanic_Deterministic
Store-level (structural fix verification) in
tests/dual_driver/agent_memory_v2_4_1_test.go (1 test):
TestV241_Store_ListAgentMemory_AdditiveAgentIDFilter(3 assertions: project+agent_id filter, project+empty, agent+agent_id)
Full test suite green (verified pre + post all 8 tests).
Upgrade notes
- Wire contract is additive only. Existing v2.4.0 callers see no behavioral change.
- New
active_agent_idfield onsession_start/publish_vibeoutputs is best-effort and empty when no agent_id is configured. - All integrations inherit INV-10 (rows survive session close). Resolution chain is project-level + per-call; per-session isolation is a v2.4.x follow-up.
- The Store-layer additive filter is the structural fix; the orchestrator-level integration just plumbs the resolved agent_id.
Carrying forward from v2.4.0
- 35 canonical tools (no new tool in v2.4.1)
- Two behavior-default flips from v2.3.0 still apply:
scope=currentdefault isproject(wassessionpre-v2.3.0)bind_sessiondefault isfalse(was implicittruepre-v2.3.0)
v2.4.0 - memory RAG into the vibe-loop
v2.4.0 — memory RAG into the vibe-loop
Date: 2026-07-28
Schema: v19 (unchanged from v2.3.0)
Canonical tool count: 35 (unchanged — additive integration, no new tools)
Commit: 621e297
What this release fixes
The agent_memory data plane shipped with producers and one consumer (recall), but the vibe-loop itself (session_start, drift_judge, research_topic, judge, consensus) never consulted it. Operators landed on every session with a blank slate. v2.4.0 closes that data-plane orphan debt.
What's new
session_startnow emits acontext_recapfield withpinned_memories(top 10) +open_todos(top 20).vibe_publish's drift_judge path now enriches the artifact text with relevant prior decisions + findings from agent_memory before calling the LLM judge (invisible at the wire level — the artifact is what gets persisted).research_topicnow populates aprior_findingsfield with top-5 in-project findings relevant to the query.- 5 helper functions added to
internal/orchestration/agent_memory.go:recallForVibe,listPinnedForVibe,listOpenTodosForVibe,formatHitsForContext,firstLine.
Drift governance
dark_memory_judge(eval_type=drift_judge) returned verdict=aligned confidence=0.95 (evaluation 416). Approved for canonical artifact publication.
Checksums (SHA-256)
dark-mem-mcp.exe 2864CD419748C04AC31A3E0AE05DB1A1FBE5F9DD577920D41FDED82202B3719A 25602048 bytes
dark-mem-cli.exe FA71CADAA9C11620CD6205823E8FB286CCEE63A9F2EE61B5D706F7889D687964 20589056 bytes
dark-mem-inspect.exe AF0BC91A172FF094BC40353E8FA0F9D7E9E8CDA3994B9012928AC751326C46C6 20132864 bytes
Verified by dark-mem-inspect --version → dark-mem-inspect 2.4.0.
Pre-flight governance
dark_memory_session_start+dark_memory_judge(eval_type=drift_judge)(verdict=aligned confidence=0.95)go build ./...exit 0go test ./...all green (4 new orch tests + 6 prior dual_driver tests + full suite)
Upgrade notes
- Wire contract is additive only. Existing callers see no behavioral change.
- New ContextRecap on
session_startand PriorFindings onresearch_topicare best-effort: errors swallowed; broken agent_memory does NOT block VLP paths. - All integrations inherit INV-10 (rows survive session close). Recap is project-wide scope by default; per-operator scope is a v2.4.x follow-up.
- The drift_judge enrichment is INVISIBLE in the persisted artifact; only the LLM prompt sees it. This is intentional — the artifact is what humans/agents downstream consume, the prompt is what the judge consumes.
v2.3.0 → v2.4.0 — what carries forward from v2.3.0
- Schema v19 (no migration in v2.4.0)
- 35 canonical tools (no new tool in v2.4.0)
- Two behavior-default flips from v2.3.0 still apply:
scope=currentdefault isproject(wassessionpre-v2.3.0)bind_sessiondefault isfalse(was implicittruepre-v2.3.0)