Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ MARM is a local-first MCP memory server: Python FastAPI in `marm-mcp-server/`, p

Then run `python scripts/find-tools.py`; every surface must report OK.

**README mirrors are generated, never hand-edited:**
**README variants:**

- Root `README.md` is the single source of truth.
- `marm-mcp-server/README.md` is the PyPI variant (adds the `mcp-name:` header and two image divs).
- `marm-mcp-server/marm-docs/README.md` is the text-only agent-facing subset (badges, demo, and footer sections stripped).
- `marm-mcp-server/README.md` is the PyPI variant (adds the `mcp-name:` header and two image divs) and is maintained separately.
- `marm-mcp-server/marm-docs/README.md` is the text-only agent-facing subset (badges, demo, and footer sections stripped) and is maintained separately.

**When bumping the version, update ALL of the following** (audit with `python scripts/find-versions.py`):

Expand All @@ -44,7 +44,7 @@ Then run `python scripts/find-tools.py`; every surface must report OK.
4. `marm-mcp-server/marm_mcp_server/config/settings.py` (`SERVER_VERSION`)
5. `marm-mcp-server/marm_mcp_server/server.py` docstring
6. `marm-mcp-server/Dockerfile` version label and `docker-compose.yml`
7. Root `README.md` h1 (then regenerate mirrors) and the version headers in `docs/INSTALL-*.md`
7. The h1 in `README.md`, `marm-mcp-server/README.md`, and `marm-mcp-server/marm-docs/README.md` (each maintained separately), plus the version headers in `docs/INSTALL-*.md`
Comment thread
coderabbitai[bot] marked this conversation as resolved.

Semver: MAJOR = breaking (schema renames, parameter removals), MINOR = new tools/parameters/features, PATCH = fixes and doc updates.

Expand All @@ -69,7 +69,7 @@ Semver: MAJOR = breaking (schema renames, parameter removals), MINOR = new tools
- Dev setup: `cd marm-mcp-server && pip install -e ".[dev]" && python scripts/bundle-concept-model.py`
- Benchmarks live in `scripts/benchmarking/`: `preformance/bench_hotpath.py` for hot-path performance, `accuracy/locomo/run_eval.py` for LoCoMo retrieval accuracy. Do not publish performance claims neither script can back.

## Current Stats (v2.27.0)
## Current Stats (v2.28.0)

- 14 MCP tools over HTTP + STDIO
- 2 isolated SQLite databases (memory + concept graph)
Expand Down
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,31 @@

## Version 2 - MARM Protocol to Universal MCP Server Evolution

<details>
<summary><strong>July 23rd, 2026: Focused Docker Commands and Full Command Surface (v2.28.0)</strong></summary>

### Focused Docker Convenience Commands

- Added `marm-memory docker` for pip-installed users: `status`, `pull`, `run`, `command` (paste-ready preview), `compose`, `stdio-command`, `logs`, `stop`, and `maintenance embeddings migrate`. Generated containers default to loopback binding, a persistent `~/.marm` mount via explicit `--mount`, managed env-file auth (the key never enters shell history), and `--restart unless-stopped`; network exposure requires `--expose-network`.
- `docker run` refuses to replace an existing container and prints the exact inspect/stop choices instead; `docker pull` only downloads. Embedding migration refuses while the managed HTTP container is running and returns Docker's real exit code. `docker upgrade` is reported as a manual step rather than silently recreating a container. Compose previews by default and only writes on `--yes`, never overwriting an existing file. The raw Docker and Compose instructions remain for Docker-only users.

### Complete Command and Usability Pass

