Release/v2.26.0 - #107
Conversation
Add the marm-memory lifecycle CLI, bundle the Console into the main package, and align runtime, documentation, and CI workflows around the managed local host.
📝 WalkthroughWalkthroughThe PR introduces the ChangesManaged runtime and bundled Console
Estimated code review effort: 5 (Critical) | ~120 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.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 78f87eaf79
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| <details> | ||
| <summary><strong>Unreleased: Notebook Scratch Pad, Permanent Docs Store, and Chunking Rework (v2.25.0)</strong></summary> | ||
| <summary><strong>July 21st, 2026: Managed Runtime CLI and Bundled Console (v2.26.0)</strong></summary> |
There was a problem hiding this comment.
Bump all release metadata to v2.26.0
This changelog advertises a v2.26.0 release, but the package/runtime metadata is still 2.25.0; python scripts/find-versions.py reports pyproject.toml, server.json, __init__.py, settings.py, server.py, Docker metadata, README, and install docs still at 2.25.0. A release from this commit will either publish the old package version or fail because that version already exists, and the new CLI will report the wrong version, so update the full version set before tagging.
AGENTS.md reference: AGENTS.md:L39-L47
Useful? React with 👍 / 👎.
| if args.command == "key": | ||
| print(generate_api_key()) |
There was a problem hiding this comment.
Bypass auto-key generation for product key commands
When SERVER_HOST=0.0.0.0 and no MARM_API_KEY is set, importing settings auto-generates and saves a key unless the legacy --generate-key flag is present in sys.argv; this new marm-memory key generate path does not hit that guard, so the command can create ~/.marm/.env and print the auto-generated-key notice before printing a separate generated key. Please make the product key-generation command part of the bypass or delay settings import so a read-only key-generation command does not mutate the runtime key.
Useful? React with 👍 / 👎.
| process = subprocess.Popen( | ||
| [sys.executable, "-m", "marm_mcp_server.console.cli", "--serve"], |
There was a problem hiding this comment.
Propagate generated API keys to Console
For the default background marm-memory console launch, if the managed runtime is bound to 0.0.0.0 with no explicit MARM_API_KEY, settings auto-generates/loads the key into the runtime process but this Console subprocess only inherits os.environ; console/mcp_client.py sends Authorization only from os.environ, while MARM auth requires a bearer token on every non-public route once a key exists. In that environment the bundled Console starts but its MCP-backed API calls get 401s, so pass the generated key through or have the Console client read the same settings key.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 13
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
README.md (1)
73-73: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winRemove stale legacy profile flags from the deployment guidance.
The deployment summaries still advertise
--swarm,--swarm-max, and--trusted, while the current managed CLI guidance usesmarm-memory start --profile .... Align every mirror so users do not copy an obsolete or inconsistent invocation:
README.md#L73-L73: replace the legacy flags with--profile swarm,--profile swarm-max, and--profile trusted.marm-mcp-server/README.md#L75-L75: apply the same profile syntax.marm-mcp-server/marm-docs/README.md#L39-L39: apply the same profile syntax.🤖 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 `@README.md` at line 73, Update the deployment summary entries in README.md (lines 73-73), marm-mcp-server/README.md (lines 75-75), and marm-mcp-server/marm-docs/README.md (lines 39-39) to replace --swarm, --swarm-max, and --trusted with --profile swarm, --profile swarm-max, and --profile trusted, keeping all three mirrors consistent.
🧹 Nitpick comments (1)
marm-mcp-server/marm_mcp_server/console/memory_store.py (1)
34-67: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winFull
entitiestable scan on every memory list/get call.Unlike the
relationshipscount above it (which pushes thememory_idsset into SQL viajson_each), the second loop pulls every row ofentities.source_memory_idsinto Python and does the intersection there. This runs on everylist_memories/get_memorycall and scales linearly with total entity count regardless of how many memory ids were requested. Consider mirroring the SQL-sidejson_eachapproach used forrelationshipsto avoid loading the whole table.🤖 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/console/memory_store.py` around lines 34 - 67, Optimize _concept_link_counts by replacing the full entities.source_memory_ids scan with a SQL-side json_each query filtered to the requested memory_ids, mirroring the existing relationships query. Aggregate matching source memory IDs directly in SQLite and add those counts to counts, while preserving malformed JSON and sqlite error handling.
🤖 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 `@docs/TECHNICAL-OVERVIEW.md`:
- Line 215: Update the embedding migration instruction in the technical overview
to use the currently registered `marm-memory maintenance embeddings migrate`
command instead of the obsolete `marm-mcp-server --migrate-embeddings`
invocation, while preserving the stopped-process requirement and mixed-dimension
behavior.
- Line 3: Synchronize all release metadata to v2.26.0: update
docs/TECHNICAL-OVERVIEW.md:3, docs/INSTALL-LINUX.md:5,
docs/INSTALL-WINDOWS.md:5, marm-mcp-server/README.md:1, and
marm-mcp-server/marm-docs/README.md:1, then run python scripts/find-versions.py
to verify no stale version sources remain.
- Around line 283-285: Update the MARM Console section to describe `marm-memory
console` as the bundled packaged launch path, replacing language that
characterizes Console as only a separate development application or still being
packaged. Retain the distinction that contributors can run the separate
FastAPI/React/Vite development servers during active development.
In `@marm-mcp-server/marm_mcp_server/console/app.py`:
- Around line 61-66: Update the FastAPI app initialization around `app` to add
app-wide bearer-token authentication for every non-health route, using a
per-runtime token and allowing the health endpoint unauthenticated. Add
`TrustedHostMiddleware` configured from the console host settings so requests
with untrusted Host headers are rejected, while preserving the existing lifespan
and app metadata.
In `@marm-mcp-server/marm_mcp_server/console/cli.py`:
- Around line 39-48: Update _serve() so start_log_maintenance does not target
runtime_dir() / "console.log", which is actively streamed by run_console().
Disable maintenance for the active console log or use a separate rotated target,
while preserving the existing uvicorn startup behavior.
In `@marm-mcp-server/marm_mcp_server/console/concept_store.py`:
- Around line 61-101: The read paths including summary, search, neighborhood,
get_entity, build_runs, get_build_run, duplicates, and graph_overview must close
SQLite handles deterministically. Import and apply contextlib.closing around
each _connect result, while retaining the existing transaction context so
connections are closed after each operation rather than relying on garbage
collection.
In `@marm-mcp-server/marm_mcp_server/console/endpoints/concepts.py`:
- Around line 154-168: Update _run_concept_build to catch
mcp_client.McpRequestError alongside mcp_client.McpUnavailable and handle both
through the existing launch failure-update path. Preserve the current immediate
error status, mcp_unavailable error code behavior unless an established
request-error code is available, and ensure neither MCP exception escapes the
background thread without updating the job record.
In `@marm-mcp-server/marm_mcp_server/console/memory_store.py`:
- Around line 152-176: Parenthesize the OR expression in the compaction_role ==
"none" branch of list_memories so it remains grouped when combined with the
other clauses via AND. Preserve the existing filtering semantics for NULL or
"none" roles and ensure both result rows and total counts use the corrected
condition.
- Around line 15-67: The SQLite connections used by _connect callers and
_concept_link_counts must be explicitly closed rather than relying on the
connection context manager. Wrap each _connect(db_path) usage and the ad-hoc
sqlite3.connect(db_path) in contextlib.closing while preserving existing
commit/rollback behavior and error handling.
In `@marm-mcp-server/marm_mcp_server/console/models.py`:
- Around line 40-43: Update ProjectDeletePayload.confirm to require the same
explicit typed confirmation literal used by the other delete payloads, removing
the boolean default; then update the downstream delete_project/internal
projects-delete contract to accept and validate that string confirmation value
end-to-end.
In `@marm-mcp-server/marm_mcp_server/core/graph_supervisor.py`:
- Around line 92-103: Replace the `_lock.locked()`-based `"starting"`
determination in the graph status method with an explicit lifecycle state or a
synchronized snapshot. Ensure `state`, `_client`, and `_available` are read
consistently under the existing synchronization strategy so shutdown cannot be
reported as starting and contradictory `started`/`available` values cannot be
returned.
In `@marm-mcp-server/pyproject.toml`:
- Line 8: Update every release-version declaration in pyproject.toml,
marm_mcp_server.__init__, config.settings, and server.py from 2.25.0 to 2.26.0,
then run python scripts/find-versions.py to verify no stale version remains.
In `@marm-mcp-server/tests/test_http_rate_limit.py`:
- Around line 29-34: Strengthen the shutdown test around the runtime status and
shutdown requests by asserting the shutdown response content and performing a
follow-up status check that confirms the write queue/runtime is stopped. Ensure
the shutdown path does not leave persistent global state in shared runtime or
rate-limiter singletons that could affect later tests.
---
Outside diff comments:
In `@README.md`:
- Line 73: Update the deployment summary entries in README.md (lines 73-73),
marm-mcp-server/README.md (lines 75-75), and marm-mcp-server/marm-docs/README.md
(lines 39-39) to replace --swarm, --swarm-max, and --trusted with --profile
swarm, --profile swarm-max, and --profile trusted, keeping all three mirrors
consistent.
---
Nitpick comments:
In `@marm-mcp-server/marm_mcp_server/console/memory_store.py`:
- Around line 34-67: Optimize _concept_link_counts by replacing the full
entities.source_memory_ids scan with a SQL-side json_each query filtered to the
requested memory_ids, mirroring the existing relationships query. Aggregate
matching source memory IDs directly in SQLite and add those counts to counts,
while preserving malformed JSON and sqlite error handling.
🪄 Autofix (Beta)
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
Run ID: 5592b44b-fb5c-4d45-a10d-fad1adc200a2
⛔ Files ignored due to path filters (1)
marm-mcp-server/marm_mcp_server/console/static/favicon.svgis excluded by!**/*.svg
📒 Files selected for processing (64)
.github/dependabot.yml.github/workflows/publish-mcp.ymlCHANGELOG.mdCONTRIBUTING.mdREADME.mddocs-site/app.jsdocs/FAQ.mddocs/INSTALL-LINUX.mddocs/INSTALL-WINDOWS.mddocs/TECHNICAL-OVERVIEW.mdmarm-console/README.mdmarm-console/artifacts/marm-console/src/components/knowledge/GraphViz.tsxmarm-console/run-dev.ps1marm-console/server/README.mdmarm-console/server/__main__.pymarm-console/server/requirements.txtmarm-console/tests/conftest.pymarm-console/tests/test_concept_build_concurrency.pymarm-console/tests/test_concept_store.pymarm-console/tests/test_memory_dashboard_gap_routes.pymarm-console/tests/test_memory_mutation_routes.pymarm-console/tests/test_overview_health.pymarm-console/tests/test_project_routes.pymarm-mcp-server/README.mdmarm-mcp-server/marm-docs/README.mdmarm-mcp-server/marm_mcp_server/cli.pymarm-mcp-server/marm_mcp_server/console/__init__.pymarm-mcp-server/marm_mcp_server/console/__main__.pymarm-mcp-server/marm_mcp_server/console/app.pymarm-mcp-server/marm_mcp_server/console/cli.pymarm-mcp-server/marm_mcp_server/console/concept_store.pymarm-mcp-server/marm_mcp_server/console/core.pymarm-mcp-server/marm_mcp_server/console/endpoints/__init__.pymarm-mcp-server/marm_mcp_server/console/endpoints/compaction.pymarm-mcp-server/marm_mcp_server/console/endpoints/concepts.pymarm-mcp-server/marm_mcp_server/console/endpoints/logs.pymarm-mcp-server/marm_mcp_server/console/endpoints/memory.pymarm-mcp-server/marm_mcp_server/console/endpoints/notebook.pymarm-mcp-server/marm_mcp_server/console/endpoints/overview.pymarm-mcp-server/marm_mcp_server/console/endpoints/projects.pymarm-mcp-server/marm_mcp_server/console/endpoints/sessions.pymarm-mcp-server/marm_mcp_server/console/mcp_client.pymarm-mcp-server/marm_mcp_server/console/memory_store.pymarm-mcp-server/marm_mcp_server/console/models.pymarm-mcp-server/marm_mcp_server/console/static/assets/index-CPMGdUC9.jsmarm-mcp-server/marm_mcp_server/console/static/assets/index-Q5uE8oOU.cssmarm-mcp-server/marm_mcp_server/console/static/index.htmlmarm-mcp-server/marm_mcp_server/console/static/robots.txtmarm-mcp-server/marm_mcp_server/core/graph_supervisor.pymarm-mcp-server/marm_mcp_server/core/runtime_manager.pymarm-mcp-server/marm_mcp_server/core/shutdown_manager.pymarm-mcp-server/marm_mcp_server/endpoints/system.pymarm-mcp-server/marm_mcp_server/middleware/rate_limiting.pymarm-mcp-server/marm_mcp_server/server.pymarm-mcp-server/marm_mcp_server/services/knowledge_setup.pymarm-mcp-server/marm_mcp_server/services/runtime_status.pymarm-mcp-server/marm_mcp_server/utils/dependency_check.pymarm-mcp-server/pyproject.tomlmarm-mcp-server/tests/test_bundled_console.pymarm-mcp-server/tests/test_http_rate_limit.pymarm-mcp-server/tests/test_knowledge_setup.pymarm-mcp-server/tests/test_runtime_cli.pymarm-mcp-server/tests/test_runtime_status.pyscripts/check-file-length.py
💤 Files with no reviewable changes (6)
- marm-console/server/README.md
- scripts/check-file-length.py
- CONTRIBUTING.md
- marm-console/server/main.py
- marm-console/server/requirements.txt
- docs-site/app.js
There was a problem hiding this comment.
Caution
Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.
🛑 Comments failed to post (13)
docs/TECHNICAL-OVERVIEW.md (3)
3-3: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Synchronize all release version metadata to v2.26.0.
CHANGELOG.mddeclares v2.26.0, but these release-facing documents still advertise v2.25.0:
docs/TECHNICAL-OVERVIEW.md#L3-L3: change the implementation version to v2.26.0.docs/INSTALL-LINUX.md#L5-L5: change the installation-guide version to v2.26.0.docs/INSTALL-WINDOWS.md#L5-L5: change the installation-guide version to v2.26.0.marm-mcp-server/README.md#L1-L1: update the package README version.marm-mcp-server/marm-docs/README.md#L1-L1: regenerate/update the documentation mirror version.As per coding guidelines, version bumps must update every enumerated version source and run
python scripts/find-versions.py.📍 Affects 5 files
docs/TECHNICAL-OVERVIEW.md#L3-L3(this comment)docs/INSTALL-LINUX.md#L5-L5docs/INSTALL-WINDOWS.md#L5-L5marm-mcp-server/README.md#L1-L1marm-mcp-server/marm-docs/README.md#L1-L1🤖 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 `@docs/TECHNICAL-OVERVIEW.md` at line 3, Synchronize all release metadata to v2.26.0: update docs/TECHNICAL-OVERVIEW.md:3, docs/INSTALL-LINUX.md:5, docs/INSTALL-WINDOWS.md:5, marm-mcp-server/README.md:1, and marm-mcp-server/marm-docs/README.md:1, then run python scripts/find-versions.py to verify no stale version sources remain.Source: Coding guidelines
215-215: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Update the embedding migration command.
This still documents
marm-mcp-server --migrate-embeddings, whilemarm-mcp-server/marm_mcp_server/cli.py:191-205registersmarm-memory maintenance embeddings migrate. Users following this overview can invoke the obsolete workflow.🤖 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 `@docs/TECHNICAL-OVERVIEW.md` at line 215, Update the embedding migration instruction in the technical overview to use the currently registered `marm-memory maintenance embeddings migrate` command instead of the obsolete `marm-mcp-server --migrate-embeddings` invocation, while preserving the stopped-process requirement and mixed-dimension behavior.
283-285: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Describe the bundled Console architecture.
The overview says Console is a separate development application and is “still being packaged,” contradicting
marm-console/README.md:22-28and the v2.26.0 bundled-Console release objective. Update this section to documentmarm-memory consoleas the packaged launch path while retaining the separate contributor dev server distinction.Also applies to: 305-316
🤖 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 `@docs/TECHNICAL-OVERVIEW.md` around lines 283 - 285, Update the MARM Console section to describe `marm-memory console` as the bundled packaged launch path, replacing language that characterizes Console as only a separate development application or still being packaged. Retain the distinction that contributors can run the separate FastAPI/React/Vite development servers during active development.marm-mcp-server/marm_mcp_server/console/app.py (1)
61-66: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash set -euo pipefail # Inspect the console app and nearby auth/middleware setup git ls-files marm-mcp-server/marm_mcp_server/console echo '--- app.py ---' nl -ba marm-mcp-server/marm_mcp_server/console/app.py | sed -n '1,220p' echo '--- search for auth / trusted host / cors in console package ---' rg -n "TrustedHostMiddleware|CORSMiddleware|Authentication|Bearer|token|Host header|host header|Depends\(|APIKey|OAuth|middleware" marm-mcp-server/marm_mcp_server/console marm-mcp-server/marm_mcp_server -g '!**/__pycache__/**'Repository: Lyellr88/marm-memory
Length of output: 1550
🏁 Script executed:
#!/bin/bash set -euo pipefail # Map the console package structure to find where routes are registered ast-grep outline marm-mcp-server/marm_mcp_server/console --view expandedRepository: Lyellr88/marm-memory
Length of output: 8971
🏁 Script executed:
#!/bin/bash set -euo pipefail # Check whether the console exposes mutation endpoints and how they are mounted rg -n "include_router|APIRouter|`@router`\.(get|post|put|patch|delete)|`@app`\.(get|post|put|patch|delete)" marm-mcp-server/marm_mcp_server/console marm-mcp-server/marm_mcp_server -g '!**/__pycache__/**'Repository: Lyellr88/marm-memory
Length of output: 19788
🏁 Script executed:
#!/bin/bash set -euo pipefail # Read the console entrypoint and route modules if they exist fd -a -t f 'app.py|*.py' marm-mcp-server/marm_mcp_server/console marm-mcp-server/marm_mcp_server | sed -n '1,200p'Repository: Lyellr88/marm-memory
Length of output: 456
🏁 Script executed:
#!/bin/bash set -euo pipefail nl -ba marm-mcp-server/marm_mcp_server/console/app.py | sed -n '1,220p'Repository: Lyellr88/marm-memory
Length of output: 198
🏁 Script executed:
#!/bin/bash set -euo pipefail printf '%s\n' '--- console/app.py ---' sed -n '1,220p' marm-mcp-server/marm_mcp_server/console/app.py printf '%s\n' '--- console/cli.py ---' sed -n '1,220p' marm-mcp-server/marm_mcp_server/console/cli.py printf '%s\n' '--- console/__main__.py ---' sed -n '1,220p' marm-mcp-server/marm_mcp_server/console/__main__.pyRepository: Lyellr88/marm-memory
Length of output: 7156
🏁 Script executed:
#!/bin/bash set -euo pipefail printf '%s\n' '--- console/app.py with line numbers ---' python3 - <<'PY' from pathlib import Path path = Path("marm-mcp-server/marm_mcp_server/console/app.py") for i, line in enumerate(path.read_text().splitlines(), 1): print(f"{i:4d}: {line}") PYRepository: Lyellr88/marm-memory
Length of output: 4338
🏁 Script executed:
#!/bin/bash set -euo pipefail printf '%s\n' '--- search for authentication / trusted host / CORS in console ---' rg -n "TrustedHostMiddleware|CORSMiddleware|Authentication|APIKey|Bearer|token|auth|host header|Host" marm-mcp-server/marm_mcp_server/console marm-mcp-server/marm_mcp_server -g '!**/__pycache__/**'Repository: Lyellr88/marm-memory
Length of output: 50377
🏁 Script executed:
#!/bin/bash set -euo pipefail python3 - <<'PY' from pathlib import Path for rel in [ "marm-mcp-server/marm_mcp_server/console/app.py", "marm-mcp-server/marm_mcp_server/console/endpoints/memory.py", "marm-mcp-server/marm_mcp_server/console/endpoints/sessions.py", "marm-mcp-server/marm_mcp_server/console/endpoints/logs.py", "marm-mcp-server/marm_mcp_server/console/endpoints/notebook.py", "marm-mcp-server/marm_mcp_server/console/endpoints/compaction.py", "marm-mcp-server/marm_mcp_server/console/endpoints/concepts.py", "marm-mcp-server/marm_mcp_server/console/endpoints/projects.py", ]: print(f"\n--- {rel} ---") text = Path(rel).read_text().splitlines() for i, line in enumerate(text, 1): if "Authorization" in line or "Depends" in line or "middleware" in line or "`@router`." in line or "`@app`." in line or "HTTPException" in line: print(f"{i:4d}: {line}") PYRepository: Lyellr88/marm-memory
Length of output: 5469
🏁 Script executed:
#!/bin/bash set -euo pipefail printf '%s\n' '--- console auth / host / middleware search ---' rg -n "TrustedHostMiddleware|CORSMiddleware|Authorization|Bearer|apiKey|Depends\(|middleware" marm-mcp-server/marm_mcp_server/console marm-mcp-server/marm_mcp_server -g '!**/__pycache__/**' | head -n 200 printf '%s\n' '--- console endpoints with decorators and imports ---' python3 - <<'PY' from pathlib import Path for rel in [ "marm-mcp-server/marm_mcp_server/console/endpoints/memory.py", "marm-mcp-server/marm_mcp_server/console/endpoints/sessions.py", "marm-mcp-server/marm_mcp_server/console/endpoints/logs.py", "marm-mcp-server/marm_mcp_server/console/endpoints/notebook.py", "marm-mcp-server/marm_mcp_server/console/endpoints/compaction.py", "marm-mcp-server/marm_mcp_server/console/endpoints/concepts.py", "marm-mcp-server/marm_mcp_server/console/endpoints/projects.py", ]: print(f"\n### {rel}") for i, line in enumerate(Path(rel).read_text().splitlines(), 1): if any(tok in line for tok in ("from fastapi", "`@router`.", "Authorization", "Depends(", "HTTPException")): print(f"{i:4d}: {line}") PYRepository: Lyellr88/marm-memory
Length of output: 50377
🏁 Script executed:
#!/bin/bash set -euo pipefail python3 - <<'PY' from pathlib import Path targets = [ "marm-mcp-server/marm_mcp_server/console/app.py", "marm-mcp-server/marm_mcp_server/console/endpoints/memory.py", "marm-mcp-server/marm_mcp_server/console/endpoints/sessions.py", "marm-mcp-server/marm_mcp_server/console/endpoints/logs.py", "marm-mcp-server/marm_mcp_server/console/endpoints/notebook.py", "marm-mcp-server/marm_mcp_server/console/endpoints/compaction.py", "marm-mcp-server/marm_mcp_server/console/endpoints/concepts.py", "marm-mcp-server/marm_mcp_server/console/endpoints/projects.py", ] for rel in targets: print(f"\n--- {rel} ---") for i, line in enumerate(Path(rel).read_text().splitlines(), 1): if any(token in line for token in ( "CORSMiddleware", "TrustedHostMiddleware", "Authorization", "Bearer", "Depends(", "APIKey", "apiKey", "middleware", "`@router`.", "`@app`.", )): print(f"{i:4d}: {line}") PYRepository: Lyellr88/marm-memory
Length of output: 2666
Broken Authentication (CWE-306): Missing Authentication for Critical Function
Reachability: External
● Entry marm-mcp-server/marm_mcp_server/server.py:49 lifespan │ ▼ ● Sink marm-mcp-server/marm_mcp_server/console/app.pyProtect the Console API with auth and Host validation The Console exposes mutable
/api/*routes with no app-wide authentication orTrustedHostMiddleware. Loopback binding and CORS are not an access boundary here: a DNS-rebound page can still send same-origin requests, andMARM_CONSOLE_HOSTcan expose the same unauthenticated APIs on the network. Require a per-runtime bearer token for non-health routes and reject untrusted Host headers.🤖 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/console/app.py` around lines 61 - 66, Update the FastAPI app initialization around `app` to add app-wide bearer-token authentication for every non-health route, using a per-runtime token and allowing the health endpoint unauthenticated. Add `TrustedHostMiddleware` configured from the console host settings so requests with untrusted Host headers are rejected, while preserving the existing lifespan and app metadata.marm-mcp-server/marm_mcp_server/console/cli.py (1)
39-48: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash ast-grep run --pattern 'def start_log_maintenance($$$) { $$$ }' --lang python marm-mcp-server/marm_mcp_server/core/runtime_manager.py ast-grep run --pattern 'def bound_log_file($$$) { $$$ }' --lang python marm-mcp-server/marm_mcp_server/core/runtime_manager.pyRepository: Lyellr88/marm-memory
Length of output: 811
🏁 Script executed:
#!/bin/bash set -euo pipefail printf '\n== cli.py ==\n' wc -l marm-mcp-server/marm_mcp_server/console/cli.py sed -n '1,140p' marm-mcp-server/marm_mcp_server/console/cli.py printf '\n== runtime_manager.py outline ==\n' ast-grep outline marm-mcp-server/marm_mcp_server/core/runtime_manager.py --view expanded || true printf '\n== runtime_manager.py relevant text ==\n' rg -n "start_log_maintenance|bound_log_file|log" marm-mcp-server/marm_mcp_server/core/runtime_manager.py sed -n '1,260p' marm-mcp-server/marm_mcp_server/core/runtime_manager.pyRepository: Lyellr88/marm-memory
Length of output: 13679
Avoid truncating the active console log in
_serve()``
start_log_maintenance(runtime_dir() / "console.log")rewrites the same file thatrun_console()is already streaming to via the inherited stdout fd. That can race with live writes and drop or garble console output; keep maintenance off the active log or point it at a rotated target.🤖 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/console/cli.py` around lines 39 - 48, Update _serve() so start_log_maintenance does not target runtime_dir() / "console.log", which is actively streamed by run_console(). Disable maintenance for the active console log or use a separate rotated target, while preserving the existing uvicorn startup behavior.marm-mcp-server/marm_mcp_server/console/concept_store.py (1)
61-101: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== File map ==" git ls-files marm-mcp-server/marm_mcp_server/console/concept_store.py echo echo "== Relevant lines in concept_store.py ==" sed -n '1,260p' marm-mcp-server/marm_mcp_server/console/concept_store.py | nl -ba | sed -n '1,260p' echo echo "== Search for connection handling in console package ==" rg -n "contextlib\.closing|with connection:|sqlite3\.connect|def _connect|def summary|def search|def neighborhood|def get_entity|def build_runs|def get_build_run|def duplicates|def graph_overview" marm-mcp-server/marm_mcp_server/consoleRepository: Lyellr88/marm-memory
Length of output: 312
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== concept_store.py with line numbers ==" awk '{printf "%6d %s\n", NR, $0}' marm-mcp-server/marm_mcp_server/console/concept_store.py | sed -n '1,260p' echo echo "== Connection-related helpers and read functions ==" rg -n "def _connect|def _schema_status|def summary|def search|def neighborhood|def get_entity|def build_runs|def get_build_run|def duplicates|def graph_overview|closing|sqlite3\.connect|connection\.close|with connection:|with closing" marm-mcp-server/marm_mcp_server/console/concept_store.py echo echo "== Other console files mentioning closing or sqlite connections ==" rg -n "closing|sqlite3\.connect|connection\.close|with connection:" marm-mcp-server/marm_mcp_server/consoleRepository: Lyellr88/marm-memory
Length of output: 13537
Close concept-store connections deterministically
with connection:only manages the transaction; it doesn’t close the SQLite handle. These read paths (summary,search,neighborhood,get_entity,build_runs,get_build_run,duplicates,graph_overview) rely on GC to release the FD, so a polling consumer can accumulate open handles. Wrap the connection incontextlib.closingas well.🤖 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/console/concept_store.py` around lines 61 - 101, The read paths including summary, search, neighborhood, get_entity, build_runs, get_build_run, duplicates, and graph_overview must close SQLite handles deterministically. Import and apply contextlib.closing around each _connect result, while retaining the existing transaction context so connections are closed after each operation rather than relying on garbage collection.marm-mcp-server/marm_mcp_server/console/endpoints/concepts.py (1)
154-168: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Background build thread only handles
McpUnavailable, notMcpRequestError.
core._mcp_tool_mutationcatches bothmcp_client.McpRequestErrorandmcp_client.McpUnavailablewhen talking to the MCP server._run_concept_buildonly catchesMcpUnavailable. If the MCP server responds with an HTTP error (4xx/5xx →McpRequestError), the exception propagates unhandled inside the daemon thread — it's swallowed by Python's default thread excepthook, and the job record is never updated. The build then reports"queued"/"running"for up to_CONCEPT_BUILD_STALE_SECONDS(300s) before_stale_build_resultfinally marks it"error"/"stale_run", instead of surfacing the real failure immediately.🐛 Proposed fix
def _run_concept_build(job_id: str, payload: dict) -> None: payload["run_id"] = job_id try: mcp_client.post("marm_concept_build", payload, timeout=120.0) - except mcp_client.McpUnavailable: + except (mcp_client.McpUnavailable, mcp_client.McpRequestError) as exc: with _launching_concept_builds_lock: launch = _launching_concept_builds.get(job_id) if launch: failed, _ = launch failed.update( status="error", - error_code="mcp_unavailable", + error_code="mcp_unavailable" if isinstance(exc, mcp_client.McpUnavailable) else "mcp_request_error", finished_at=time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()), )📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.def _run_concept_build(job_id: str, payload: dict) -> None: payload["run_id"] = job_id try: mcp_client.post("marm_concept_build", payload, timeout=120.0) except (mcp_client.McpUnavailable, mcp_client.McpRequestError) as exc: with _launching_concept_builds_lock: launch = _launching_concept_builds.get(job_id) if launch: failed, _ = launch failed.update( status="error", error_code="mcp_unavailable" if isinstance(exc, mcp_client.McpUnavailable) else "mcp_request_error", finished_at=time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()), )🤖 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/console/endpoints/concepts.py` around lines 154 - 168, Update _run_concept_build to catch mcp_client.McpRequestError alongside mcp_client.McpUnavailable and handle both through the existing launch failure-update path. Preserve the current immediate error status, mcp_unavailable error code behavior unless an established request-error code is available, and ensure neither MCP exception escapes the background thread without updating the job record.marm-mcp-server/marm_mcp_server/console/memory_store.py (2)
15-67: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
Does Python's sqlite3.Connection close the underlying database when used as awithcontext manager?💡 Result:
No, Python's sqlite3.Connection does not close the underlying database connection when used as a with context manager [1][2][3]. The sqlite3 context manager is designed specifically for transaction control, not resource management [1][4]. When you use a connection object with a with statement, it performs the following actions upon exiting the block: - If the block finishes successfully, the context manager commits the transaction [1][2]. - If an exception occurs within the block, the context manager rolls back the transaction [1][2]. - It does not implicitly close the connection or open a new transaction [1][3]. Because the connection remains open after the with block concludes, you must manually call con.close to release the database resource [1][4][5]. Failure to do so may lead to resource leaks, such as open file handles [5]. As of Python 3.13, if a Connection object is garbage collected without being closed, a ResourceWarning will be emitted [1][6]. If you prefer to have the connection automatically closed upon exiting the block, you can use contextlib.closing: from contextlib import closing import sqlite3 with closing(sqlite3.connect('example.db')) as con: with con: # Perform database operations # The connection will be closed automatically when exiting the 'closing' block
Citations:
- 1: https://docs.python.org/3/library/sqlite3.html
- 2: https://docs.python.org/3.11/library/sqlite3.html
- 3: https://stackoverflow.com/questions/77827942/connection-and-cursor-still-usable-outside-with-block
- 4: https://stackoverflow.com/questions/58471206/does-connection-exit-close-itself-in-sqlite3
- 5: https://alexwlchan.net/notes/2024/sqlite3-context-manager-doesnt-close-connections/
- 6: https://github.com/python/cpython/blob/main/Doc/library/sqlite3.rst
🏁 Script executed:
#!/bin/bash set -euo pipefail # Map the file and inspect the relevant section with line numbers. git ls-files marm-mcp-server/marm_mcp_server/console/memory_store.py echo '---' cat -n marm-mcp-server/marm_mcp_server/console/memory_store.py | sed -n '1,220p' echo '--- SEARCH close/closing usages ---' rg -n "contextlib\.closing|\.close\(\)|with _connect\(|sqlite3\.connect\(" marm-mcp-server/marm_mcp_server/console/memory_store.py marm-mcp-server/marm_mcp_server/console -g '*.py'Repository: Lyellr88/marm-memory
Length of output: 12606
Close SQLite connections explicitly
with _connect(db_path) as connection:only commits/rolls back; it does not close the handle. These console queries can leave file descriptors open until GC runs. Wrap_connect()and the ad-hoc_concept_link_counts()connection incontextlib.closingor close them infinally.🧰 Tools
🪛 ast-grep (0.44.1)
[info] 50-50: use jsonify instead of json.dumps for JSON output
Context: json.dumps(memory_ids)
Note: [CWE-116] Improper Encoding or Escaping of Output.(use-jsonify)
🤖 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/console/memory_store.py` around lines 15 - 67, The SQLite connections used by _connect callers and _concept_link_counts must be explicitly closed rather than relying on the connection context manager. Wrap each _connect(db_path) usage and the ad-hoc sqlite3.connect(db_path) in contextlib.closing while preserving existing commit/rollback behavior and error handling.
152-176: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
Missing parentheses break the
compaction_role="none"filter combined with any other filter.Line 171's clause
"compaction_role IS NULL OR compaction_role = 'none'"is not parenthesized, unlike theis Nonebranch at line 169. Since clauses are joined withAND, SQL's precedence (ANDbinds tighter thanOR) turnsWHERE compaction_role IS NULL OR compaction_role = 'none' AND session_name = ?intoWHERE compaction_role IS NULL OR (compaction_role = 'none' AND session_name = ?). Any request combiningcompaction_role=nonewithsession/project/platform/context_type/qwill return extra rows from unrelated sessions/projects that merely have a NULLcompaction_role, and thetotalcount will be inflated the same way.🐛 Proposed fix
elif compaction_role == "none": - clauses.append("compaction_role IS NULL OR compaction_role = 'none'") + clauses.append("(compaction_role IS NULL OR compaction_role = 'none')")📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.def list_memories( db_path: Path, *, q: str | None = None, session: str | None = None, project: str | None = None, platform: str | None = None, context_type: str | None = None, compaction_role: str | None = None, limit: int = 50, offset: int = 0, ) -> dict: limit = min(max(limit, 1), 200) offset = max(offset, 0) clauses: list[str] = [] params: list[object] = [] if compaction_role is None: clauses.append("(compaction_role IS NULL OR compaction_role != 'source')") elif compaction_role == "none": clauses.append("(compaction_role IS NULL OR compaction_role = 'none')") elif compaction_role == "compacted": clauses.append("compaction_role = 'source'") else: clauses.append("compaction_role = ?") params.append(compaction_role)🤖 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/console/memory_store.py` around lines 152 - 176, Parenthesize the OR expression in the compaction_role == "none" branch of list_memories so it remains grouped when combined with the other clauses via AND. Preserve the existing filtering semantics for NULL or "none" roles and ensure both result rows and total counts use the corrected condition.marm-mcp-server/marm_mcp_server/console/models.py (1)
40-43: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
ProjectDeletePayload.confirmis a plain bool, unlike every other delete payload.
MemoryDeletePayload,MemoryBulkDeletePayload,SessionDeletePayload,BulkDeletePayload,LogDeletePayload, andNotebookDeletePayloadall requireconfirm: Literal["DELETE"](or"DELETE_ALL") as an explicit typed-in confirmation string to guard against accidental destructive calls.ProjectDeletePayloadinstead usesconfirm: bool = False, defaulting to a value that's trivially true-able (e.g., any client bug that defaults booleans toTrue, or a generic "confirm" toggle reused across forms) without the same deliberate string-match safeguard. Project deletion is at least as destructive as the others — worth aligning it with the sameLiteralpattern.♻️ Proposed fix
+from typing import Literal + class ProjectDeletePayload(BaseModel): name: str - confirm: bool = False + confirm: Literal["DELETE"]Note:
endpoints/projects.py'sdelete_projectforwardspayload.model_dump()directly to the MCPinternal/projects/deleteoperation, so the downstream contract would need to tolerate the string value instead of a bool.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.from typing import Literal class ProjectDeletePayload(BaseModel): name: str confirm: Literal["DELETE"]🤖 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/console/models.py` around lines 40 - 43, Update ProjectDeletePayload.confirm to require the same explicit typed confirmation literal used by the other delete payloads, removing the boolean default; then update the downstream delete_project/internal projects-delete contract to accept and validate that string confirmation value end-to-end.marm-mcp-server/marm_mcp_server/core/graph_supervisor.py (1)
92-103: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Do not use
_lock.locked()as the startup indicator.
_lockis also held bystop(). While shutdown clears_ready, this method can report"starting"even though the graph is stopping. Since_clientand_availableare read without synchronization, it can also return contradictory fields such asstarted: falsewithavailable: true. Track an explicit lifecycle state or capture a consistent snapshot under the existing synchronization strategy.As per path instructions, Python reviews prioritize runtime correctness and async/concurrency 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/core/graph_supervisor.py` around lines 92 - 103, Replace the `_lock.locked()`-based `"starting"` determination in the graph status method with an explicit lifecycle state or a synchronized snapshot. Ensure `state`, `_client`, and `_available` are read consistently under the existing synchronization strategy so shutdown cannot be reported as starting and contradictory `started`/`available` values cannot be returned.Source: Path instructions
marm-mcp-server/pyproject.toml (1)
8-8: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash grep -n '^version' marm-mcp-server/pyproject.toml rg -n 'SERVER_VERSION|__version__' marm-mcp-server/marm_mcp_server/__init__.py marm-mcp-server/marm_mcp_server/config/settings.py marm-mcp-server/marm_mcp_server/server.pyRepository: Lyellr88/marm-memory
Length of output: 801
Version bump is still missing
marm-mcp-server/pyproject.toml,marm-mcp-server/marm_mcp_server/__init__.py,marm-mcp-server/marm_mcp_server/config/settings.py, andmarm-mcp-server/marm_mcp_server/server.pystill declare2.25.0. Update all release-version sources to2.26.0and runpython scripts/find-versions.py.🤖 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 8, Update every release-version declaration in pyproject.toml, marm_mcp_server.__init__, config.settings, and server.py from 2.25.0 to 2.26.0, then run python scripts/find-versions.py to verify no stale version remains.Source: Coding guidelines
marm-mcp-server/tests/test_http_rate_limit.py (1)
29-34: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Shallow shutdown assertions — verify state isolation and add real assertions.
These two new checks only assert
status_code == 200; they don't verify shutdown actually changed runtime state (e.g., write-queue stopped) or that no lingering global state from/internal/runtime/shutdownleaks into later tests reusing the samerate_limiter/runtime singletons. As per path instructions, "Do not write existence-check or coded-to-pass tests; prefer deep tests exercising real paths over broad shallow coverage," and tests should not be "non-isolated."Consider asserting on response content (e.g.,
shutdown.json()) and/or a follow-upruntime_statuscheck confirming the queue/runtime reflects the shutdown, and confirmshutdown_managerdoesn't set any global flag that could affect subsequent tests in the same process.🤖 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/tests/test_http_rate_limit.py` around lines 29 - 34, Strengthen the shutdown test around the runtime status and shutdown requests by asserting the shutdown response content and performing a follow-up status check that confirms the write queue/runtime is stopped. Ensure the shutdown path does not leave persistent global state in shared runtime or rate-limiter singletons that could affect later tests.Source: Path instructions
|
@CodeRabbit review |
✅ Action performedReview finished.
|
Address PR review findings across managed runtime lifecycle, Console authentication, SQLite reads, graph state reporting, and CLI diagnostics. Synchronize v2.26.0 release metadata and documentation, preserve bounded logs and dynamic static assets, and expand regression coverage for the corrected behavior.
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/cli.py`:
- Around line 37-43: Update _write_generated_api_key to preserve direct display
only for interactive stdout; refuse non-interactive or redirected output by
default, and require an explicit opt-in before emitting the generated key when
stdout is captured or piped. Keep the existing interactive message unchanged.
🪄 Autofix (Beta)
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
Run ID: 15212bb1-f44a-406e-878b-524a06d49e9f
📒 Files selected for processing (31)
CHANGELOG.mdREADME.mddocs/INSTALL-DOCKER.mddocs/INSTALL-LINUX.mddocs/INSTALL-PLATFORMS.mddocs/INSTALL-WINDOWS.mddocs/TECHNICAL-OVERVIEW.mdmarm-console/tests/test_concept_store.pymarm-console/tests/test_memory_mutation_routes.pymarm-console/tests/test_overview_health.pymarm-mcp-server/Dockerfilemarm-mcp-server/README.mdmarm-mcp-server/docker-compose.ymlmarm-mcp-server/marm-docs/README.mdmarm-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/concept_store.pymarm-mcp-server/marm_mcp_server/console/endpoints/concepts.pymarm-mcp-server/marm_mcp_server/console/mcp_client.pymarm-mcp-server/marm_mcp_server/console/memory_store.pymarm-mcp-server/marm_mcp_server/core/graph_supervisor.pymarm-mcp-server/marm_mcp_server/server.pymarm-mcp-server/pyproject.tomlmarm-mcp-server/server.jsonmarm-mcp-server/tests/test_bundled_console.pymarm-mcp-server/tests/test_cli_entrypoint.pymarm-mcp-server/tests/test_graph_supervisor.pymarm-mcp-server/tests/test_runtime_cli.py
🚧 Files skipped from review as they are similar to previous changes (16)
- marm-console/tests/test_overview_health.py
- marm-mcp-server/pyproject.toml
- marm-mcp-server/marm_mcp_server/console/endpoints/concepts.py
- docs/TECHNICAL-OVERVIEW.md
- marm-mcp-server/marm_mcp_server/console/mcp_client.py
- docs/INSTALL-LINUX.md
- marm-console/tests/test_concept_store.py
- marm-mcp-server/marm_mcp_server/server.py
- CHANGELOG.md
- marm-mcp-server/marm-docs/README.md
- marm-mcp-server/README.md
- marm-mcp-server/marm_mcp_server/console/cli.py
- README.md
- marm-mcp-server/marm_mcp_server/console/app.py
- marm-mcp-server/marm_mcp_server/console/concept_store.py
- marm-mcp-server/tests/test_runtime_cli.py
📜 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,docs/INSTALL-*.md}
📄 CodeRabbit inference engine (AGENTS.md)
When bumping the version, update every enumerated version source and run
python scripts/find-versions.py; follow SemVer definitions for breaking changes, features, and fixes.
Files:
marm-mcp-server/Dockerfiledocs/INSTALL-DOCKER.mddocs/INSTALL-PLATFORMS.mdmarm-mcp-server/marm_mcp_server/__init__.pymarm-mcp-server/server.jsonmarm-mcp-server/marm_mcp_server/config/settings.pydocs/INSTALL-WINDOWS.md
**/*.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:
docs/INSTALL-DOCKER.mddocs/INSTALL-PLATFORMS.mddocs/INSTALL-WINDOWS.md
marm-mcp-server/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
Keep changes surgical: touch only what the task requires, match existing style, and preserve behavior during refactors.
Files:
marm-mcp-server/marm_mcp_server/__init__.pymarm-mcp-server/tests/test_graph_supervisor.pymarm-mcp-server/tests/test_cli_entrypoint.pymarm-mcp-server/tests/test_bundled_console.pymarm-mcp-server/marm_mcp_server/config/settings.pymarm-mcp-server/marm_mcp_server/core/graph_supervisor.pymarm-mcp-server/marm_mcp_server/console/memory_store.pymarm-mcp-server/marm_mcp_server/cli.py
marm-mcp-server/marm_mcp_server/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
marm-mcp-server/marm_mcp_server/**/*.py: All memory writes must go through the serialized asynchronous write queue; do not add bypass paths.
A semantic-store failure inmarm_log_entrymust never fail the log write.
Keep the memory database and concept-graph database isolated; never share connections between their pools.
Graph and concept failures must never break the seven core memory tools.
Use one lazy-loaded, lock-serialized fastembed encoder with 512 dimensions; writes must succeed when the encoder is unavailable.
Prefer the smallest change that solves the problem; avoid speculative abstractions and unrequested configuration flags.
Use minimal comments that explain only non-obvious reasons; never narrate the next line.
Keep orchestration in its current owner file and extract modules only at real architectural boundaries.
Files:
marm-mcp-server/marm_mcp_server/__init__.pymarm-mcp-server/marm_mcp_server/config/settings.pymarm-mcp-server/marm_mcp_server/core/graph_supervisor.pymarm-mcp-server/marm_mcp_server/console/memory_store.pymarm-mcp-server/marm_mcp_server/cli.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/__init__.pymarm-mcp-server/tests/test_graph_supervisor.pymarm-mcp-server/tests/test_cli_entrypoint.pymarm-console/tests/test_memory_mutation_routes.pymarm-mcp-server/tests/test_bundled_console.pymarm-mcp-server/marm_mcp_server/config/settings.pymarm-mcp-server/marm_mcp_server/core/graph_supervisor.pymarm-mcp-server/marm_mcp_server/console/memory_store.pymarm-mcp-server/marm_mcp_server/cli.py
marm-mcp-server/{marm_mcp_server/endpoints/**/*.py,server.py,server_stdio.py,server.json,scripts/find-tools.py,tests/**/*.py,README.md,docs/**/*.md,marm_mcp_server/marm-docs/**/*.md}
📄 CodeRabbit inference engine (AGENTS.md)
When adding or removing an MCP tool, update the endpoint implementation, HTTP route and whitelist, STDIO registration or wrapper,
server.json, canonical tool list, all full tool-list documentation and counts, and tests for both transports.
Files:
marm-mcp-server/tests/test_graph_supervisor.pymarm-mcp-server/tests/test_cli_entrypoint.pymarm-mcp-server/tests/test_bundled_console.pymarm-mcp-server/server.json
marm-mcp-server/tests/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
marm-mcp-server/tests/**/*.py: Run tests withpytestfrommarm-mcp-server/; use real FastAPI endpoints and SQLite, mocking only when it preserves at least 95% fidelity.
Every new MARM Console API route requires 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 tests exercising real paths over broad shallow coverage.
Usepytest.mark.skiponly for genuinely unavailable dependencies, never merely to avoid implementation effort.
Files:
marm-mcp-server/tests/test_graph_supervisor.pymarm-mcp-server/tests/test_cli_entrypoint.pymarm-mcp-server/tests/test_bundled_console.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_graph_supervisor.pymarm-mcp-server/tests/test_cli_entrypoint.pymarm-console/tests/test_memory_mutation_routes.pymarm-mcp-server/tests/test_bundled_console.py
marm-mcp-server/marm_mcp_server/core/{graph_supervisor.py,graph_client.py}
📄 CodeRabbit inference engine (AGENTS.md)
The code-graph binary must run as a supervised child process over newline-delimited JSON-RPC, start lazily, and degrade on failure.
Files:
marm-mcp-server/marm_mcp_server/core/graph_supervisor.py
🪛 ast-grep (0.44.1)
marm-mcp-server/marm_mcp_server/console/memory_store.py
[info] 63-63: use jsonify instead of json.dumps for JSON output
Context: json.dumps(memory_ids)
Note: [CWE-116] Improper Encoding or Escaping of Output.
(use-jsonify)
🪛 GitHub Check: CodeQL
marm-mcp-server/marm_mcp_server/cli.py
[failure] 39-39: Clear-text logging of sensitive information
This expression logs sensitive data (password) as clear text.
🔇 Additional comments (15)
docs/INSTALL-DOCKER.md (1)
5-5: LGTM!docs/INSTALL-PLATFORMS.md (1)
1-1: LGTM!docs/INSTALL-WINDOWS.md (1)
5-5: LGTM!Also applies to: 70-70, 79-79, 97-108, 296-296
marm-mcp-server/marm_mcp_server/core/graph_supervisor.py (1)
28-29: LGTM!Also applies to: 46-51, 69-79, 102-110, 126-135
marm-mcp-server/marm_mcp_server/config/settings.py (1)
125-125: LGTM!Also applies to: 385-388
marm-mcp-server/marm_mcp_server/console/memory_store.py (1)
8-8: LGTM!Also applies to: 44-70, 73-74, 116-116, 174-174, 195-195, 234-234, 272-272, 292-292, 352-352, 374-382, 402-402, 431-431, 441-441
marm-mcp-server/tests/test_bundled_console.py (1)
1-5: LGTM!Also applies to: 14-25, 28-35, 38-65, 68-79
marm-mcp-server/tests/test_cli_entrypoint.py (1)
18-24: LGTM!Also applies to: 34-34, 46-46
marm-mcp-server/tests/test_graph_supervisor.py (1)
341-363: LGTM!marm-mcp-server/marm_mcp_server/__init__.py (1)
17-20: LGTM!marm-mcp-server/server.json (1)
6-6: LGTM!Also applies to: 20-25
marm-mcp-server/docker-compose.yml (1)
21-21: LGTM!marm-mcp-server/Dockerfile (1)
68-68: LGTM!marm-console/tests/test_memory_mutation_routes.py (1)
1-2: LGTM!Also applies to: 176-191, 194-225
marm-mcp-server/marm_mcp_server/cli.py (1)
534-534: LGTM!Also applies to: 652-652
v2.26.0 - Managed Runtime CLI and Bundled Console
This release makes MARM easier to install, run, inspect, and manage locally.
Added the marm-memory CLI with managed start, stop, restart, status, logs, and doctor workflows.
Added named runtime profiles for standard, swarm, swarm-max, and trusted deployments.
Bundled MARM Console into the main marm-mcp-server package. marm-memory console now runs the local app without a
separate Console backend checkout or Node install.
Added CLI workflows for Knowledge setup/builds, project indexing, maintenance, embedding migration, key generation,
and diagnostics.
Added verified runtime process ownership, bounded logs, graceful shutdown behavior, and clear human-readable status
output with stable --json automation output.
Hardened runtime polling, error reporting, lifecycle rate-limit handling, and Docker/Glama frontend build parity.
Updated docs and install guidance around the managed runtime and bundled Console.
No MCP tools were added or removed. HTTP and STDIO remain at 14 public tools.
Summary by CodeRabbit
New Features
marm-memoryCLI for starting, stopping, restarting, status/doctor, and knowledge setup, with managed runtime support./internal/runtime/statusand a runtime shutdown endpoint.Bug Fixes
Documentation