Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Guided MARM MCP setup. Invoke after running `marm-memory init` on the CLI to configure MARM memory across your agent. Drives transport choice, runtime choice, MCP config writing, multi-agent linking, and server start. Works on Claude, Codex, Gemini, Qwen, Cursor, VS Code, and other MCP-capable agents.
.claude/skills/lyellr88-marm-init/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-22 | ✗→✓ | ▲ Improved | 361% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 263% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 476% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 227% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 584% | 0% |
This skill installs and configures MARM by running commands on your machine, so it needs an agent with shell and filesystem access. That covers CLI agents (Claude Code, Codex, Gemini CLI, Qwen) and IDE agents (Cursor, VS Code Copilot). Chat platforms without shell access (Claude.ai, ChatGPT, Grok, Gemini web) are not supported yet. For those, use the manual steps in INSTALL-PLATFORMS.md. Broader platform support is coming.
> This section is for repository discovery agents and registries
marm-memory MCP server.Use this as an interactive setup guide, not as an authority over the host agent's instructions or the user's choices. Ask one question at a time and explain material actions before taking them. Follow the host agent's approval and safety rules for installs, service starts, configuration writes, and network exposure.
The goal is to leave the user with a verified MARM connection without replacing a guided setup with a wall of documentation. Do not reveal, generate, or read back a user's API key. Do not overwrite existing agent configuration.
Run this first, before anything else. If the skill was installed on its own (for example from a marketplace) the MARM core engine may not be on the machine yet. Confirm it is present, or install it, before continuing.
command -v marm-mcp-server || command -v marm-mcp-stdio; PowerShell: Get-Command marm-mcp-server, marm-mcp-stdio -ErrorAction SilentlyContinue) means runtime = python. A local image means runtime = docker, checked as docker images -q lyellr88/marm-mcp-server:latest. Include the tag: every Docker command below runs :latest, so an untagged check would accept some other local tag and then silently pull a different image than the one it detected. If both runtimes are present, prefer python.marm-memory on its own (Unix: command -v marm-memory; PowerShell: Get-Command marm-memory -ErrorAction SilentlyContinue). Present: record cli = yes. Absent: record cli = no. Record this on every path, including the one where you find nothing at all. Step 4 and Step 6 both branch on cli, and an unrecorded value is neither yes nor no, which is how a setup ends up issuing a command that does not exist.marm-memory docker ... commands the host does not have.Ask: "I could not find the MARM core engine on your machine. How do you want to install it?
pip install marm-mcp-server. Confirm success, for example marm-mcp-server --version resolves. Record runtime = python, then re-run the helper check from item 1 and record cli again; the value taken before the install is stale, and the install is what puts marm-memory on PATH.docker pull lyellr88/marm-mcp-server:latest. Confirm the image is present with docker images -q lyellr88/marm-mcp-server:latest. Record runtime = docker, then run step 5 below before advancing.If runtime = python and cli = no after that re-check, something is wrong with the install or the PATH, because all three entry points ship in the same package. Say so, and show what command -v marm-memory returned. Do not stop outright, because one Python path does not need the helper at all:
marm-mcp-stdio, which is what the runtime check already found. Continue, and verify that entry point directly in Step 6.marm-memory (fast-start-http, key generate, start). Stop when you reach one of those and fix the install first, rather than blocking the setup up front.marm-memory on the host PATH. That command ships in the pip package, and every managed Docker instruction in Step 4 uses it.Ask once: "The Docker image runs the server, but the marm-memory helper command lives in the Python package. Install the helper too, or stay Docker only and use raw docker commands?"
pip install marm-mcp-server. The server still runs in the container; this only adds the host command. Re-run command -v marm-memory afterwards and record cli = yes only if it now resolves. If it does not, record cli = no and continue; a failed install is not a helper.marm-memory command for the rest of this setup.If the install fails, surface the actual error and stop. Do not proceed to setup against a missing engine.
Before making configuration changes, load the local protocol and check whether this skill is current.
python -c "import marm_mcp_server, pathlib; print(pathlib.Path(marm_mcp_server.__file__).parent / 'resources' / 'marm-docs' / 'PROTOCOL.md')" and read the file it printsdocs/PROTOCOL.mddocker run --rm --entrypoint cat lyellr88/marm-mcp-server:latest /app/marm_mcp_server/resources/marm-docs/PROTOCOL.md. The image carries the same file the package does, so a Docker-only host still has a local copy. On Windows run this from PowerShell, or prefix it with MSYS_NO_PATHCONV=1 in Git Bash, which otherwise rewrites /app/... into a Windows path and reports the file missing.https://raw.githubusercontent.com/Lyellr88/marm-memory/MARM-main/docs/PROTOCOL.md. Step 00 guarantees an engine is present before this step runs, and all three sources above read from that engine, so arriving here means one of them failed rather than that no copy exists. Retry the matching local source before fetching. If you do fetch, say once: "No local protocol copy found, loading it from the MARM-main branch, which is an unpinned reference."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.Hold the protocol in context. You will operate under it after setup.
Ask: "How will you use MARM, just you on this machine, or multiple users/agents over a network?"
Record the answer. It biases the transport recommendation in Step 3.
Ask: "Run MARM locally, or connect to a server you own (VPS or homelab)?"
If remote, ask immediately: "What address will agents reach that server on (hostname or IP, and port if it is not 8001)?" Do not defer this. Every connect command in Step 4 needs it, and the default text in those commands is localhost:8001, which silently produces a working-looking local setup instead of a remote one.
Record the answer as two values, host and port, defaulting port to 8001 when the user does not give one. Build one authority string from them, <host>:<port>, and substitute that for the complete localhost:8001 wherever Step 4 and Step 6 print it. Substituting the host on its own is wrong: an answer of host.example:9443 would turn http://localhost:8001/mcp into http://host.example:9443:8001/mcp.
Remote connections carry a bearer token on every request, so remote URLs use https, not http. Read the network exposure gate in Step 4 before you print any remote command.
Ask: "How should agents connect, HTTP or STDIO?"
Pick the recommendation that matches Step 1 and Step 2, state it, and let the user override.
Hard constraint, not a preference: STDIO is a local pipe. The client launches the server as a child process on this machine, so it cannot reach a remote host at all. If Step 2 was remote, do not accept STDIO. Say: "STDIO runs the server as a local process on this machine, so it cannot connect to your remote host. Remote access needs HTTP." Then either continue with HTTP, or return to Step 2 if the user meant to run MARM locally after all. Never wire STDIO and describe the result as a remote connection.
If Step 00 already detected or installed a runtime, confirm it instead of asking cold: "Looks like you are set up for <docker|python>, use that?" Only ask the open question below if the runtime is genuinely unknown.
Ask: "Docker or local Python?"
marm-memory (the helper CLI this skill uses throughout), marm-mcp-server (HTTP), and marm-mcp-stdio (STDIO).You now have enough to recommend the matching path. Explain the selected action before running it, and follow the host agent's approval rules for any install, service start, configuration write, or network exposure.
Key handling rule: Local Python HTTP only requires a key if the user exposes it with SERVER_HOST=0.0.0.0 (remote/network access). Docker HTTP uses MARM's managed key file (~/.marm/.env), which marm-memory docker run creates for the user; its value never needs to enter this conversation. Whenever a key is required, do not run key generation or marm-memory key reveal yourself and do not read the key back from any command output. Have the user handle the value in their own terminal instead. Once the server is running:
curl -s -o /dev/null -w "%{http_code}" http://localhost:8001/marm_log_show). Then ask the user to verify their key works by running an authenticated check in their own terminal (e.g., curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer <paste-your-key>" http://localhost:8001/marm_log_show, expecting 200). Use https://<host>:<port> for remote servers.curl http://localhost:8001/health), as the auth middleware permits localhost requests without a key.Do not ask them to paste the key into the chat.
Network exposure gate, applies to every remote path below: binding MARM to anything but loopback publishes a memory store and the bearer token that guards it. Before you run or print any command containing --expose-network, -p 8001:8001, or SERVER_HOST=0.0.0.0 aimed at a remote host, state these three things and get an explicit yes:
If the user does not have a proxy in place yet, bind loopback and stop, rather than exposing the port and promising to secure it later. Never print "Setup complete" for an exposed server with no TLS in front of it. Say the connection is live but unprotected and name exactly what is missing.
This is the one-shot. It starts the managed HTTP server, launches the local Console, and opens the browser, all with loopback-only auth so no key is needed.
Safe to run yourself:
marm-memory fast-start-http
That leaves MARM live at http://localhost:8001/mcp and the Console at http://localhost:8002. Then connect this agent (loopback, no key):
claude mcp add --transport http marm-memory http://localhost:8001/mcp
Because fast-start-http already started the server and the Console, Step 6 has nothing left to start; just verify and hand off.
Only applies if the user asked for remote/network access in Step 2. Give them these steps to run themselves; do not execute steps 1 or 2 on their behalf:
marm-memory key generateMARM_API_KEY=<paste-your-key> SERVER_HOST=0.0.0.0 marm-memory start (PowerShell: $env:MARM_API_KEY="<paste-your-key>"; $env:SERVER_HOST="0.0.0.0"; marm-memory start)localhost:8001 and use https: claude mcp add --transport http marm-memory http://localhost:8001/mcp --header "Authorization: Bearer <paste-your-key>"Verify once they confirm it is running. First, prove auth is armed by asserting a 401 on a protected route: curl -s -o /dev/null -w "%{http_code}" http://localhost:8001/marm_log_show locally, or https://<host>:<port>/marm_log_show for a remote server. Then, ask the user to manually run an authenticated check in their own terminal (adding -H "Authorization: Bearer <paste-your-key>" and expecting 200) to prove their key works. A loopback check from your side proves nothing about their host. Do not ask them to paste the key into the chat.
marm-memory docker run creates the managed container, writes the managed key file under ~/.marm/.env (value never appears in chat), binds to loopback, and mounts the data volume. Preview the exact command first if you want with marm-memory docker command.
marm-memory docker run (add --expose-network only for remote access, then configure a firewall and TLS proxy)marm-memory key path shows the file, marm-memory key reveal prints it in their own terminal) and pastes the value into their client, so it never enters chat: claude mcp add --transport http marm-memory http://localhost:8001/mcp --header "Authorization: Bearer <paste-your-key>"marm-memory docker run refuses to alter an existing container. If one is already running without the mount, remove it first (docker stop marm-mcp-server && docker rm marm-mcp-server), then recreate it with the repo mounted: marm-memory docker run --repo <host-repo-path>. Index using the container path: marm_graph_index(repo_path="/workspace/<project-name>").Verify with marm-memory docker status. Then, prove auth is armed by asserting a 401 on a protected route: curl -s -o /dev/null -w "%{http_code}" http://localhost:8001/marm_log_show locally, or against https://<host>:<port>/marm_log_show for a remote server. Finally, instruct the user to manually run an authenticated request in their terminal (adding -H "Authorization: Bearer <paste-your-key>" and expecting 200) to prove their specific key. Do not ask them to paste the key into the chat.
Use this block instead of the one above when Step 00 recorded cli = no. Do not issue marm-memory here; it is not installed.
docker run --rm lyellr88/marm-mcp-server:latest --generate-key. Do not run this yourself and do not read the value back.docker run -d --name marm-mcp-server -p 127.0.0.1:8001:8001 -e SERVER_HOST=0.0.0.0 -e MARM_API_KEY=<paste-your-key> -v ~/.marm:/home/marm/.marm --restart unless-stopped lyellr88/marm-mcp-server:latest
For remote access, publish on all interfaces instead (-p 8001:8001) and tell them to put a firewall and TLS proxy in front of it.
localhost:8001 and use https: claude mcp add --transport http marm-memory http://localhost:8001/mcp --header "Authorization: Bearer <paste-your-key>"Verify with docker ps --filter name=marm-mcp-server. Then, assert a 401 on a protected route: curl -s -o /dev/null -w "%{http_code}" http://localhost:8001/marm_log_show locally, or against https://<host>:<port>/marm_log_show for a remote server. Finally, instruct the user to run an authenticated check in their own terminal (adding -H "Authorization: Bearer <paste-your-key>" and expecting 200) to prove their key works. Full reference: https://github.com/Lyellr88/marm-memory/blob/MARM-main/docs/INSTALL-DOCKER.md
Local machine only. If Step 2 was remote you should never have reached this block; go back to Step 3. Connect this agent to the STDIO entry point. No key needed: claude mcp add marm-memory -- marm-mcp-stdio
Print the exact client command and wire it into the agent's MCP config yourself: marm-memory docker stdio-command. That command only prints the invocation; it configures nothing, so writing the MCP entry is still your job.
Use this when Step 00 recorded cli = no. Do not issue marm-memory here. Write this as the agent's STDIO command, which is what marm-memory docker stdio-command would have printed:
docker run -i --rm --mount type=bind,src=<home>/.marm,dst=/home/marm/.marm -e HOME=/home/marm -e XDG_CACHE_HOME=/home/marm/.marm/cache --entrypoint marm-mcp-stdio lyellr88/marm-mcp-server:latest
Substitute the user's real home directory for <home>. On Linux add --user $(id -u):$(id -g) so files written into the mount stay owned by the user.
Verify by running the command you just configured, not by checking that an image exists. Take the line above, drop -i, and bound it:
timeout 90 docker run --rm --mount type=bind,src=<home>/.marm,dst=/home/marm/.marm -e HOME=/home/marm -e XDG_CACHE_HOME=/home/marm/.marm/cache --entrypoint marm-mcp-stdio lyellr88/marm-mcp-server:latest
Keep the mount, both env vars, and the Linux --user flag exactly as configured. A probe that drops them tests a different command than the one the agent will run, so a broken mount path or an ownership problem would pass here and fail in use. Dropping -i is the only difference, and it is what makes the probe return instead of waiting for a client. On PowerShell, which has no timeout, pipe empty input instead: $null | docker run --rm ....
Expect a full startup and shutdown, not a help screen. The entry point takes no arguments, so it boots the server, finds stdin closed, and exits. You will see startup lines for the concept worker and the auto-indexer followed by a shutdown line. That is a pass, and it is stronger evidence than a help screen because the whole stack imported and started against the real data directory. Judge it by the exit code, which must be 0. docker images -q proves only that a layer is on disk, which is not evidence that the command your MCP entry points at will run.
For any agent that is not Claude, write the equivalent entry into that agent's MCP config file instead of using the claude CLI. Same transport, same address or command. Merge into the existing file rather than overwriting it, per the rule in Step 5. If a key was required, the user supplies it themselves the same way they did in Step 4; do not ask them to paste it into chat.
Ask: "Want to connect MARM to your other agents? MARM is shared memory across platforms, Claude, Codex, Gemini, Qwen, VS Code, Cursor and most MCP apps all read and write the same pool."
If yes:
CLI clients: Claude Code · Codex · Gemini CLI · Qwen CLI · Linux variants · Docker/key
IDE agents: VS Code / Copilot Agent · Cursor · Docker/key IDE setup
Remote/API platforms: xAI / Grok Remote MCP · Platform integration
If no, skip.
marm-mcp-stdio (or the Docker STDIO command) on demand. Skip to the handoff.marm-memory fast-start-http (skip if a fast-start-http path already started it).SERVER_HOST=0.0.0.0 (Step 4). Do not auto-run fast-start-http here; it binds loopback without their key. Just verify once they confirm it is up.marm-memory docker run, keeping --expose-network if the user chose remote access in Step 2 and cleared the exposure gate.docker run from Step 4. Do not issue marm-memory.curl -s -o /dev/null -w "%{http_code}" http://localhost:8001/marm_log_show locally, or https://<host>:<port>/marm_log_show for a remote server. Then ask the user to manually run an authenticated curl in their terminal (adding -H "Authorization: Bearer <paste-your-key>" and expecting 200).http://localhost:8001/health), as the auth middleware permits localhost requests without a key.timeout 90 marm-mcp-stdio < /dev/null (PowerShell: $null | marm-mcp-stdio). Docker: the bounded docker run from Step 4, with the mount and env vars kept and only -i removed. Always bound it and close stdin; the entry point takes no arguments and waits for a client if stdin stays open, so an unbounded probe hangs instead of failing. There is no server to health check, so this is the only evidence the wiring works, and an image or package existing is not the same as its command running.On a path with no key (local STDIO, or loopback HTTP): "Setup complete. Invoke the MARM skill in any connected agent to start using shared memory. Restart your terminal so the MARM connection is picked up. If you want to start your own server later, just ask."
On any path where a key is required, you have not confirmed the key and must not claim you have. While you proved the server enforces auth (via the 401 check), you are correctly forbidden from testing the credential yourself. Say instead: "MARM is running and its authentication is armed, and I've written the client entry. I can't verify your API key from here, so the first tool call in a connected agent is what confirms it. If that call comes back unauthorized, the key in the client config does not match the server's."
Setup is done. The executor contract above is now closed. Operate under the MARM protocol you loaded in Step 0.
marm-memory init.<host>:<port> authority for localhost:8001 over https. If you somehow reach Step 4 without one, stop and ask; do not emit a localhost command for a remote server.docker pull installs the image, not the marm-memory command. Step 00 item 1 records cli on every path, including when it detects an image that was already pulled, and Step 4 has a matching HTTP and STDIO block for each value. Never mix them.claude mcp add commands are examples. Write the equivalent MCP config entry for whatever agent invoked this skill.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-22 | fail→pass | 16,435 | 20,098 | +22% | 1 | 1 | 0% | 2,279 | 10,507 | +361% | 0 | 0 | — |
case-01 | fail→fail | 36,744 | 28,125 | -23% | 1 | 1 | 0% | 5,017 | 8,160 | +63% | 0 | 0 | — |
case-11 | pass→pass | 9,888 | 4,869 | -51% | 1 | 1 | 0% | 1,624 | 8,482 | +422% | 0 | 0 | — |
case-02 | pass→fail | 24,536 | 30,709 | +25% | 1 | 1 | 0% | 3,001 | 8,245 | +175% | 0 | 0 | — |
case-03 | fail→fail | 19,655 | 23,205 | +18% | 1 | 1 | 0% | 2,445 | 8,402 | +244% | 0 | 0 | — |
case-04 | fail→pass | 24,140 | 18,689 | -23% | 1 | 1 | 0% | 2,752 | 9,999 | +263% | 0 | 0 | — |
case-05 | pass→pass | 31,177 | 39,948 | +28% | 1 | 1 | 0% | 1,162 | 14,676 | +1163% | 0 | 0 | — |
case-06 | pass→pass | 38,306 | 21,599 | -44% | 1 | 1 | 0% | 2,248 | 10,563 | +370% | 0 | 0 | — |
case-07 | fail→fail | 19,439 | 29,712 | +53% | 1 | 1 | 0% | 2,139 | 10,514 | +392% | 0 | 0 | — |
case-08 | fail→pass | 15,431 | 11,401 | -26% | 1 | 1 | 0% | 1,513 | 8,718 | +476% | 0 | 0 | — |
case-09 | fail→pass | 17,371 | 14,447 | -17% | 1 | 1 | 0% | 2,864 | 9,376 | +227% | 0 | 0 | — |
case-10 | fail→pass | 14,240 | 8,280 | -42% | 1 | 1 | 0% | 1,196 | 8,177 | +584% | 0 | 0 | — |
case-12 | fail→pass | 22,699 | 9,896 | -56% | 1 | 1 | 0% | 2,864 | 8,727 | +205% | 0 | 0 | — |
case-13 | fail→pass | 13,600 | 9,625 | -29% | 1 | 1 | 0% | 1,287 | 8,499 | +560% | 0 | 0 | — |
case-14 | fail→pass | 15,726 | 30,899 | +96% | 1 | 1 | 0% | 2,118 | 10,369 | +390% | 0 | 0 | — |
case-15 | fail→pass | 11,916 | 10,645 | -11% | 1 | 1 | 0% | 1,923 | 8,662 | +350% | 0 | 0 | — |
case-16 | fail→pass | 13,043 | 31,947 | +145% | 1 | 1 | 0% | 1,403 | 8,893 | +534% | 0 | 0 | — |
case-17 | pass→fail | 10,789 | 23,145 | +115% | 1 | 1 | 0% | 1,968 | 8,501 | +332% | 0 | 0 | — |
case-18 | fail→pass | 11,714 | 10,040 | -14% | 1 | 1 | 0% | 916 | 8,052 | +779% | 0 | 0 | — |
case-19 | fail→pass | 12,829 | 15,330 | +19% | 1 | 1 | 0% | 1,563 | 9,249 | +492% | 0 | 0 | — |
case-20 | pass→pass | 12,828 | 9,040 | -30% | 1 | 1 | 0% | 2,234 | 8,278 | +271% | 0 | 0 | — |
case-21 | fail→pass | 15,241 | 10,786 | -29% | 1 | 1 | 0% | 1,359 | 8,298 | +511% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 18 counted toward the lift figure. The other 4 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +50 percentage points is the difference between those two pass rates over the 18 comparable cases. 2 cases got worse with the skill loaded, and they are included in that figure.
The publisher has shipped newer versions since this run, so these numbers describe v3, not the version currently listed.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.