- Added transport aliases `http` (foreground HTTP) and `stdio` (in-process MCP STDIO), plus `fast-start-http`, which starts or reuses the runtime, launches Console, and prints a single status report. The existing `start`, `marm-mcp-server`, and `marm-mcp-stdio` entry points are unchanged.
- Expanded key management: `key init` creates or reuses the managed `~/.marm/.env` without ever rotating an existing key, `key path` prints only the path, and `key reveal` prints the key on stdout with its capture warning on stderr. `key generate` is unchanged.
- Added `upgrade`/`update` and `uninstall`. Both preserve all user data under `~/.marm`, detect editable, pipx, and Windows-launcher installs, and print the exact manual command when self-replacement is not safe. `upgrade --check` reports installed versus latest without installing.
- Replaced the default argparse root help with a grouped, terminal-width-aware layout (Daily Use, Setup and Updates, Knowledge and Projects, Docker, Maintenance), added root `-V`/`--version` and a `help <command>` alias, and gave every command a visible one-line description.

### Authenticated Console Handoff

- Added `marm-memory console --import-key`, which hands the managed runtime key to a local Console browser session without exposing it in the frontend, URL, browser storage, or logs. A short-lived, single-use bootstrap token is exchanged for an HttpOnly, SameSite=strict session cookie, and the runtime key stays server-side. Normal Console launch stays keyless, and manual key entry remains available for remote or separately managed runtimes.

### Internal

- `cli.py` was split into focused service modules (Docker, key, package, workflow, help, logs, and project commands) as the command surface grew, with no behavior change to existing commands.

</details>

<details>
<summary><strong>July 22nd, 2026: Bundled Concept Extraction (v2.27.0)</strong></summary>

Expand Down
14 changes: 14 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,20 @@ Run Docker smoke directly when changing Docker, transport setup, auth, or startu
python scripts/test-scripts/docker-smoke.py
```

For changes to Docker bind mounts, container users, `HOME`, cache paths, or data persistence, also run the Linux-only smoke test. It verifies that a host-owned mounted database can be written through HTTP and survives a container restart.

Run it from a native Linux host or WSL2 with Docker Desktop WSL integration enabled. The script creates its temporary mounted data directory under Linux `/tmp`; do not change that location to `/mnt/c`, or the UID/GID assertion is no longer meaningful:

```bash
bash scripts/test-scripts/docker-linux-bind-mount-smoke.sh
```

The script uses the latest official image by default. To test a locally built image instead:

```bash
MARM_DOCKER_SMOKE_IMAGE=marm-mcp-server:smoke bash scripts/test-scripts/docker-linux-bind-mount-smoke.sh
```

## Documentation

Update docs when changing:
Expand Down
121 changes: 115 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
width="900"
height="250">
</picture>
<h1 align="center">MARM: Local-First Persistent Multi-Agent Memory Layer for MCP Clients v2.27.0</h1>
<h1 align="center">MARM: Local-First Persistent Multi-Agent Memory Layer for MCP Clients v2.28.0</h1>

[![License](https://img.shields.io/badge/license-Apache--2.0-blue)](https://github.com/Lyellr88/marm-memory/blob/MARM-main/LICENSE)
[![Python](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org/)
Expand Down Expand Up @@ -36,6 +36,7 @@
- [Why MARM Memory](#why-marm-memory)
- [Performance & Scaling Benchmarks](#performance--scaling-benchmarks)
- [Quick Start](#-quick-start-for-mcp-http--stdio)
- [Runtime CLI Commands](#runtime-cli-commands)
- [Complete MCP Tool Suite](#complete-mcp-tool-suite-14-tools)
- [Using MARM: Talk, Don't Call Tools](#using-marm-talk-dont-call-tools)
- [Understanding MARM Memory](#understanding-marm-memory)
Expand Down Expand Up @@ -99,10 +100,65 @@ pip install marm-mcp-server
| **Private high-throughput swarm** | `marm-memory start --profile swarm-max` | `"agent" mcp add --transport http marm-memory http://localhost:8001/mcp` |
| **Trusted private lab/server** | `marm-memory start --profile trusted` | `"agent" mcp add --transport http marm-memory http://localhost:8001/mcp` |

