Release/v2.38.0 - #138
Conversation
The typecheck gate covered marm_mcp_server/core/ only, so two thirds of the package could accumulate type errors unnoticed, and it had already gone red at 115 against a baseline of 113. Widening the scope to the whole package found 93 more errors and, more usefully, both ends of the same defects: an implicit Optional parameter counted once inside core/ while every caller honestly passing None to it went unreported. 208 errors at the new scope, now 155. Scope and reporting: - TARGET is the whole package. Two reporting bugs had to be fixed first or the wider scope would have misreported: per-file counts keyed on basename merged the nine names that repeat across subpackages (memory.py, concepts.py, models.py, cli.py, ...), and the clean-file count used a non-recursive glob. Cleared: - types-psutil for real stubs, plus per-library ignore_missing_imports for the three packages that ship no py.typed and have no stubs. Named one library at a time so a mistyped MARM import still errors, verified with a probe. - 19 implicit Optional signatures and the 10 caller-side arg-type errors they caused. No new errors surfaced inside those bodies, so the signatures were wrong and the code was already correct. - _classify_chunk declared Optional[str] but cannot return None on either path, which its own docstring and tests already asserted. - Three separate errors traced to one variable name serving two unrelated purposes, where the first assignment fixed a type the second use inherited. Left visible: - endpoints/graph.py:179, a narrow check-then-use race on get_client() during shutdown. It is a 500 instead of the usual unavailable payload, with no stuck lease and no effect on core memory. All 13 call sites share it; the other 12 are invisible only because CbmClient resolves to Any. Suppressing it here would claim a safety it does not have. See docs/current/graph-client-none-guard.md. No behavior change and no version bump. 1077 tests pass, unchanged before and after. Latest tag v2.37.0 is released, so the unreleased minor gap is 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Continues the typing pass from a89fe95: 155 errors down to 78. Everything here was already implied by the code or already unused by the toolchain, so no behavior changes and no design decisions. Connection plumbing, which cascaded further than expected: - memory_db.py's pool and ConnectionContext are typed end to end, including __enter__ -> sqlite3.Connection. That only works with the pool's own get_connection typed too, otherwise a no-untyped-def just becomes a no-any-return. self.conn needed sqlite3.Connection | None for __enter__ to narrow. That file went 11 errors to 3. - 14 conn parameters and the 3 get_connection methods. Annotating the boundary cleared several no-any-return errors on its own, since a typed conn makes cursor.rowcount an int rather than Any. Signatures: - 21 functions given -> None, and the 4 middleware given call_next: RequestResponseEndpoint with -> Response. - The 3 lifespan functions are AsyncIterator[None], not None. A first pass looked for "no return with a value" and would have mislabeled all three, since a generator has no return statement at all. - 24 return types that were mechanically determinable from their own return expressions, applied by function name so a shifted line could not mis-target. One real finding, from a body mypy had been skipping: protocol_injection reads response.body_iterator, which starlette's declared Response type does not carry. BaseHTTPMiddleware actually returns a private _StreamingResponse. The code is correct and starlette's hint is too narrow, so this is an ignore with the reason rather than a cast that would misstate the object's identity. Toolchain: - Removed black, isort, and flake8 from dev deps, their pyproject config, and the publish workflow's install line. None were invoked by any workflow. black wanted to reformat 13 files against ruff format, producing worse output on comprehensions containing triple-quoted strings, and flake8's 1,136 findings were E501 against its own 79-char default plus E203, which is knowingly incompatible with black-style slices. Satisfying either would have moved code away from what CI enforces. - Import order was checked and left alone: 108 I001 findings are cosmetic, and ruff correctly leaves server_stdio.py alone, where imports sit after a builtins.print patch that must run first so stdout stays a clean JSON-RPC channel. 1078 tests pass. ruff check, ruff format, and the typecheck gate are clean at baseline 78. Latest tag v2.37.0 is released, so the unreleased minor gap is 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Expand Mypy coverage across the server package, strengthen internal contracts, and standardize Ruff validation in CI.\n\nDocument the release, align v2.38.0 metadata, and preserve the two graph lifecycle findings as an explicit follow-up rather than suppressing them.
📝 WalkthroughWalkthroughChangesThe release updates version references to 2.38.0, replaces legacy formatting tools with Ruff, expands Mypy coverage, strengthens type annotations across the server, core, services, and utilities, and improves document-to-memory mirror retry behavior. Release, tooling, and typecheck coverage
Estimated code review effort: 3 (Moderate) | ~30 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/publish-mcp.yml:
- Line 59: Update the release workflow’s dependency installation and typecheck
gate around scripts/typecheck.py to pin mypy to the baseline’s exact version and
include the exact validation scripts, configuration, and versioned inputs used
to establish BASELINE = 2. Ensure the release check runs against those pinned
inputs rather than unversioned or drifting tooling.
In `@marm-mcp-server/marm_mcp_server/core/consolidation.py`:
- Around line 45-46: Reorder the union members in the affected annotations of
the consolidation function so None is the final member, including project and
platform at both declaration sites. Preserve the existing types and _Unset
defaults; only adjust the union ordering to satisfy Ruff RUF036.
In `@marm-mcp-server/marm_mcp_server/services/notebook.py`:
- Around line 277-279: Update _save so a failure from docs_db.set_memory_id
after memory.store_doc_mirror does not leave synchronization unreconciled: catch
the update failure, persist a durable idempotent reconciliation record keyed by
doc_id, and report mirror_status as "pending". Ensure reconciliation retries
safely under concurrent saves and SQLite transactions, and only mark the mirror
synchronized after the docs row update succeeds.
In `@marm-mcp-server/pyproject.toml`:
- Line 7: Align all release metadata with the chosen version and add the
corresponding changelog entry: update marm-mcp-server/pyproject.toml:7, both
version references in marm-mcp-server/server.json:6 and 20-25, and
marm-mcp-server/marm_mcp_server/server.py:8-9 consistently, then add a
CHANGELOG.md release entry for that same version before release.
In `@scripts/typecheck.py`:
- Line 28: Align the type-error baseline behavior with its documentation: update
the gate around BASELINE in scripts/typecheck.py to compare against a snapshot
or per-file baseline so replacements are rejected, or remove the claim that
every new type error fails from CHANGELOG.md lines 8-9. Apply the chosen
correction at the corresponding site; no other changes are required.
In `@skills/marm-init/SKILL.md`:
- Around line 46-47: Pin both installer artifacts to immutable releases in
skills/marm-init/SKILL.md lines 46-47 and
marm-mcp-server/marm_mcp_server/resources/skills/marm-init/SKILL.md lines 46-47:
replace the unversioned pip package with a fixed marm-mcp-server version and
replace the Docker image’s latest tag with a fixed release tag or digest,
keeping both copies consistent.
- Around line 57-60: The protocol fetch path in skills/marm-init/SKILL.md lines
57-60 and marm-mcp-server/marm_mcp_server/resources/skills/marm-init/SKILL.md
lines 57-60 must validate the remote source before using its content or
fallbacks. Add a checksum or pinned-commit verification for the PROTOCOL.md
source, and only execute or continue with fetched content when validation
succeeds; apply the same change to both copies.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 5cc9cdd6-2a9d-4704-bdee-5c769c70da93
📒 Files selected for processing (67)
.github/workflows/publish-mcp.ymlAGENTS.mdCHANGELOG.mddocs/INSTALL-LINUX.mddocs/INSTALL-WINDOWS.mdmarm-mcp-server/Dockerfilemarm-mcp-server/docker-compose.ymlmarm-mcp-server/marm_mcp_server/__init__.pymarm-mcp-server/marm_mcp_server/cli.pymarm-mcp-server/marm_mcp_server/config/settings.pymarm-mcp-server/marm_mcp_server/console/app.pymarm-mcp-server/marm_mcp_server/console/cli.pymarm-mcp-server/marm_mcp_server/console/endpoints/concepts.pymarm-mcp-server/marm_mcp_server/core/compaction.pymarm-mcp-server/marm_mcp_server/core/compaction_scheduler.pymarm-mcp-server/marm_mcp_server/core/concept_db.pymarm-mcp-server/marm_mcp_server/core/concept_extraction.pymarm-mcp-server/marm_mcp_server/core/consolidation.pymarm-mcp-server/marm_mcp_server/core/docs_db.pymarm-mcp-server/marm_mcp_server/core/events.pymarm-mcp-server/marm_mcp_server/core/graph_index_lock.pymarm-mcp-server/marm_mcp_server/core/graph_index_worker.pymarm-mcp-server/marm_mcp_server/core/memory.pymarm-mcp-server/marm_mcp_server/core/memory_db.pymarm-mcp-server/marm_mcp_server/core/memory_delete.pymarm-mcp-server/marm_mcp_server/core/memory_ops.pymarm-mcp-server/marm_mcp_server/core/memory_recall.pymarm-mcp-server/marm_mcp_server/core/memory_scoring.pymarm-mcp-server/marm_mcp_server/core/memory_utils.pymarm-mcp-server/marm_mcp_server/core/models.pymarm-mcp-server/marm_mcp_server/core/rate_limiter.pymarm-mcp-server/marm_mcp_server/core/response_limiter.pymarm-mcp-server/marm_mcp_server/core/runtime_manager.pymarm-mcp-server/marm_mcp_server/core/shutdown_manager.pymarm-mcp-server/marm_mcp_server/core/stdio_tool_lifecycle.pymarm-mcp-server/marm_mcp_server/core/write_queue.pymarm-mcp-server/marm_mcp_server/endpoints/compaction.pymarm-mcp-server/marm_mcp_server/endpoints/concepts.pymarm-mcp-server/marm_mcp_server/endpoints/logging.pymarm-mcp-server/marm_mcp_server/endpoints/memory.pymarm-mcp-server/marm_mcp_server/endpoints/notebook.pymarm-mcp-server/marm_mcp_server/endpoints/reasoning.pymarm-mcp-server/marm_mcp_server/endpoints/session.pymarm-mcp-server/marm_mcp_server/endpoints/system.pymarm-mcp-server/marm_mcp_server/middleware/auth.pymarm-mcp-server/marm_mcp_server/middleware/protocol_injection.pymarm-mcp-server/marm_mcp_server/middleware/rate_limiting.pymarm-mcp-server/marm_mcp_server/resources/skills/marm-init/SKILL.mdmarm-mcp-server/marm_mcp_server/server.pymarm-mcp-server/marm_mcp_server/server_stdio.pymarm-mcp-server/marm_mcp_server/services/analytics.pymarm-mcp-server/marm_mcp_server/services/automation.pymarm-mcp-server/marm_mcp_server/services/compaction_apply.pymarm-mcp-server/marm_mcp_server/services/compaction_summarize.pymarm-mcp-server/marm_mcp_server/services/documentation.pymarm-mcp-server/marm_mcp_server/services/notebook.pymarm-mcp-server/marm_mcp_server/services/product_workflows.pymarm-mcp-server/marm_mcp_server/services/recall.pymarm-mcp-server/marm_mcp_server/services/stdio_graph_tools.pymarm-mcp-server/marm_mcp_server/utils/chunk_backfill.pymarm-mcp-server/marm_mcp_server/utils/embedding_migration.pymarm-mcp-server/marm_mcp_server/utils/helpers.pymarm-mcp-server/marm_mcp_server/utils/security.pymarm-mcp-server/pyproject.tomlmarm-mcp-server/server.jsonscripts/typecheck.pyskills/marm-init/SKILL.md
📜 Review details
🧰 Additional context used
📓 Path-based instructions (9)
{marm-mcp-server/pyproject.toml,marm-mcp-server/server.json,marm-mcp-server/marm_mcp_server/__init__.py,marm-mcp-server/marm_mcp_server/config/settings.py,marm-mcp-server/marm_mcp_server/server.py,marm-mcp-server/Dockerfile,docker-compose.yml,README.md,marm-mcp-server/README.md,marm-mcp-server/marm_mcp_server/resources/marm-docs/README.md,docs/INSTALL-*.md}
📄 CodeRabbit inference engine (AGENTS.md)
When bumping the version, update every listed package, server, Docker, compose, README, and install-document version occurrence and audit with
python scripts/find-versions.py.
Files:
marm-mcp-server/Dockerfiledocs/INSTALL-WINDOWS.mddocs/INSTALL-LINUX.mdmarm-mcp-server/marm_mcp_server/__init__.pymarm-mcp-server/server.jsonmarm-mcp-server/pyproject.tomlmarm-mcp-server/marm_mcp_server/server.pymarm-mcp-server/marm_mcp_server/config/settings.py
**/*.md
⚙️ CodeRabbit configuration file
**/*.md: Only flag documentation issues that are materially wrong, misleading for installation/release behavior, or inconsistent with live MCP behavior. Skip style, phrasing, formatting, and wording preferences.
Files:
AGENTS.mddocs/INSTALL-WINDOWS.mddocs/INSTALL-LINUX.mdCHANGELOG.mdmarm-mcp-server/marm_mcp_server/resources/skills/marm-init/SKILL.mdskills/marm-init/SKILL.md
marm-mcp-server/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
Keep HTTP and STDIO transports in exact parity; never fork behavior between transports.
Files:
marm-mcp-server/marm_mcp_server/services/analytics.pymarm-mcp-server/marm_mcp_server/middleware/auth.pymarm-mcp-server/marm_mcp_server/core/runtime_manager.pymarm-mcp-server/marm_mcp_server/__init__.pymarm-mcp-server/marm_mcp_server/services/automation.pymarm-mcp-server/marm_mcp_server/console/endpoints/concepts.pymarm-mcp-server/marm_mcp_server/core/shutdown_manager.pymarm-mcp-server/marm_mcp_server/console/cli.pymarm-mcp-server/marm_mcp_server/core/events.pymarm-mcp-server/marm_mcp_server/core/compaction.pymarm-mcp-server/marm_mcp_server/server.pymarm-mcp-server/marm_mcp_server/endpoints/notebook.pymarm-mcp-server/marm_mcp_server/services/compaction_summarize.pymarm-mcp-server/marm_mcp_server/endpoints/reasoning.pymarm-mcp-server/marm_mcp_server/endpoints/system.pymarm-mcp-server/marm_mcp_server/core/memory_utils.pymarm-mcp-server/marm_mcp_server/services/compaction_apply.pymarm-mcp-server/marm_mcp_server/utils/helpers.pymarm-mcp-server/marm_mcp_server/core/compaction_scheduler.pymarm-mcp-server/marm_mcp_server/config/settings.pymarm-mcp-server/marm_mcp_server/server_stdio.pymarm-mcp-server/marm_mcp_server/core/memory_ops.pymarm-mcp-server/marm_mcp_server/core/concept_extraction.pymarm-mcp-server/marm_mcp_server/services/stdio_graph_tools.pymarm-mcp-server/marm_mcp_server/utils/chunk_backfill.pymarm-mcp-server/marm_mcp_server/services/product_workflows.pymarm-mcp-server/marm_mcp_server/endpoints/session.pymarm-mcp-server/marm_mcp_server/cli.pymarm-mcp-server/marm_mcp_server/endpoints/memory.pymarm-mcp-server/marm_mcp_server/middleware/protocol_injection.pymarm-mcp-server/marm_mcp_server/core/graph_index_lock.pymarm-mcp-server/marm_mcp_server/utils/security.pymarm-mcp-server/marm_mcp_server/services/recall.pymarm-mcp-server/marm_mcp_server/core/models.pymarm-mcp-server/marm_mcp_server/core/stdio_tool_lifecycle.pymarm-mcp-server/marm_mcp_server/endpoints/compaction.pymarm-mcp-server/marm_mcp_server/middleware/rate_limiting.pymarm-mcp-server/marm_mcp_server/console/app.pymarm-mcp-server/marm_mcp_server/core/memory_recall.pymarm-mcp-server/marm_mcp_server/core/docs_db.pymarm-mcp-server/marm_mcp_server/endpoints/concepts.pymarm-mcp-server/marm_mcp_server/core/memory_delete.pymarm-mcp-server/marm_mcp_server/core/response_limiter.pymarm-mcp-server/marm_mcp_server/services/notebook.pymarm-mcp-server/marm_mcp_server/services/documentation.pymarm-mcp-server/marm_mcp_server/endpoints/logging.pymarm-mcp-server/marm_mcp_server/core/memory_scoring.pymarm-mcp-server/marm_mcp_server/core/concept_db.pymarm-mcp-server/marm_mcp_server/core/graph_index_worker.pymarm-mcp-server/marm_mcp_server/core/rate_limiter.pymarm-mcp-server/marm_mcp_server/core/write_queue.pymarm-mcp-server/marm_mcp_server/core/memory_db.pymarm-mcp-server/marm_mcp_server/utils/embedding_migration.pymarm-mcp-server/marm_mcp_server/core/consolidation.pymarm-mcp-server/marm_mcp_server/core/memory.py
marm-mcp-server/marm_mcp_server/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
marm-mcp-server/marm_mcp_server/**/*.py: All memory writes must use the serialized asynchronous write queue; do not add bypass paths.
A semantic-store failure duringmarm_log_entrymust never fail the log write.
Keep the memory, concept-graph, and analytics SQLite databases isolated; never share connections or pools between them.
Graph and concept failures must never break the seven core memory tools.
Every code-index call anddelete_projectmust acquire the graph gate, and release must be driven by engine-call completion rather than awaiting-task completion.
Runtime switches must be persisted in the database; background workers must reread their flag every cycle and continue running while disabled.
Background indexing must never block writes, recall, or startup.
Graph enrichment inmarm_smart_recallmust be read-only, fail-open, bounded, and trimmed before primary results when enforcing response limits.
Use one lazily loaded, lock-serialized fastembed encoder with 512 dimensions; writes must succeed when the encoder is unavailable.
Prefer the smallest change that solves the task; avoid speculative abstractions and unrequested configuration flags.
Keep comments minimal and explain only non-obvious reasons; do not narrate the next line.
Keep orchestration in its current owner file and extract modules only at real boundaries consistent with the existing endpoint split.
Files:
marm-mcp-server/marm_mcp_server/services/analytics.pymarm-mcp-server/marm_mcp_server/middleware/auth.pymarm-mcp-server/marm_mcp_server/core/runtime_manager.pymarm-mcp-server/marm_mcp_server/__init__.pymarm-mcp-server/marm_mcp_server/services/automation.pymarm-mcp-server/marm_mcp_server/console/endpoints/concepts.pymarm-mcp-server/marm_mcp_server/core/shutdown_manager.pymarm-mcp-server/marm_mcp_server/console/cli.pymarm-mcp-server/marm_mcp_server/core/events.pymarm-mcp-server/marm_mcp_server/core/compaction.pymarm-mcp-server/marm_mcp_server/server.pymarm-mcp-server/marm_mcp_server/endpoints/notebook.pymarm-mcp-server/marm_mcp_server/services/compaction_summarize.pymarm-mcp-server/marm_mcp_server/endpoints/reasoning.pymarm-mcp-server/marm_mcp_server/endpoints/system.pymarm-mcp-server/marm_mcp_server/core/memory_utils.pymarm-mcp-server/marm_mcp_server/services/compaction_apply.pymarm-mcp-server/marm_mcp_server/utils/helpers.pymarm-mcp-server/marm_mcp_server/core/compaction_scheduler.pymarm-mcp-server/marm_mcp_server/config/settings.pymarm-mcp-server/marm_mcp_server/server_stdio.pymarm-mcp-server/marm_mcp_server/core/memory_ops.pymarm-mcp-server/marm_mcp_server/core/concept_extraction.pymarm-mcp-server/marm_mcp_server/services/stdio_graph_tools.pymarm-mcp-server/marm_mcp_server/utils/chunk_backfill.pymarm-mcp-server/marm_mcp_server/services/product_workflows.pymarm-mcp-server/marm_mcp_server/endpoints/session.pymarm-mcp-server/marm_mcp_server/cli.pymarm-mcp-server/marm_mcp_server/endpoints/memory.pymarm-mcp-server/marm_mcp_server/middleware/protocol_injection.pymarm-mcp-server/marm_mcp_server/core/graph_index_lock.pymarm-mcp-server/marm_mcp_server/utils/security.pymarm-mcp-server/marm_mcp_server/services/recall.pymarm-mcp-server/marm_mcp_server/core/models.pymarm-mcp-server/marm_mcp_server/core/stdio_tool_lifecycle.pymarm-mcp-server/marm_mcp_server/endpoints/compaction.pymarm-mcp-server/marm_mcp_server/middleware/rate_limiting.pymarm-mcp-server/marm_mcp_server/console/app.pymarm-mcp-server/marm_mcp_server/core/memory_recall.pymarm-mcp-server/marm_mcp_server/core/docs_db.pymarm-mcp-server/marm_mcp_server/endpoints/concepts.pymarm-mcp-server/marm_mcp_server/core/memory_delete.pymarm-mcp-server/marm_mcp_server/core/response_limiter.pymarm-mcp-server/marm_mcp_server/services/notebook.pymarm-mcp-server/marm_mcp_server/services/documentation.pymarm-mcp-server/marm_mcp_server/endpoints/logging.pymarm-mcp-server/marm_mcp_server/core/memory_scoring.pymarm-mcp-server/marm_mcp_server/core/concept_db.pymarm-mcp-server/marm_mcp_server/core/graph_index_worker.pymarm-mcp-server/marm_mcp_server/core/rate_limiter.pymarm-mcp-server/marm_mcp_server/core/write_queue.pymarm-mcp-server/marm_mcp_server/core/memory_db.pymarm-mcp-server/marm_mcp_server/utils/embedding_migration.pymarm-mcp-server/marm_mcp_server/core/consolidation.pymarm-mcp-server/marm_mcp_server/core/memory.py
**/*.py
⚙️ CodeRabbit configuration file
**/*.py: Prioritize runtime correctness, async/concurrency safety, SQLite transaction safety, auth/rate-limit behavior, release-breaking packaging issues, and MCP protocol compatibility.
Files:
marm-mcp-server/marm_mcp_server/services/analytics.pymarm-mcp-server/marm_mcp_server/middleware/auth.pymarm-mcp-server/marm_mcp_server/core/runtime_manager.pymarm-mcp-server/marm_mcp_server/__init__.pymarm-mcp-server/marm_mcp_server/services/automation.pymarm-mcp-server/marm_mcp_server/console/endpoints/concepts.pymarm-mcp-server/marm_mcp_server/core/shutdown_manager.pymarm-mcp-server/marm_mcp_server/console/cli.pymarm-mcp-server/marm_mcp_server/core/events.pymarm-mcp-server/marm_mcp_server/core/compaction.pymarm-mcp-server/marm_mcp_server/server.pymarm-mcp-server/marm_mcp_server/endpoints/notebook.pymarm-mcp-server/marm_mcp_server/services/compaction_summarize.pymarm-mcp-server/marm_mcp_server/endpoints/reasoning.pymarm-mcp-server/marm_mcp_server/endpoints/system.pymarm-mcp-server/marm_mcp_server/core/memory_utils.pymarm-mcp-server/marm_mcp_server/services/compaction_apply.pymarm-mcp-server/marm_mcp_server/utils/helpers.pymarm-mcp-server/marm_mcp_server/core/compaction_scheduler.pymarm-mcp-server/marm_mcp_server/config/settings.pymarm-mcp-server/marm_mcp_server/server_stdio.pymarm-mcp-server/marm_mcp_server/core/memory_ops.pymarm-mcp-server/marm_mcp_server/core/concept_extraction.pymarm-mcp-server/marm_mcp_server/services/stdio_graph_tools.pymarm-mcp-server/marm_mcp_server/utils/chunk_backfill.pymarm-mcp-server/marm_mcp_server/services/product_workflows.pymarm-mcp-server/marm_mcp_server/endpoints/session.pymarm-mcp-server/marm_mcp_server/cli.pymarm-mcp-server/marm_mcp_server/endpoints/memory.pymarm-mcp-server/marm_mcp_server/middleware/protocol_injection.pymarm-mcp-server/marm_mcp_server/core/graph_index_lock.pymarm-mcp-server/marm_mcp_server/utils/security.pymarm-mcp-server/marm_mcp_server/services/recall.pymarm-mcp-server/marm_mcp_server/core/models.pymarm-mcp-server/marm_mcp_server/core/stdio_tool_lifecycle.pymarm-mcp-server/marm_mcp_server/endpoints/compaction.pymarm-mcp-server/marm_mcp_server/middleware/rate_limiting.pymarm-mcp-server/marm_mcp_server/console/app.pymarm-mcp-server/marm_mcp_server/core/memory_recall.pymarm-mcp-server/marm_mcp_server/core/docs_db.pymarm-mcp-server/marm_mcp_server/endpoints/concepts.pymarm-mcp-server/marm_mcp_server/core/memory_delete.pymarm-mcp-server/marm_mcp_server/core/response_limiter.pymarm-mcp-server/marm_mcp_server/services/notebook.pyscripts/typecheck.pymarm-mcp-server/marm_mcp_server/services/documentation.pymarm-mcp-server/marm_mcp_server/endpoints/logging.pymarm-mcp-server/marm_mcp_server/core/memory_scoring.pymarm-mcp-server/marm_mcp_server/core/concept_db.pymarm-mcp-server/marm_mcp_server/core/graph_index_worker.pymarm-mcp-server/marm_mcp_server/core/rate_limiter.pymarm-mcp-server/marm_mcp_server/core/write_queue.pymarm-mcp-server/marm_mcp_server/core/memory_db.pymarm-mcp-server/marm_mcp_server/utils/embedding_migration.pymarm-mcp-server/marm_mcp_server/core/consolidation.pymarm-mcp-server/marm_mcp_server/core/memory.py
{marm-mcp-server/marm_mcp_server/endpoints/**/*.py,marm-mcp-server/marm_mcp_server/server.py,marm-mcp-server/marm_mcp_server/server_stdio.py,marm-mcp-server/server.json,scripts/find-tools.py,README.md,docs/PROTOCOL.md,docs/PROTOCOL-LITE.md,marm-mcp-server/marm_mcp_server/resources/marm-docs/**/*.md,marm-mcp-server/tests/**/*.py}
📄 CodeRabbit inference engine (AGENTS.md)
When adding or removing an MCP tool, update its endpoint, HTTP route and whitelist, STDIO registration,
server.json, canonical tool list, all full tool-list documentation and counts, and tests for both transports; then runpython scripts/find-tools.py.
Files:
marm-mcp-server/server.jsonmarm-mcp-server/marm_mcp_server/server.pymarm-mcp-server/marm_mcp_server/endpoints/notebook.pymarm-mcp-server/marm_mcp_server/endpoints/reasoning.pymarm-mcp-server/marm_mcp_server/endpoints/system.pymarm-mcp-server/marm_mcp_server/server_stdio.pymarm-mcp-server/marm_mcp_server/endpoints/session.pymarm-mcp-server/marm_mcp_server/endpoints/memory.pymarm-mcp-server/marm_mcp_server/endpoints/compaction.pymarm-mcp-server/marm_mcp_server/endpoints/concepts.pymarm-mcp-server/marm_mcp_server/endpoints/logging.py
marm-mcp-server/marm_mcp_server/server.py
📄 CodeRabbit inference engine (AGENTS.md)
HTTP tools must be registered in both the route definitions and the
MCP_TOOL_OPERATIONSwhitelist.
Files:
marm-mcp-server/marm_mcp_server/server.py
marm-mcp-server/marm_mcp_server/endpoints/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
Endpoint logic belongs under
endpoints/, split by surface; shared helpers belong incore/.
Files:
marm-mcp-server/marm_mcp_server/endpoints/notebook.pymarm-mcp-server/marm_mcp_server/endpoints/reasoning.pymarm-mcp-server/marm_mcp_server/endpoints/system.pymarm-mcp-server/marm_mcp_server/endpoints/session.pymarm-mcp-server/marm_mcp_server/endpoints/memory.pymarm-mcp-server/marm_mcp_server/endpoints/compaction.pymarm-mcp-server/marm_mcp_server/endpoints/concepts.pymarm-mcp-server/marm_mcp_server/endpoints/logging.py
marm-mcp-server/marm_mcp_server/server_stdio.py
📄 CodeRabbit inference engine (AGENTS.md)
STDIO owns the
FastMCPapp and core wrappers; graph and concept services must be registered after core tools sotools/listorder remains stable.
Files:
marm-mcp-server/marm_mcp_server/server_stdio.py
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: Lyellr88/marm-memory
Timestamp: 2026-08-10T10:59:10.458Z
Learning: Never commit changes without an explicit user request.
Learnt from: CR
Repo: Lyellr88/marm-memory
Timestamp: 2026-08-10T10:59:10.458Z
Learning: Use SemVer: MAJOR for breaking changes, MINOR for new tools, parameters, or features, and PATCH for fixes and documentation updates.
📚 Learning: 2026-07-31T08:30:32.056Z
Learnt from: Lyellr88
Repo: Lyellr88/marm-memory PR: 125
File: docs/INSTALL-LINUX.md:323-323
Timestamp: 2026-07-31T08:30:32.056Z
Learning: In the Linux and Windows installation documentation, treat http://localhost:8001 as the primary MARM MCP Server endpoint. Do not validate its response contract against the standalone marm-mcp-server/marm_graph/server.py health route, because marm-graph is embedded in the primary marm_mcp_server service.
Applied to files:
docs/INSTALL-WINDOWS.mddocs/INSTALL-LINUX.md
🪛 GitHub Actions: Ruff CI / 0_ruff.txt
marm-mcp-server/marm_mcp_server/core/consolidation.py
[error] 45-45: Ruff check failed: RUF036 — None is not at the end of the type union. Command: ruff check --output-format=github.
🪛 GitHub Actions: Ruff CI / ruff
marm-mcp-server/marm_mcp_server/core/consolidation.py
[error] 45-45: Ruff RUF036: None is not at the end of the type union. Fix the type annotation ordering.
🪛 GitHub Check: ruff
marm-mcp-server/marm_mcp_server/core/consolidation.py
[failure] 74-74: ruff (RUF036)
marm_mcp_server/core/consolidation.py:74:15: RUF036 None not at the end of the type union.
help: Move None to the end of the type union
[failure] 73-73: ruff (RUF036)
marm_mcp_server/core/consolidation.py:73:14: RUF036 None not at the end of the type union.
help: Move None to the end of the type union
[failure] 46-46: ruff (RUF036)
marm_mcp_server/core/consolidation.py:46:15: RUF036 None not at the end of the type union.
help: Move None to the end of the type union
[failure] 45-45: ruff (RUF036)
marm_mcp_server/core/consolidation.py:45:14: RUF036 None not at the end of the type union.
help: Move None to the end of the type union
🪛 SkillSpector (2.5.1)
marm-mcp-server/marm_mcp_server/resources/skills/marm-init/SKILL.md
[info] 46: [RP1] null: pip install without ==version installs the latest release, which could include malicious changes.
Remediation: Pin the version: pip install package==1.2.3
(MCP Rug Pull (RP1))
[warning] 47: [RP1] null: Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.
Remediation: Pin the image: image:tag or image@sha256:abc123
(MCP Rug Pull (RP1))
[warning] 137: [RP1] null: Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.
Remediation: Pin the image: image:tag or image@sha256:abc123
(MCP Rug Pull (RP1))
[warning] 7: [AS3] Skill Enumeration: Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.
Remediation: Remove all code or instructions that list or read other skills' files or directories. Skills should operate independently; cross-skill access is a privilege escalation.
(Agent Snooping (AS3))
[info] 46: [RP1] null: pip install without ==version installs the latest release, which could include malicious changes.
Remediation: Pin the version: pip install package==1.2.3
(MCP Rug Pull (RP1))
[warning] 47: [RP1] null: Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.
Remediation: Pin the image: image:tag or image@sha256:abc123
(MCP Rug Pull (RP1))
[warning] 137: [RP1] null: Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.
Remediation: Pin the image: image:tag or image@sha256:abc123
(MCP Rug Pull (RP1))
[warning] 7: [AS3] Skill Enumeration: Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.
Remediation: Remove all code or instructions that list or read other skills' files or directories. Skills should operate independently; cross-skill access is a privilege escalation.
(Agent Snooping (AS3))
[info] 46: [RP1] null: pip install without ==version installs the latest release, which could include malicious changes.
Remediation: Pin the version: pip install package==1.2.3
(MCP Rug Pull (RP1))
[warning] 47: [RP1] null: Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.
Remediation: Pin the image: image:tag or image@sha256:abc123
(MCP Rug Pull (RP1))
[warning] 137: [RP1] null: Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.
Remediation: Pin the image: image:tag or image@sha256:abc123
(MCP Rug Pull (RP1))
[warning] 7: [AS3] Skill Enumeration: Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.
Remediation: Remove all code or instructions that list or read other skills' files or directories. Skills should operate independently; cross-skill access is a privilege escalation.
(Agent Snooping (AS3))
[info] 46: [RP1] null: pip install without ==version installs the latest release, which could include malicious changes.
Remediation: Pin the version: pip install package==1.2.3
(MCP Rug Pull (RP1))
[warning] 47: [RP1] null: Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.
Remediation: Pin the image: image:tag or image@sha256:abc123
(MCP Rug Pull (RP1))
[warning] 137: [RP1] null: Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.
Remediation: Pin the image: image:tag or image@sha256:abc123
(MCP Rug Pull (RP1))
[warning] 7: [AS3] Skill Enumeration: Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.
Remediation: Remove all code or instructions that list or read other skills' files or directories. Skills should operate independently; cross-skill access is a privilege escalation.
(Agent Snooping (AS3))
skills/marm-init/SKILL.md
[info] 46: [RP1] null: pip install without ==version installs the latest release, which could include malicious changes.
Remediation: Pin the version: pip install package==1.2.3
(MCP Rug Pull (RP1))
[warning] 47: [RP1] null: Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.
Remediation: Pin the image: image:tag or image@sha256:abc123
(MCP Rug Pull (RP1))
[warning] 137: [RP1] null: Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.
Remediation: Pin the image: image:tag or image@sha256:abc123
(MCP Rug Pull (RP1))
[warning] 7: [AS3] Skill Enumeration: Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.
Remediation: Remove all code or instructions that list or read other skills' files or directories. Skills should operate independently; cross-skill access is a privilege escalation.
(Agent Snooping (AS3))
[info] 46: [RP1] null: pip install without ==version installs the latest release, which could include malicious changes.
Remediation: Pin the version: pip install package==1.2.3
(MCP Rug Pull (RP1))
[warning] 47: [RP1] null: Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.
Remediation: Pin the image: image:tag or image@sha256:abc123
(MCP Rug Pull (RP1))
[warning] 137: [RP1] null: Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.
Remediation: Pin the image: image:tag or image@sha256:abc123
(MCP Rug Pull (RP1))
[warning] 7: [AS3] Skill Enumeration: Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.
Remediation: Remove all code or instructions that list or read other skills' files or directories. Skills should operate independently; cross-skill access is a privilege escalation.
(Agent Snooping (AS3))
[info] 46: [RP1] null: pip install without ==version installs the latest release, which could include malicious changes.
Remediation: Pin the version: pip install package==1.2.3
(MCP Rug Pull (RP1))
[warning] 47: [RP1] null: Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.
Remediation: Pin the image: image:tag or image@sha256:abc123
(MCP Rug Pull (RP1))
[warning] 137: [RP1] null: Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.
Remediation: Pin the image: image:tag or image@sha256:abc123
(MCP Rug Pull (RP1))
[warning] 7: [AS3] Skill Enumeration: Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.
Remediation: Remove all code or instructions that list or read other skills' files or directories. Skills should operate independently; cross-skill access is a privilege escalation.
(Agent Snooping (AS3))
[info] 46: [RP1] null: pip install without ==version installs the latest release, which could include malicious changes.
Remediation: Pin the version: pip install package==1.2.3
(MCP Rug Pull (RP1))
[warning] 47: [RP1] null: Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.
Remediation: Pin the image: image:tag or image@sha256:abc123
(MCP Rug Pull (RP1))
[warning] 137: [RP1] null: Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.
Remediation: Pin the image: image:tag or image@sha256:abc123
(MCP Rug Pull (RP1))
[warning] 7: [AS3] Skill Enumeration: Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.
Remediation: Remove all code or instructions that list or read other skills' files or directories. Skills should operate independently; cross-skill access is a privilege escalation.
(Agent Snooping (AS3))
🔇 Additional comments (66)
marm-mcp-server/marm_mcp_server/utils/chunk_backfill.py (1)
25-25: LGTM!Also applies to: 137-137, 180-182
marm-mcp-server/marm_mcp_server/utils/embedding_migration.py (1)
6-11: LGTM!Also applies to: 31-42, 56-56, 97-105, 123-123, 190-190
marm-mcp-server/marm_mcp_server/utils/helpers.py (1)
19-19: LGTM!Also applies to: 32-32
marm-mcp-server/marm_mcp_server/utils/security.py (1)
140-153: LGTM!marm-mcp-server/marm_mcp_server/core/compaction.py (1)
6-6: LGTM!Also applies to: 186-186
marm-mcp-server/marm_mcp_server/core/concept_db.py (1)
314-338: LGTM!Also applies to: 362-362, 428-428, 504-504, 529-529
marm-mcp-server/marm_mcp_server/core/concept_extraction.py (1)
9-9: LGTM!Also applies to: 69-69, 91-91, 101-101, 113-113, 127-127
marm-mcp-server/marm_mcp_server/core/docs_db.py (1)
88-93: LGTM!Also applies to: 164-166
marm-mcp-server/marm_mcp_server/core/memory.py (1)
6-8: LGTM!Also applies to: 40-40, 79-85, 102-102, 201-209, 281-281, 290-290, 416-458, 475-478
marm-mcp-server/marm_mcp_server/core/memory_db.py (1)
7-11: LGTM!Also applies to: 20-33, 49-49, 62-69, 86-99, 468-468, 479-479, 496-496
marm-mcp-server/marm_mcp_server/core/memory_delete.py (1)
4-19: LGTM!Also applies to: 52-52, 81-81, 104-104, 141-146
marm-mcp-server/marm_mcp_server/core/compaction_scheduler.py (1)
3-4: LGTM!Also applies to: 15-21, 36-41
marm-mcp-server/marm_mcp_server/core/events.py (1)
11-22: LGTM!Also applies to: 60-62
marm-mcp-server/marm_mcp_server/core/rate_limiter.py (1)
17-17: LGTM!Also applies to: 86-86
marm-mcp-server/marm_mcp_server/core/runtime_manager.py (1)
373-375: LGTM!marm-mcp-server/marm_mcp_server/core/stdio_tool_lifecycle.py (1)
7-7: LGTM!Also applies to: 22-28
marm-mcp-server/marm_mcp_server/core/consolidation.py (1)
5-24: LGTM!Also applies to: 88-93, 109-109
marm-mcp-server/marm_mcp_server/core/memory_ops.py (1)
7-7: LGTM!Also applies to: 36-40, 151-155, 302-302, 380-380
marm-mcp-server/marm_mcp_server/core/memory_recall.py (1)
6-8: LGTM!Also applies to: 34-38, 42-47, 103-103, 145-156, 180-180, 362-367
marm-mcp-server/marm_mcp_server/core/memory_scoring.py (1)
4-18: LGTM!Also applies to: 38-40, 87-90, 152-156, 300-300
marm-mcp-server/marm_mcp_server/core/memory_utils.py (1)
11-19: LGTM!Also applies to: 197-197, 288-288
marm-mcp-server/marm_mcp_server/core/models.py (1)
156-156: LGTM!Also applies to: 182-182
marm-mcp-server/marm_mcp_server/core/response_limiter.py (1)
88-88: LGTM!Also applies to: 117-120
marm-mcp-server/marm_mcp_server/core/graph_index_lock.py (1)
39-39: LGTM!Also applies to: 48-49, 131-145, 168-172
marm-mcp-server/marm_mcp_server/core/graph_index_worker.py (1)
25-28: LGTM!Also applies to: 123-123
marm-mcp-server/marm_mcp_server/core/shutdown_manager.py (1)
16-21: LGTM!Also applies to: 35-35, 49-53
marm-mcp-server/marm_mcp_server/core/write_queue.py (1)
6-11: LGTM!Also applies to: 36-36, 69-94
CHANGELOG.md (1)
3-3: LGTM!Also applies to: 5-7, 10-23
scripts/typecheck.py (1)
30-37: LGTM!Also applies to: 55-64, 74-74, 125-130
marm-mcp-server/marm_mcp_server/resources/skills/marm-init/SKILL.md (1)
16-45: LGTM!Also applies to: 48-56, 61-70, 79-80, 89-163, 173-192
skills/marm-init/SKILL.md (1)
16-45: LGTM!Also applies to: 48-56, 61-70, 79-80, 89-163, 173-192
marm-mcp-server/marm_mcp_server/__init__.py (3)
20-21: LGTM!Also applies to: 23-29
17-22: 🎯 Functional CorrectnessAlign the release number with the published change type. If this release does not add public MCP tools/parameters/features or change behavior, do not use
2.38.0; use2.37.1from the previous2.37.0release. Apply the chosen version consistently across release metadata, includingmarm-mcp-server/pyproject.toml,marm-mcp-server/server.json,marm-mcp-server/docker-compose.yml,CHANGELOG.md, andAGENTS.md, then audit withpython scripts/find-versions.py.
17-18: 🎯 Functional CorrectnessKeep the release version consistent with
CHANGELOG.md.The changelog titles this release as
v2.38.0, and all release-critical metadata currently uses2.38.0. Changing2.38.0to2.37.1would create the very version drift this review is meant to avoid.> Likely an incorrect or invalid review comment.marm-mcp-server/marm_mcp_server/cli.py (1)
13-20: LGTM!Also applies to: 89-89
marm-mcp-server/marm_mcp_server/console/cli.py (1)
15-15: LGTM!Also applies to: 45-45, 98-98
marm-mcp-server/marm_mcp_server/services/product_workflows.py (1)
10-10: LGTM!Also applies to: 119-119
docs/INSTALL-LINUX.md (1)
316-316: LGTM!docs/INSTALL-WINDOWS.md (1)
290-290: LGTM!marm-mcp-server/Dockerfile (1)
76-76: LGTM!marm-mcp-server/docker-compose.yml (1)
8-8: LGTM!Also applies to: 21-21
marm-mcp-server/marm_mcp_server/config/settings.py (1)
162-162: LGTM!Also applies to: 181-181, 209-209
marm-mcp-server/marm_mcp_server/endpoints/concepts.py (1)
13-13: LGTM!Also applies to: 327-339, 399-399, 426-430, 515-534
marm-mcp-server/marm_mcp_server/endpoints/system.py (1)
24-24: LGTM!Also applies to: 54-54, 115-115
marm-mcp-server/marm_mcp_server/middleware/auth.py (1)
4-5: LGTM!Also applies to: 13-15
marm-mcp-server/marm_mcp_server/services/compaction_summarize.py (1)
10-10: LGTM!Also applies to: 78-78, 101-101
marm-mcp-server/marm_mcp_server/services/notebook.py (1)
5-5: LGTM!Also applies to: 46-46, 89-89, 127-127, 155-155, 167-167, 182-182, 240-240, 261-272, 281-294
marm-mcp-server/pyproject.toml (2)
101-112: LGTM!
74-77: 📐 Maintainability & Code QualityNo issue found.
The CI lint/format workflow installs and runs Ruff only, and the remaining
black,isort, andflake8references inscripts/find-versions.pyare only documentation-version-search exclusions.marm-mcp-server/marm_mcp_server/endpoints/notebook.py (1)
12-12: 🎯 Functional CorrectnessVerify the FastAPI response contract for all newly annotated endpoints.
The three
-> dictannotations can change inferred response-model validation, serialization, filtering, and documentation. The supplied snippets do not show the route decorators or the complete delegated return contract. Confirm that the intended routes useresponse_model=Nonewhere required and that all success paths return plain dictionaries. (fastapi.tiangolo.com)
marm-mcp-server/marm_mcp_server/endpoints/notebook.py#L12-L12: verify everynotebook_dispatchpath returns a dictionary.marm-mcp-server/marm_mcp_server/endpoints/session.py#L17-L17: verify themarm_startroute preserves its existing response contract.marm-mcp-server/marm_mcp_server/endpoints/session.py#L68-L68: verify themarm_refreshroute preserves its existing response contract.marm-mcp-server/marm_mcp_server/middleware/protocol_injection.py (1)
8-9: LGTM!Also applies to: 32-34, 125-127
marm-mcp-server/marm_mcp_server/middleware/rate_limiting.py (1)
4-5: LGTM!Also applies to: 44-46
marm-mcp-server/marm_mcp_server/server.py (1)
11-12: LGTM!Also applies to: 52-52, 111-111
marm-mcp-server/marm_mcp_server/services/analytics.py (1)
13-15: LGTM!marm-mcp-server/marm_mcp_server/services/automation.py (1)
7-19: LGTM!marm-mcp-server/marm_mcp_server/services/documentation.py (1)
15-15: LGTM!Also applies to: 59-59, 262-262, 278-278
marm-mcp-server/marm_mcp_server/console/app.py (1)
14-24: LGTM!Also applies to: 75-75, 97-99, 153-153, 181-181, 192-192
marm-mcp-server/marm_mcp_server/console/endpoints/concepts.py (1)
126-126: LGTM!marm-mcp-server/marm_mcp_server/endpoints/compaction.py (1)
36-36: LGTM!Also applies to: 93-95, 257-257, 310-310, 535-535
marm-mcp-server/marm_mcp_server/endpoints/logging.py (1)
17-17: LGTM!Also applies to: 34-34, 44-44
marm-mcp-server/marm_mcp_server/endpoints/memory.py (1)
22-24: LGTM!Also applies to: 215-215
marm-mcp-server/marm_mcp_server/endpoints/reasoning.py (1)
13-13: LGTM!marm-mcp-server/marm_mcp_server/server_stdio.py (1)
22-22: LGTM!Also applies to: 59-59
marm-mcp-server/marm_mcp_server/services/compaction_apply.py (1)
9-13: LGTM!marm-mcp-server/marm_mcp_server/services/recall.py (1)
29-30: LGTM!marm-mcp-server/marm_mcp_server/services/stdio_graph_tools.py (1)
17-20: LGTM!Also applies to: 368-368
| pip install -r marm-mcp-server/requirements.txt | ||
| pip install -e './marm-mcp-server' --no-deps | ||
| pip install pytest pytest-asyncio pytest-cov jsonschema requests black isort flake8 mypy ruff | ||
| pip install pytest pytest-asyncio pytest-cov jsonschema requests mypy ruff |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== workflow lines around install =="
sed -n '45,70p' .github/workflows/publish-mcp.yml 2>/dev/null || true
echo
echo "== typecheck file outline/content =="
if [ -f scripts/typecheck.py ]; then
wc -l scripts/typecheck.py
sed -n '1,120p' scripts/typecheck.py
else
fd -a 'typecheck.py' .
fi
echo
echo "== files mentioning mypy/ruff/pytest-asyncio validation baseline =="
rg -n "mypy|ruff|BASELINE|typecheck|pytest-cov|jsonschema|requests|pip install" .github scripts -S || true
echo
echo "== other tool pins in repo =="
rg -n "mypy=.*|ruff=.*|python_requires|twine|pytest-cov|jsonschema|requests|mypy|mypy-strict|ruff check" pyproject.toml setup.cfg setup.py tox.ini .github -S 2>/dev/null | head -n 200Repository: Lyellr88/marm-memory
Length of output: 10960
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== scripts/find-versions.py relevant section =="
sed -n '55,90p' scripts/find-versions.py 2>/dev/null || true
echo
echo "== requirements files mentioning validation packages =="
for f in $(git ls-files | rg '(^|/)requirements.*\.txt$|pyproject\.toml$|tox\.ini$|setup\.cfg$'); do
if rg -n "mypy|ruff|pytest|pytest-asyncio|pytest-cov|jsonschema|requests|strict" "$f" >/tmp/matches.$$; then
echo "--- $f"
cat /tmp/matches.$$
fi
done
echo
echo "== workflow exact validation steps =="
sed -n '48,66p' .github/workflows/publish-mcp.yml
sed -n '128,138p' .github/workflows/publish-mcp.ymlRepository: Lyellr88/marm-memory
Length of output: 2854
Pin scripts/typecheck.py inputs before enabling it as a release gate.
scripts/typecheck.py fails if reported errors go above BASELINE = 2 and explicitly says a pinned Mypy is not optional because the baseline is version-specific. Add an exact mypy pin and the exact validation scripts/config/versioned inputs used when creating the baseline before gating releases on this check.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/publish-mcp.yml at line 59, Update the release workflow’s
dependency installation and typecheck gate around scripts/typecheck.py to pin
mypy to the baseline’s exact version and include the exact validation scripts,
configuration, and versioned inputs used to establish BASELINE = 2. Ensure the
release check runs against those pinned inputs rather than unversioned or
drifting tooling.
| if mirror_memory_id is not None: | ||
| with docs_db.get_connection() as conn: | ||
| docs_db.set_memory_id(conn, doc_row.id, memory_id) | ||
| docs_db.set_memory_id(conn, doc_row.id, mirror_memory_id) |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Keep mirror synchronization pending when the document-ID update fails.
If docs_db.set_memory_id raises after memory.store_doc_mirror succeeds, _save propagates the exception. The docs row still contains the old or null memory_id, while the memory mirror already exists. A later save can create a duplicate mirror or clean the wrong record. Catch this failure and use a durable, idempotent reconciliation keyed by doc_id; report mirror_status as "pending" until the docs update succeeds.
As per path instructions, prioritize runtime correctness, async/concurrency safety, and SQLite transaction safety.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@marm-mcp-server/marm_mcp_server/services/notebook.py` around lines 277 - 279,
Update _save so a failure from docs_db.set_memory_id after
memory.store_doc_mirror does not leave synchronization unreconciled: catch the
update failure, persist a durable idempotent reconciliation record keyed by
doc_id, and report mirror_status as "pending". Ensure reconciliation retries
safely under concurrent saves and SQLite transactions, and only mark the mirror
synchronized after the docs row update succeeds.
Source: Path instructions
| [project] | ||
| name = "marm-mcp-server" | ||
| version = "2.37.0" | ||
| version = "2.38.0" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== files =="
git ls-files | rg '(^|/)pyproject\.toml$|(^|/)server\.json$|(^|/)README\.md$|(^|/)INSTALL-.*\.md$|scripts/find-versions\.py|marm-mcp-server/marm_mcp_server/server\.py'
echo
echo "== version occurrences =="
rg -n '"?version"?|2\.38|2\.37|2\.3[0-9]|Dockerfile|marm-mcp-server|lyellr88/marm-mcp-server|python scripts/find-versions' \
-g '!**/.git/**' \
-g '!**/*.pyc' \
-g '!**/__pycache__/**' .
echo
echo "== pyproject excerpt =="
cat -n marm-mcp-server/pyproject.toml | sed -n '1,40p'
echo
echo "== server.json excerpt =="
cat -n marm-mcp-server/server.json | sed -n '1,45p'
echo
echo "== server.py header =="
cat -n marm-mcp-server/marm_mcp_server/server.py | sed -n '1,35p'
echo
echo "== scripts/find-versions.py =="
cat -n scripts/find-versions.py | sed -n '1,220p' || trueRepository: Lyellr88/marm-memory
Length of output: 50377
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== targeted files status =="
git diff --stat -- marm-mcp-server/pyproject.toml marm-mcp-server/server.json marm-mcp-server/marm_mcp_server/server.py README.md marm-mcp-server/README.md docker-compose.yml marm-mcp-server/Dockerfile scripts/find-versions.py docs/INSTALL-*.md 2>/dev/null || true
echo
echo "== targeted versions with line numbers =="
rg -n -C 2 '("version"|version|2\.38\.0|2\.37\.0|2\.37\.1|lyellr88/marm-mcp-server|marm-mcp-server|python scripts/find-versions)' \
marm-mcp-server/pyproject.toml \
marm-mcp-server/server.json \
marm-mcp-server/marm_mcp_server/server.py \
README.md \
marm-mcp-server/README.md \
docker-compose.yml \
marm-mcp-server/Dockerfile \
scripts/find-versions.py \
docs/INSTALL-*.md \
2>/dev/null || true
echo
echo "== find-versions.py =="
cat -n scripts/find-versions.py | sed -n '1,220p' || true
echo
echo "== semver mentions =="
rg -n -i -C 2 'semver|breaking|minor|patch|feature|fix|mcp|transport' README.md docs marm-mcp-server/pyproject.toml 2>/dev/null || true
echo
echo "== inspect static asset length issue if present =="
wc -l ./marm-mcp-server/marm_mcp_server/console/static/assets/index-D10wAXCq.js 2>/dev/null || trueRepository: Lyellr88/marm-memory
Length of output: 50379
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== first changelog entry =="
python3 - <<'PY'
from pathlib import Path
text = Path("CHANGELOG.md").read_text()
lines = text.splitlines()
for i, line in enumerate(lines, 1):
if line.startswith("# ") or line.startswith("## "):
print(f"{i}: {line}")
break
PY
echo
echo "== release/type mentions in changelog head =="
sed -n '1,80p' CHANGELOG.md
echo
echo "== docker-compose version refs =="
test -f docker-compose.yml && sed -n '1,80p' docker-compose.yml || true
echo
echo "== all exact 2.38.0 refs in tracked text =="
git grep -n '"version": "2\.38\.0"\|version = "2\.38\.0"\|Version: 2\.38\.0\|2\.38\.0' -- '*.toml' '*.json' '*.py' '*.yml' '*.yaml' Dockerfile README.md docs/INSTALL-*.md scripts/find-versions.py marm-mcp-server 2>/dev/null || true
echo
echo "== git tree refs for version files =="
git ls-tree HEAD -- marm-mcp-server/pyproject.toml marm-mcp-server/server.json marm-mcp-server/marm_mcp_server/server.py README.md marm-mcp-server/README.md docker-compose.yml marm-mcp-server/Dockerfile scripts/read-versions.py docs/INSTALL-*.md | sed -n '1,120p'Repository: Lyellr88/marm-memory
Length of output: 11603
Align the release version metadata with the changelog.
CHANGELOG.md has no release entry for 2.38.0, but the tracked package, manifest, OCI, Docker, and module metadata all use 2.38.0. Use the chosen release version consistently, and ensure the changelog contains a release entry for it before release.
📍 Affects 3 files
marm-mcp-server/pyproject.toml#L7-L7(this comment)marm-mcp-server/server.json#L6-L6marm-mcp-server/server.json#L20-L25marm-mcp-server/marm_mcp_server/server.py#L8-L9
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@marm-mcp-server/pyproject.toml` at line 7, Align all release metadata with
the chosen version and add the corresponding changelog entry: update
marm-mcp-server/pyproject.toml:7, both version references in
marm-mcp-server/server.json:6 and 20-25, and
marm-mcp-server/marm_mcp_server/server.py:8-9 consistently, then add a
CHANGELOG.md release entry for that same version before release.
Sources: Coding guidelines, Learnings
| from collections import Counter | ||
|
|
||
| BASELINE = 113 | ||
| BASELINE = 2 |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== files =="
git ls-files | rg '(^|/)(scripts/typecheck.py|CHANGELOG.md)$' || true
echo "== typecheck.py =="
if [ -f scripts/typecheck.py ]; then
nl -ba scripts/typecheck.py | sed -n '1,90p'
fi
echo "== changelog excerpt =="
if [ -f CHANGELOG.md ]; then
nl -ba CHANGELOG.md | sed -n '1,25p'
fi
echo "== search related terms =="
rg -n "BASELINE|mypy|typecheck|new type error|type error" -S . --glob '!/.git/**' --glob '!node_modules/**' | head -100Repository: Lyellr88/marm-memory
Length of output: 263
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== typecheck.py =="
if [ -f scripts/typecheck.py ]; then
cat -n scripts/typecheck.py | sed -n '1,90p'
fi
echo "== changelog excerpt =="
if [ -f CHANGELOG.md ]; then
cat -n CHANGELOG.md | sed -n '1,25p'
fi
echo "== related code searches =="
rg -n "BASELINE|mypy|typecheck|typeerr|new type error|type error|exit_code|subprocess" -S . --glob '!/.git/**' --glob '!node_modules/**' | head -200 || true
echo "== parse typecheck behavior =="
python3 - <<'PY'
from pathlib import Path
p=Path("scripts/typecheck.py")
if p.exists():
text=p.read_text()
print(text)
PYRepository: Lyellr88/marm-memory
Length of output: 28811
Keep the baseline description aligned with the count-only gate. scripts/typecheck.py only rejects total > BASELINE, so a new error replacing an old one can pass unchanged. Change the gate to snapshotted or per-file baseline comparison, or update CHANGELOG.md to remove the claim that every new type error fails.
📍 Affects 2 files
scripts/typecheck.py#L28-L28(this comment)CHANGELOG.md#L8-L9
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/typecheck.py` at line 28, Align the type-error baseline behavior with
its documentation: update the gate around BASELINE in scripts/typecheck.py to
compare against a snapshot or per-file baseline so replacements are rejected, or
remove the claim that every new type error fails from CHANGELOG.md lines 8-9.
Apply the chosen correction at the corresponding site; no other changes are
required.
| - pip: run `pip install marm-mcp-server`. Confirm success, for example `marm-mcp-server --version` resolves. Record runtime = python. | ||
| - Docker: run `docker pull lyellr88/marm-mcp-server:latest`. Confirm the image is present with `docker images -q lyellr88/marm-mcp-server`. Record runtime = docker. |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Locate SKILL.md files =="
git ls-files | grep -E '(^|/)SKILL\.md$' | sed -n '1,50p'
echo
echo "== Relevant lines =="
for f in $(git ls-files | grep -E '(^|/)SKILL\.md$'); do
if grep -n -E 'pip install marm-mcp-server|docker pull|Docker image|lyellr88/marm-mcp-server' "$f" >/dev/null; then
echo "--- $f"
sed -n '36,55p' "$f" | cat -n
fi
done
echo
echo "== Release/version references nearby =="
for f in $(git ls-files | grep -E 'README\.md$|AGENTS\.md$|CHANGELOG\.md$'); do
echo "--- $f"
grep -n -E 'marm-mcp-server|pip install|docker|lyellr88|version' "$f" | sed -n '1,80p' || true
doneRepository: Lyellr88/marm-memory
Length of output: 36446
🌐 Web query:
Docker latest tag mutable image digest best practice package latest pip install mutable artifact security
💡 Result:
Using the latest tag and mutable image tags in production is a significant security and operational risk; the industry best practice is to pin container images by their unique, immutable digest (e.g., image@sha256:...) [1][2][3][4]. Why latest and mutable tags are unsafe: 1. Lack of Determinism: The latest tag is a moving label that points to whatever image was most recently pushed [5][2][6]. This causes non-deterministic behavior, where two deployments of the same configuration might pull different images [7][6]. 2. Security Vulnerabilities (TOCTOU): Using mutable tags exposes your environment to Time-of-Check vs. Time-of-Use (TOCTOU) attacks [4][8]. An image can be scanned and validated as secure, but replaced in the registry by a malicious image with the same tag before it is deployed [4][9]. 3. Broken Reproducibility: If an issue occurs, you cannot reliably roll back to a known-good state because the tag no longer points to the same bytes it did during the original deployment [2][6]. 4. Operational Risks: Unexpected updates can occur during pod restarts if your orchestrator (like Kubernetes) is configured to pull images, leading to mysterious production failures that are difficult to debug [2][6]. Best Practices: - Pin by Digest: Always use the immutable SHA-256 digest in your deployment manifests or configuration files [1][3][4]. This ensures that every deployment is byte-for-byte identical to the version you tested and validated [7][9]. - Enforce Tag Immutability: If your registry supports it (e.g., AWS ECR's imageTagMutability, GCP Artifact Registry's immutable tags), enable it to prevent existing tags from being overwritten [2][3][6]. - Automate Updates: Since pinning by digest prevents automatic updates, use automation tools (such as Renovate or Dependabot) to monitor for new base images and automatically open pull requests to update the pinned digests in your manifests [7][9]. - Separate Build from Deploy: CI pipelines should build an image, generate its unique digest, and then inject that specific digest into the deployment process, rather than relying on mutable tag names [3][9]. Regarding pip install latest: The risks are similar. Installing the "latest" version of a software package without pinning a version (e.g., via a requirements.txt or lockfile with hashes) is a supply chain security risk. It makes your builds non-reproducible and potentially vulnerable to malicious code injection if an upstream package is compromised or updated unexpectedly. Always use lockfiles that include specific versions and cryptographic hashes (e.g., pip-compile with hashes) to ensure the artifact you install is the exact one you verified. Top Results: [1], [2], [7], [3], [4], [9]
Citations:
- 1: https://docs.docker.com/dhi/explore/security-concepts/digests/
- 2: https://devop.sh/blog/stop-shipping-latest-tag-kubernetes/
- 3: https://cr0x.net/en/docker-image-tag-rule/
- 4: https://www.sysdig.com/blog/toctou-tag-mutability
- 5: https://www.docker.com/blog/docker-best-practices-using-tags-and-labels-to-manage-docker-image-sprawl/
- 6: https://podostack.com/p/docker-image-tagging-strategies
- 7: https://safeguard.sh/resources/blog/container-image-digests-vs-tags-why-pinning-matters
- 8: https://webflow.sysdig.com/blog/toctou-tag-mutability
- 9: https://safeguard.sh/resources/blog/how-image-digest-pinning-strengthens-container-supply-chain-integrity-in-snyk-workflows
Pin both installer artifacts to immutable releases.
skills/marm-init/SKILL.md#L46-L55andmarm-mcp-server/marm_mcp_server/resources/skills/marm-init/SKILL.md#L46-L55both usepip install marm-mcp-serverandlyellr88/marm-mcp-server:latest. Replace these in both copies with a fixed package version and a fixed Docker tag or digest.
🧰 Tools
🪛 SkillSpector (2.5.1)
[info] 46: [RP1] null: pip install without ==version installs the latest release, which could include malicious changes.
Remediation: Pin the version: pip install package==1.2.3
(MCP Rug Pull (RP1))
[warning] 47: [RP1] null: Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.
Remediation: Pin the image: image:tag or image@sha256:abc123
(MCP Rug Pull (RP1))
[warning] 137: [RP1] null: Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.
Remediation: Pin the image: image:tag or image@sha256:abc123
(MCP Rug Pull (RP1))
[warning] 7: [AS3] Skill Enumeration: Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.
Remediation: Remove all code or instructions that list or read other skills' files or directories. Skills should operate independently; cross-skill access is a privilege escalation.
(Agent Snooping (AS3))
📍 Affects 2 files
skills/marm-init/SKILL.md#L46-L47(this comment)marm-mcp-server/marm_mcp_server/resources/skills/marm-init/SKILL.md#L46-L47
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@skills/marm-init/SKILL.md` around lines 46 - 47, Pin both installer artifacts
to immutable releases in skills/marm-init/SKILL.md lines 46-47 and
marm-mcp-server/marm_mcp_server/resources/skills/marm-init/SKILL.md lines 46-47:
replace the unversioned pip package with a fixed marm-mcp-server version and
replace the Docker image’s latest tag with a fixed release tag or digest,
keeping both copies consistent.
Source: Linters/SAST tools
| 1. Read the full MARM protocol from source: `https://raw.githubusercontent.com/Lyellr88/marm-memory/MARM-main/docs/PROTOCOL.md` If the network read fails, fall back in this order: | ||
| - local repo `docs/PROTOCOL.md` | ||
| - packaged copy `marm-mcp-server/marm_mcp_server/resources/marm-docs/PROTOCOL.md` | ||
| 2. Freshness check: read the `version:` field in this file's frontmatter and compare it against the `version:` in the source copy at `metadata.source`. If the source version is higher, tell the user once: "Your MARM init skill is out of date. Re-run `marm-memory init` to refresh it." Then continue with the version you have. |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf 'Files matching marm-init SKILL.md:\n'
git ls-files | rg '(^|/)marm-init/SKILL\.md$|marm-mcp-server/.*marm-init/SKILL\.md$'
printf '\nRelevant SKILL.md snippets:\n'
for f in $(git ls-files | rg '(^|/)marm-init/SKILL\.md$|marm-mcp-server/.*marm-init/SKILL\.md$'); do
echo "--- $f"
cat -n "$f" | sed -n '1,90p'
done
printf '\nSearch for protocol source usages/init behavior:\n'
rg -n "marm-memory|MARM-main|PROTOCOL|metadata\.source|version:" -S . || true
printf '\nGit diff stat/name-status if available:\n'
git diff --stat || true
git diff --name-status || trueRepository: Lyellr88/marm-memory
Length of output: 50377
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf 'Find exact SKILL.md files:\n'
git ls-files | rg '(^skills/marm-init/SKILL\.md$|^marm-mcp-server/.*marm-init/SKILL\.md$)' || true
printf '\nSkips using fd with lowercase match (if available):\n'
fd -a 'SKILL\.md$' . 2>/dev/null | rg 'marm-init|skills/marm-init' || true
printf '\nFocused rg for URLs:\n'
rg -n "Lyellr88/marm-memory/MARM-main/docs/PROTOCOL|/docs/PROTOCOL\.md$|metadata\.source|version:" -S --glob '!**/node_modules/**' --glob '!**/.git/**' .
printf '\nInspect likely installer/workflow files if any:\n'
rg -n "init|marm-init|SKILL|metadata\.source|PROTOCOL" -S marm-mcp-server/scripts marm-mcp-server tests --glob '!**/node_modules/**' || trueRepository: Lyellr88/marm-memory
Length of output: 50377
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf 'Git tracked files by direct name matches:\n'
for f in 'skills/marm-init/SKILL.md' 'marm-mcp-server/marm_mcp_server/resources/skills/marm-init/SKILL.md'; do
if git ls-files --error-unmatch "$f" >/dev/null 2>&1; then
echo "tracked $f"
else
echo "missing $f"
fi
done
printf '\nAll tracked files named SKILL.md:\n'
git ls-files '*SKILL.md' | sed -n '1,80p'
printf '\nAll tracked files in marm-init paths:\n'
git ls-files '*marm-init*' | sed -n '1,120p'
printf '\nFocused rg to tracked Python/config/test files only:\n'
git ls-files | rg '\.(py|md|yaml|yml|toml)$|/tests/' | rg 'skill|marm-init|protocol|marm|init' | while IFS= read -r f; do
rg -n "Lyellr88/marm-memory/MARM-main/docs/PROTOCOL|marm-mcp-server/marm_mcp_server/resources/skills/marm-init|version:|metadata\.source|PROTOCOL\.md" "$f" \
&& printf '\n--- %s\n' "$f" \
|| true
done
printf '\nDiff stat and changed markdown files only:\n'
git diff --stat
git diff --name-only | rg '\.md$|marm-init|skills|marm_mcp_server' || trueRepository: Lyellr88/marm-memory
Length of output: 6189
Validate the protocol source before running the fetch path.
Both skills/marm-init/SKILL.md and the packaged marm-mcp-server/marm_mcp_server/resources/skills/marm-init/SKILL.md direct fetches from https://raw.githubusercontent.com/Lyellr88/marm-memory/MARM-main/docs/PROTOCOL.md. Add an immutability check, such as checksum or pinned commit verification, before executing that protocol content or using fetch fallbacks.
🧰 Tools
🪛 SkillSpector (2.5.1)
[info] 46: [RP1] null: pip install without ==version installs the latest release, which could include malicious changes.
Remediation: Pin the version: pip install package==1.2.3
(MCP Rug Pull (RP1))
[warning] 47: [RP1] null: Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.
Remediation: Pin the image: image:tag or image@sha256:abc123
(MCP Rug Pull (RP1))
[warning] 137: [RP1] null: Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.
Remediation: Pin the image: image:tag or image@sha256:abc123
(MCP Rug Pull (RP1))
[warning] 7: [AS3] Skill Enumeration: Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.
Remediation: Remove all code or instructions that list or read other skills' files or directories. Skills should operate independently; cross-skill access is a privilege escalation.
(Agent Snooping (AS3))
📍 Affects 2 files
skills/marm-init/SKILL.md#L57-L60(this comment)marm-mcp-server/marm_mcp_server/resources/skills/marm-init/SKILL.md#L57-L60
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@skills/marm-init/SKILL.md` around lines 57 - 60, The protocol fetch path in
skills/marm-init/SKILL.md lines 57-60 and
marm-mcp-server/marm_mcp_server/resources/skills/marm-init/SKILL.md lines 57-60
must validate the remote source before using its content or fallbacks. Add a
checksum or pinned-commit verification for the PROTOCOL.md source, and only
execute or continue with fetched content when validation succeeds; apply the
same change to both copies.
A doc save commits the docs row, then links it to a memories mirror in a second write. A failure in that second write propagated out of _save, so a save that had already durably succeeded reported an error and left the mirror row unlinked. The next save then passed existing_memory_id=None and created a second mirror, once per save. The link failure is now reported as mirror_status="pending" on a successful save, matching the existing behavior for a failed mirror write. _store_doc_mirror resolves a doc's existing mirror by metadata.doc_id when it has no usable id, inside its own transaction, so the write is idempotent per doc and the pending status is a promise it can keep. Two tests drive the real failure through notebook_dispatch against SQLite. The repair test was confirmed to fail without the doc_id resolution. Also in this commit: - Reorder four unions in consolidation.py so None comes last. Ruff 0.16.2 promoted RUF036 out of preview and failed CI on them; 0.15.16 reported the file clean, so a local pass did not predict CI. - Pin ruff==0.16.2 in CI so a ruff release cannot fail an unchanged PR. - Correct the changelog's typecheck claim to name the count-based mechanism rather than implying every new type error is caught.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@marm-mcp-server/marm_mcp_server/core/memory_ops.py`:
- Around line 426-437: Update the orphan-repair logic around existing_memory_id
to fetch all matching doc rows for metadata["doc_id"], retain one canonical row,
and remove or retire surplus rows using the existing chunk and graph cleanup
path. Ensure repair leaves recall with a single document mirror, and add a
regression test covering two orphaned rows with the same document ID.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 332ef027-5c8e-414c-b9fa-a75fef6d73ba
📒 Files selected for processing (6)
.github/workflows/ruff.ymlCHANGELOG.mdmarm-mcp-server/marm_mcp_server/core/consolidation.pymarm-mcp-server/marm_mcp_server/core/memory_ops.pymarm-mcp-server/marm_mcp_server/services/notebook.pymarm-mcp-server/tests/test_notebook_service.py
🚧 Files skipped from review as they are similar to previous changes (3)
- CHANGELOG.md
- marm-mcp-server/marm_mcp_server/core/consolidation.py
- marm-mcp-server/marm_mcp_server/services/notebook.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{py,md,json,yml,yaml,toml,Dockerfile}
📄 CodeRabbit inference engine (AGENTS.md)
Keep changes surgical: modify only what the task requires, match existing style, and preserve behavior during refactors.
Files:
marm-mcp-server/tests/test_notebook_service.pymarm-mcp-server/marm_mcp_server/core/memory_ops.py
marm-mcp-server/tests/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
marm-mcp-server/tests/**/*.py: Run tests with pytest frommarm-mcp-server/; exercise real FastAPI endpoints and real SQLite, mocking only when it meaningfully accelerates tests and matches behavior with at least 95% fidelity.
Every new MARM Console API route needs at least one happy-path FastAPI response-contract test with the MCP adapter stubbed.
Do not write existence-check or coded-to-pass tests; prefer deep real-path coverage, and usepytest.mark.skiponly for genuinely unavailable dependencies.
Files:
marm-mcp-server/tests/test_notebook_service.py
**/tests/**
⚙️ CodeRabbit configuration file
**/tests/**: Focus on tests that are flaky, non-isolated, incorrectly asserting behavior, or missing coverage for a changed high-risk path. Skip minor naming, comments, and layout preferences.
Files:
marm-mcp-server/tests/test_notebook_service.py
**/*.py
⚙️ CodeRabbit configuration file
**/*.py: Prioritize runtime correctness, async/concurrency safety, SQLite transaction safety, auth/rate-limit behavior, release-breaking packaging issues, and MCP protocol compatibility.
Files:
marm-mcp-server/tests/test_notebook_service.pymarm-mcp-server/marm_mcp_server/core/memory_ops.py
marm-mcp-server/marm_mcp_server/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
marm-mcp-server/marm_mcp_server/**/*.py: HTTP and STDIO transports must remain in exact behavioral parity; never fork behavior between transports.
All memory writes must use the serialized asynchronous write queue; do not add bypass paths.
marm_log_entrymust dual-write alog_entriesrow and semantic memory, while semantic-store failure must never fail the log write.
Never share database connections or pools between the memory database and the concept-graph database.
Every code-index call anddelete_projectmust use the graph gate; release must be driven by engine-call completion rather than the awaiting task.
Background indexing must never block writes, recall, or startup; graph and concept failures must not break the seven core memory tools.
marm_smart_recallmust keep primary memory ranking authoritative; graph enrichment is bounded, read-only, fail-open, and trimmed before primary results when enforcing response limits.
Use one lazy-loaded, lock-serialized fastembedjinaai/jina-embeddings-v2-small-enencoder with 512 dimensions; writes must succeed if the encoder is unavailable.
New tools must be implemented inendpoints/, routed and whitelisted for HTTP, wrapped or serviced for STDIO, and added to every consistency-list artifact.
Prefer the smallest solution; avoid speculative abstractions and unrequested configuration flags. Keep orchestration in its current owner and extract modules only at real boundaries.
Use minimal comments only for non-obvious reasons; do not add comments that narrate the next line.
Files:
marm-mcp-server/marm_mcp_server/core/memory_ops.py
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: Lyellr88/marm-memory
Timestamp: 2026-08-10T11:40:37.646Z
Learning: Never commit changes without an explicit user request.
Learnt from: CR
Repo: Lyellr88/marm-memory
Timestamp: 2026-08-10T11:40:37.646Z
Learning: Use semantic versioning: MAJOR for breaking changes, MINOR for new tools, parameters, or features, and PATCH for fixes and documentation updates.
🔇 Additional comments (1)
.github/workflows/ruff.yml (1)
27-32: LGTM!
| if not existing_memory_id and metadata.get("doc_id") is not None: | ||
| orphan = conn.execute( | ||
| """ | ||
| SELECT id FROM memories | ||
| WHERE context_type = 'doc' | ||
| AND json_extract(metadata, '$.doc_id') = ? | ||
| ORDER BY timestamp LIMIT 1 | ||
| """, | ||
| (metadata["doc_id"],), | ||
| ).fetchone() | ||
| if orphan is not None: | ||
| existing_memory_id = orphan[0] |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Repair pre-existing duplicate document mirrors.
If earlier failed retries created multiple doc rows for one metadata.doc_id, this query updates only one row and leaves the other stale mirrors intact. Recall can still return duplicate document content after the link repair.
Resolve all matching rows during repair. Keep one row. Remove or retire surplus rows through the existing chunk and graph cleanup path. Add a regression test that starts with two orphaned rows for the same document.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@marm-mcp-server/marm_mcp_server/core/memory_ops.py` around lines 426 - 437,
Update the orphan-repair logic around existing_memory_id to fetch all matching
doc rows for metadata["doc_id"], retain one canonical row, and remove or retire
surplus rows using the existing chunk and graph cleanup path. Ensure repair
leaves recall with a single document mirror, and add a regression test covering
two orphaned rows with the same document ID.
v2.38.0 strengthens MARM’s internal reliability without changing its MCP tools, parameters, stored data, or HTTP/STDIO behavior.
Mypy now checks all 110 server modules, with a strict baseline that prevents new type errors from landing unnoticed.
Core contracts were tightened across memory storage, recall, embeddings, compaction, queues, graph coordination, FastAPI paths, and CLI services.
The encoder now accurately distinguishes single-text and batch embedding results, while migration and rechunking continue to support injected test encoders.
Ruff is now the single formatter/linter used locally and in CI; conflicting Black, isort, and Flake8 dependencies were removed.
Full validation passed: 1,078 tests, server.json validation, Mypy gate, and v2.38.0 wheel/sdist build.
Two known graph-shutdown race findings remain deliberately visible in the Mypy baseline and are documented for a dedicated lifecycle fix rather than suppressed in this type-safety release.
Summary by CodeRabbit
New Features
Documentation
Chores