The managed runtime runs in the background by default. Use `marm-memory status`,
`marm-memory logs --follow`, `marm-memory restart`, and `marm-memory stop` for
normal lifecycle work. `marm-memory console` starts or reuses that runtime and
opens the bundled local web app without requiring Node.js.
The managed runtime runs in the background by default. Use `marm-memory status`, `marm-memory logs --follow`, `marm-memory restart`, and `marm-memory stop` for normal lifecycle work. `marm-memory console` starts or reuses that runtime and opens the bundled local web app without requiring Node.js.

For the shortest native HTTP workflow, run `marm-memory fast-start-http`. It starts or reuses the local runtime, starts Console, opens it in the browser, and ends with the active URLs and a recovery command. Use `--no-console` or `--no-browser` when you only want the server. `--client <name>` is reserved for verified client adapters; MARM does not claim to configure a client it has not validated yet.

`marm-memory http` is the foreground HTTP alias, while `marm-memory stdio` runs the same strict MCP STDIO transport as `marm-mcp-stdio`. Use `marm-memory --help` for grouped command help, `marm-memory help <command>` for command-specific help, and `marm-memory --version` for the installed version.

### Runtime CLI Commands

`marm-memory` is the local runtime manager installed with the Python package. These are the normal operational commands; use `marm-memory <command> --help` for flags and command-specific examples.

**Daily runtime work**

```bash
marm-memory fast-start-http # start HTTP, Console, and open the browser
marm-memory start # start or reuse the managed HTTP runtime
marm-memory start --profile swarm # shared multi-agent preset
marm-memory stop # stop the managed runtime safely
marm-memory restart # restart the managed runtime
marm-memory status # inspect runtime, database, queue, and graph status
marm-memory logs --follow # follow bounded runtime logs
marm-memory console # start or reuse the bundled local Console
```

**Transports and setup**

```bash
marm-memory http # run HTTP in the foreground
marm-memory stdio # run the strict local MCP STDIO transport
marm-memory doctor # diagnose the local install
marm-memory key init # create or reuse ~/.marm/.env without displaying the key
marm-memory key path # print the managed key-file path
marm-memory key reveal # explicitly display the managed key
marm-memory console --import-key # open an authenticated local Console session
marm-memory upgrade --check # compare the installed package with PyPI
marm-memory uninstall # preview package removal; always preserves ~/.marm
```

**Knowledge, projects, and maintenance**

```bash
marm-memory knowledge status
marm-memory knowledge build --all
marm-memory projects list
marm-memory projects index /absolute/path/to/repository
marm-memory projects status
marm-memory maintenance status
marm-memory maintenance embeddings migrate
```

Docker commands are documented separately below because they require explicit data mounts, network exposure, and key-handling choices.

### Local Keys And Package Lifecycle

Normal localhost HTTP remains keyless and loopback-only. For an exposed runtime or a Docker deployment, use `marm-memory key init` to create or reuse the managed `~/.marm/.env` key file. `marm-memory key path` prints only its path; `marm-memory key reveal` intentionally prints the key with a terminal-capture warning. `marm-memory key generate` remains the non-persistent compatibility command.

When a managed key is active, `marm-memory console --import-key` opens a local Console session without placing the API key in browser storage, frontend state, logs, or a URL query string. Manual bearer-key entry remains available for a separately managed or remote runtime.

Use `marm-memory upgrade --check` to compare the installed package with PyPI. `marm-memory upgrade` previews a safe native upgrade; `--yes` performs it only where the active installer can be replaced safely. `marm-memory uninstall` similarly previews package removal and always preserves `~/.marm`, including memory databases, graph indexes, keys, logs, and configuration. On Windows, editable installs, or pipx installs, MARM prints the exact manual command rather than attempting to replace an active launcher.


### Upgrade Existing Embeddings

Expand Down Expand Up @@ -197,7 +253,7 @@ pip install marm-mcp-server
**Swarm / multi-agent note:** The write queue is enabled by default to serialize memory writes through one worker. For shared HTTP deployments, use `marm-memory start --profile swarm` (200 RPM) or `--profile swarm-max` (600 RPM). `--profile trusted` disables rate limiting entirely for private deployments. STDIO is still best for private single-agent/local use. See [Swarm & multi-agent presets](#swarm--multi-agent-presets) for the full table.

<details>
<summary><strong>Local pip HTTP (zero config)</strong></summary>
<summary><strong>Local pip HTTP </strong></summary>

> "agent" refers to claude, gemini, grok, qwen, or any MCP client. Codex uses --url instead of --transport to add MCP tools.

Expand Down Expand Up @@ -257,6 +313,59 @@ marm-mcp-stdio

> Docker HTTP requires an API key because it exposes MARM as a network server; STDIO stays local to the client process and does not need one.

If you installed MARM through pip, the product CLI can safely preview or run the same setup. It uses a loopback port by default, preserves `~/.marm`, stores the generated key in `~/.marm/.env` rather than shell history, and refuses to replace an existing container.

```bash
marm-memory docker command # preview the exact HTTP command
marm-memory docker run # create the managed HTTP container
marm-memory docker stdio-command # print a Docker STDIO client command
marm-memory docker status
marm-memory docker logs --follow
marm-memory docker stop

# Optional: mount repositories read-only for code indexing.
marm-memory docker run --repo /absolute/path/to/repository

# Optional: preview or explicitly write a Compose configuration.
marm-memory docker compose
marm-memory docker compose --yes
```

The HTTP `run`, `command`, and `compose` commands accept the same operational flags:

| Flag | Purpose |
|---|---|
| `--data-dir <absolute path>` | Persistent host directory mounted at `/home/marm/.marm`. Defaults to `~/.marm`; this holds memory, indexes, logs, and the managed key file. |
| `--env-file <path>` | Explicit Docker env file. It must already contain `MARM_API_KEY`; without this flag, MARM uses `~/.marm/.env` and creates a key there only when `docker run` or `docker compose --yes` needs one. |
| `--port <number>` | Host HTTP port. Default: `8001`. |
| `--expose-network` | Bind the host port to `0.0.0.0` instead of loopback. This is deliberate network exposure; configure a firewall and TLS proxy. |
| `--profile standard\|swarm\|swarm-max\|trusted` | Select the same write-queue and rate-limit preset as native HTTP startup. |
| `--rate-limit-rpm <number>` | Override the selected profile's HTTP rate limit. `0` disables rate limiting. |
| `--repo <absolute path>` | Repeatable read-only repository mount for code indexing. MARM reports each corresponding `/workspace/repo-N` path to index inside the container. |
| `--tag <tag>` | Official image tag. Default: `latest`. |
| `--pull` | Pull the selected image before creating a new HTTP container. |
| `--name <name>` | Managed container name. MARM refuses to replace an existing container with that name. |
| `--memory <limit>` / `--cpus <limit>` | Optional Docker resource limits. |
| `--dry-run` | `docker run` only: print the planned command without creating a container or key file. `docker command` is always a preview. |

For example:

```bash
# Shared local server with a custom data path and two repositories for indexing.
marm-memory docker command \
--profile swarm \
--data-dir /srv/marm-data \
--repo /srv/projects/api \
--repo /srv/projects/web

# Execute the reviewed command, pulling the image first.
marm-memory docker run --profile swarm --data-dir /srv/marm-data --pull
```

Docker STDIO is separate from Docker HTTP: `marm-memory docker stdio-command` uses `docker run -i --rm`, has no port and no bearer key, but still mounts the data directory so SQLite memory persists after the short-lived container exits. Use `--data-dir` and `--tag` with that command when needed. There are no separate `docker key` or `docker mount` commands; `--env-file` and `--data-dir` make those choices explicit in the generated HTTP command.

`marm-memory docker pull` only downloads an image. `marm-memory docker maintenance embeddings migrate` runs against the same data mount and refuses while the managed HTTP container is running. The helper is available only with the pip-installed `marm-memory` command; Docker-only users can use the raw commands below.

```bash
# Step 1: generate key (do not add < > around the key)
docker run --rm lyellr88/marm-mcp-server:latest --generate-key
Expand Down
2 changes: 1 addition & 1 deletion docs/INSTALL-DOCKER.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Universal Memory Intelligence Platform for AI Agents

**MARM v2.27.0** - Memory Accurate Response Mode
**MARM v2.28.0** - Memory Accurate Response Mode
*Docker deployment guide for Windows, Mac, and Linux*

---
Expand Down
4 changes: 2 additions & 2 deletions docs/INSTALL-LINUX.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Universal Memory Intelligence Platform for AI Agents

**MARM v2.27.0** - Memory Accurate Response Mode
**MARM v2.28.0** - Memory Accurate Response Mode
*Complete Linux installation guide*

---
Expand Down Expand Up @@ -320,7 +320,7 @@ curl -s http://localhost:8001/health
{
"status": "healthy",
"service": "MARM MCP Server",
"version": "2.27.0",
"version": "2.28.0",
"timestamp": "2026-01-01T00:00:00+00:00",
"database": "connected",
"semantic_search": "available"
Expand Down
2 changes: 1 addition & 1 deletion docs/INSTALL-PLATFORMS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# MARM v2.27.0 MCP Server - Platform Integration Guide
# MARM v2.28.0 MCP Server - Platform Integration Guide

## Table of Contents

Expand Down
4 changes: 2 additions & 2 deletions docs/INSTALL-WINDOWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Universal Memory Intelligence Platform for AI Agents

**MARM v2.27.0** - Memory Accurate Response Mode
**MARM v2.28.0** - Memory Accurate Response Mode
*Complete Windows installation guide*

---
Expand Down Expand Up @@ -294,7 +294,7 @@ Invoke-WebRequest -Uri http://localhost:8001/health
{
"status": "healthy",
"service": "MARM MCP Server",
"version": "2.27.0",
"version": "2.28.0",
"timestamp": "2026-01-01T00:00:00+00:00",
"database": "connected",
"semantic_search": "available"
Expand Down
2 changes: 1 addition & 1 deletion docs/TECHNICAL-OVERVIEW.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# MARM Technical Overview

> Current implementation: MARM MCP Server v2.27.0
> Current implementation: MARM MCP Server v2.28.0

This document explains what MARM is, why it is built this way, and how information moves through the system from an agent writing something to that information being recalled later. It is intended as a technical product overview, not a source-code reference.

Expand Down
28 changes: 28 additions & 0 deletions marm-console/artifacts/marm-console/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useEffect, useState } from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { Route, Switch, Router as WouterRouter } from 'wouter';
import { ConnectionProvider } from '@/lib/marm-connection';
Expand Down Expand Up @@ -33,7 +34,34 @@ function Router() {
);
}

function useConsoleBootstrap(): boolean {
const [ready, setReady] = useState(() => {
const params = new URLSearchParams(window.location.hash.slice(1));
return !params.get('marm-bootstrap');
});

useEffect(() => {
const params = new URLSearchParams(window.location.hash.slice(1));
const token = params.get('marm-bootstrap');
if (!token) return;

window.history.replaceState(null, '', `${window.location.pathname}${window.location.search}`);
void fetch('/api/auth/bootstrap', {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token }),
}).finally(() => setReady(true));
}, []);

return ready;
}

function App() {
const ready = useConsoleBootstrap();

if (!ready) return null;

return (
<QueryClientProvider client={queryClient}>
<ConnectionProvider>
Expand Down
1 change: 1 addition & 0 deletions marm-console/artifacts/marm-console/src/lib/marm-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ async function request<T>(
headers,
body: opts?.body !== undefined ? JSON.stringify(opts.body) : undefined,
signal: controller.signal,
credentials: 'same-origin',
});
} catch (err) {
if (err instanceof DOMException && err.name === 'AbortError') {
Expand Down
Loading
Loading