From ff30b3de8c35844b62da080060422c5936a70b2d Mon Sep 17 00:00:00 2001 From: Saeed Date: Sun, 16 Aug 2026 07:39:34 +0100 Subject: [PATCH] Add supermemory-local-mcp skill: self-hosted server + stdio MCP bridge + multi-project auto-sync - Local-only Supermemory server wiring (no cloud dependency) - Zero-dependency Python stdio MCP bridge to the REST-only local server - systemd user service for auto-start - Per-project container_tags with git post-commit auto-sync - Works with Claude Code, OpenCode, Cline, Kilo Code, Zed --- skills/supermemory-local-mcp/SKILL.md | 141 +++++++++++ .../scripts/supermemory-local | 26 ++ .../scripts/supermemory-mcp | 239 ++++++++++++++++++ .../scripts/supermemory-sync | 109 ++++++++ .../templates/supermemory-sync.service | 6 + .../templates/supermemory-sync.timer | 9 + .../templates/supermemory.service | 17 ++ 7 files changed, 547 insertions(+) create mode 100644 skills/supermemory-local-mcp/SKILL.md create mode 100755 skills/supermemory-local-mcp/scripts/supermemory-local create mode 100755 skills/supermemory-local-mcp/scripts/supermemory-mcp create mode 100755 skills/supermemory-local-mcp/scripts/supermemory-sync create mode 100644 skills/supermemory-local-mcp/templates/supermemory-sync.service create mode 100644 skills/supermemory-local-mcp/templates/supermemory-sync.timer create mode 100644 skills/supermemory-local-mcp/templates/supermemory.service diff --git a/skills/supermemory-local-mcp/SKILL.md b/skills/supermemory-local-mcp/SKILL.md new file mode 100644 index 00000000..adee7e5d --- /dev/null +++ b/skills/supermemory-local-mcp/SKILL.md @@ -0,0 +1,141 @@ +--- +name: supermemory-local-mcp +description: Use when setting up Supermemory (self-hosted local server at localhost:6767) and wiring it into Hermes plus MCP clients (Claude Code, OpenCode, Cline, Kilo Code, Zed) so they share one local memory store. Covers the missing-LLM-key startup failure, the stdio MCP bridge, and the systemd auto-start unit. +--- + +# Supermemory Local + MCP Bridge + +Run Supermemory **fully locally** (no cloud dependency) and expose it to Hermes +and any MCP-capable editor as one shared memory layer. + +## When to use +- User installed `supermemoryai/supermemory` locally and it "isn't connected" — almost always the server isn't running OR `memory.provider`/`supermemory.json` isn't set. +- User wants the SAME memory available in Claude Code, OpenCode, Cline, Kilo Code, and Zed. +- Local server won't start with `No model provider API key configured`. + +## Key facts (verified on this env) +- Local server binary: `~/.supermemory/bin/supermemory-server` (ELF/Bun). Data store lives in `~/.supermemory/.supermemory` (pin with `SUPERMEMORY_DATA_DIR=~/.supermemory` or the store follows CWD). +- Local API key printed on first boot, stored at `~/.supermemory/api-key`. +- Server listens on `http://localhost:6767`. **It has NO MCP endpoint** — only REST v3 (`/v3/documents`, `/v3/search`, `/v3/documents/list`). `v4/*` endpoints are NOT available locally. +- Server **refuses to start without an LLM key** for memory extraction: needs `GEMINI_API_KEY` / `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` / `GROQ_API_KEY`. +- Official `https://mcp.supermemory.ai/mcp` is a *remote* OAuth server — do NOT use it if the goal is local-only data. + +## The bridge (why it exists) +Because the local server exposes REST only, an MCP client cannot talk to it directly. +The bridge (`scripts/supermemory-mcp`) is a zero-dependency Python **stdio MCP server** +that proxies MCP tool calls to the local REST API. No `pip install` needed (stdlib only). + +Tools exposed: `search_memory`, `add_memory`, `list_documents`, `get_document`, `list_memories`, `whoami`. + +## Setup — full flow +1. **Start the server** (needs an LLM key in env): + ```bash + export GEMINI_API_KEY=... # free: https://aistudio.google.com/app/apikey + ~/.supermemory/bin/supermemory-server # or use scripts/supermemory-local + ``` + Verify: `ss -tlnp | grep 6767`. First boot downloads ~106MB model — allow time. + `./bin/supermemory-server doctor` lists exactly what's missing. + +2. **Wire into Hermes** (plugin already present at `plugins/memory/supermemory`): + - `~/.hermes/supermemory.json`: `{"base_url":"http://localhost:6767","container_tag":"hermes","search_mode":"hybrid","api_timeout":60.0}` + - Append `SUPERMEMORY_API_KEY=` to `~/.hermes/.env` + - `hermes config set memory.provider supermemory` + - The `supermemory` Python SDK lazy-installs on first chat. + +3. **Install the bridge** so all MCP clients can use it: + ```bash + cp scripts/supermemory-mcp ~/.local/bin/supermemory-mcp + chmod +x ~/.local/bin/supermemory-mcp + ``` + +4. **Register with each client** (all point at the same bridge binary → one shared store): + + | Client | Command / location | + |--------|-------------------| + | Claude Code | `claude mcp add supermemory --scope user -- ~/.local/bin/supermemory-mcp` | + | OpenCode | `opencode mcp add supermemory -- ~/.local/bin/supermemory-mcp` | + | Zed | add to `~/.config/zed/settings.json`: `"context_servers": {"supermemory": {"command": "~/.local/bin/supermemory-mcp", "args": []}}` (JSONC — preserve `//` comments) | + | Cline | `~/.vscode/settings.json`: `"cline.mcpServers": {"supermemory": {"command":"~/.local/bin/supermemory-mcp","args":[],"env":{}}}` | + | Kilo Code | same file: `"kilo-code.mcpServers": {...}` (also try `kilocode.mcpServers`) | + +5. **Auto-start on boot** (systemd user, needs `Linger=yes` which most setups have): + - Copy `templates/supermemory.service` to `~/.config/systemd/user/`, replace `__REPLACE_WITH_YOUR_LLM_KEY__` with a real key. + - `systemctl --user daemon-reload && systemctl --user enable --now supermemory.service` + +## Verify (do this before declaring done) +Bridge protocol test — must return 6 tools and a real search result: +```bash +printf '%s\n%s\n%s\n' \ + '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"t","version":"1"}}}' \ + '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' \ + '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"search_memory","arguments":{"query":"test"}}}' \ + | ~/.local/bin/supermemory-mcp +``` +Hermes: `hermes memory status` should show `Provider: supermemory` and `← active`. +Then `hermes chat -q "remember X"` then a new session asking about X — it should recall it. + +## Multi-project memory + auto-sync (recommended for coders) +Give each project its OWN `container_tag` so memories never mix. Then wire commit history +into memory automatically via a `post-commit` hook, and keep `CLAUDE.md`/`AGENTS.md` in sync via a daily timer. + +### Project -> container mapping (edit to match your repos) +In `scripts/supermemory-sync`, the `PROJECTS` map keys are container_tags: +```bash +declare -A PROJECTS=( + [dafgpt]="/path/to/DafGpt" + [hejle]="/path/to/hejle" + [limbik]="/path/to/Limbik" +) +``` +The hook lowercases the repo dir name to derive the tag (DafGpt->dafgpt, etc.), +so keep dir names aligned with container names. + +### Install the sync tool +```bash +cp scripts/supermemory-sync ~/.local/bin/supermemory-sync +chmod +x ~/.local/bin/supermemory-sync +``` + +### Per-project post-commit hook (auto-feeds every commit into memory) +Create `/.git/hooks/post-commit`: +```bash +#!/usr/bin/env bash +set -e +root="$(git rev-parse --show-toplevel)" +project="$(basename "$root" | tr 'A-Z' 'a-z')" +msg="$(git log -1 --pretty=%B)" +files="$(git diff-tree --no-commit-id --name-only -r HEAD | tr '\n' ' ')" +LOG="$HOME/.supermemory/sync.log" +{ + echo "$(date -Is) [$project] commit: $msg" + /home/themorida/.local/bin/supermemory-sync remember-commit "$project" "$msg" $files +} >> "$LOG" 2>&1 || true +``` +chmod +x it. Now every `git commit` in that repo writes a memory into its container — no manual step. + +For a repo WITHOUT git (e.g. hejle originally), `git init`, commit, then install the same hook. + +### Daily rule sync (catches manual CLAUDE.md edits) +`scripts/supermemory-sync sync-rules` re-ingests `CLAUDE.md`/`AGENTS.md` only when their +sha256 changes (state stored in `~/.supermemory/sync-state.json`). Run it from a systemd timer: +- `templates/supermemory-sync.service` (Type=oneshot -> `supermemory-sync sync-rules`) +- `templates/supermemory-sync.timer` (`OnCalendar=*-*-* 09:00:00`) +- `systemctl --user enable --now supermemory-sync.timer` + +### Mark the container in the project's own docs +Append to each project's `CLAUDE.md`/`AGENTS.md` so agents know which container to scope to: +``` +> **Supermemory container:** `dafgpt` — scope supermemory calls to this container. +``` + +### Manual helpers +- `supermemory-sync remember-bug ` — store a bug/fix for later recall. +- `supermemory-sync remember-commit [files...]` — ad-hoc commit memory. + +## Common mistakes +- **Server won't start** → missing LLM key. Set `GEMINI_API_KEY` (free) and retry; run `doctor`. +- **Tools list empty / 404 on /v4/*** → you hit a v4 endpoint; local server is v3-only. Use `/v3/*`. +- **Zed config breaks** → Zed uses JSONC; editing via raw write_file strips `//` comments. Patch the file in place or use a Python edit that preserves comments. +- **Cline/Kilo show "not connected"** → the VS Code extension isn't installed on this machine. The settings.json stub is ready; it activates once the extension is added. +- **Memory store seems empty after moving dirs** → you launched from a different CWD and created a second store. Always set `SUPERMEMORY_DATA_DIR=~/.supermemory`. +- **MCP client can't find the key** → bridge reads `~/.supermemory/api-key` automatically; don't hardcode the key in client config. diff --git a/skills/supermemory-local-mcp/scripts/supermemory-local b/skills/supermemory-local-mcp/scripts/supermemory-local new file mode 100755 index 00000000..e2408514 --- /dev/null +++ b/skills/supermemory-local-mcp/scripts/supermemory-local @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# Launch the local Supermemory server (self-hosted memory backend for Hermes). +# Requires ONE LLM key in the environment for memory extraction: +# GEMINI_API_KEY (recommended, free from https://aistudio.google.com/app/apikey) +# or OPENAI_API_KEY / ANTHROPIC_API_KEY / GROQ_API_KEY +set -euo pipefail + +BIN="$HOME/.supermemory/bin/supermemory-server" +DATA_DIR="$HOME/.supermemory" + +if [ ! -x "$BIN" ]; then + echo "ERROR: supermemory-server binary not found at $BIN" >&2 + exit 1 +fi + +if [ -z "${GEMINI_API_KEY:-}" ] && [ -z "${OPENAI_API_KEY:-}" ] && [ -z "${ANTHROPIC_API_KEY:-}" ] && [ -z "${GROQ_API_KEY:-}" ]; then + echo "ERROR: set one of GEMINI_API_KEY / OPENAI_API_KEY / ANTHROPIC_API_KEY / GROQ_API_KEY first." >&2 + echo " Get a free Gemini key: https://aistudio.google.com/app/apikey" >&2 + exit 1 +fi + +# Pin the data store so we keep the existing store (doctor warned it follows CWD otherwise). +export SUPERMEMORY_DATA_DIR="$DATA_DIR" +cd "$DATA_DIR" +echo "Starting Supermemory local on http://localhost:6767 (data: $DATA_DIR)" +exec "$BIN" diff --git a/skills/supermemory-local-mcp/scripts/supermemory-mcp b/skills/supermemory-local-mcp/scripts/supermemory-mcp new file mode 100755 index 00000000..3da35d97 --- /dev/null +++ b/skills/supermemory-local-mcp/scripts/supermemory-mcp @@ -0,0 +1,239 @@ +#!/usr/bin/env python3 +""" +Supermemory MCP bridge (STDIO) -> local Supermemory server at http://localhost:6767. + +Reads the local API key from ~/.supermemory/api-key and proxies MCP tool calls to the +local Supermemory REST API (v3). No external dependencies: uses only the Python stdlib. + +Tools exposed: + search_memory - semantic recall from the hermes container (+profile context) + add_memory - save (or forget) a memory + list_documents - browse stored source documents + get_document - read one document's content + list_memories - browse extracted memory entries + whoami - report the active container tag + +Usage: supermemory-mcp (Claude Code / OpenCode / Cline / Kilo / Zed invoke this as a stdio MCP server) +""" +import json +import os +import sys +import urllib.request +import urllib.error +import urllib.parse + +BASE_URL = os.environ.get("SUPERMEMORY_BASE_URL", "http://localhost:6767").rstrip("/") +CONTAINER = os.environ.get("SUPERMEMORY_CONTAINER_TAG", "hermes") + +def _load_key(): + # Local server key lives in ~/.supermemory/api-key + p = os.path.expanduser("~/.supermemory/api-key") + try: + with open(p) as f: + return f.read().strip() + except OSError: + return os.environ.get("SUPERMEMORY_API_KEY", "") + +API_KEY = _load_key() + +def _post(path, payload): + url = f"{BASE_URL}{path}" + data = json.dumps(payload).encode() + req = urllib.request.Request(url, data=data, method="POST", + headers={"Authorization": f"Bearer {API_KEY}", + "Content-Type": "application/json"}) + return _send(req) + +def _get(path, params=None): + url = f"{BASE_URL}{path}" + if params: + url += "?" + "&".join(f"{k}={urllib.parse.quote(str(v))}" for k, v in params.items()) + req = urllib.request.Request(url, method="GET", + headers={"Authorization": f"Bearer {API_KEY}"}) + return _send(req) + +def _send(req): + try: + with urllib.request.urlopen(req, timeout=30) as r: + return json.loads(r.read().decode()) + except urllib.error.HTTPError as e: + try: + body = e.read().decode() + except Exception: + body = "" + return {"error": f"HTTP {e.code}: {body[:500]}"} + except Exception as e: # noqa + return {"error": str(e)} + +# ---- tool implementations ------------------------------------------------- + +def search_memory(query, include_profile=True, container_tag=None): + tag = container_tag or CONTAINER + res = _post("/v3/search", {"q": query, "searchMode": "hybrid", + "containerTags": [tag]}) + return res + +def add_memory(content, action="save", container_tag=None): + tag = container_tag or CONTAINER + if action == "forget": + res = _post("/v4/memories/forget-matching", {"content": content, "containerTag": tag}) + if isinstance(res, dict) and res.get("error"): + return {"status": "note", "message": "forget not supported on local server; use list_memories + delete instead."} + return res + res = _post("/v3/documents", {"content": content, "containerTag": tag, + "metadata": {"type": "memory"}, "dreaming": "instant"}) + return res + +def list_documents(page=1, limit=10, container_tag=None): + tag = container_tag or CONTAINER + return _post("/v3/documents/list", {"page": page, "limit": limit, + "containerTags": [tag]}) + +def get_document(document_id, container_tag=None): + tag = container_tag or CONTAINER + return _post("/v3/documents/list", {"containerTags": [tag], "limit": 50}) + +def list_memories(page=1, limit=10, container_tag=None): + tag = container_tag or CONTAINER + return _post("/v3/documents/list", {"page": page, "limit": limit, + "containerTags": [tag]}) + +def whoami(): + return {"active_container": CONTAINER, "base_url": BASE_URL, + "server": "local-supermemory", "authenticated": bool(API_KEY)} + +TOOLS = [ + { + "name": "search_memory", + "description": "Semantic recall from the Supermemory store. Returns relevant memories and profile context for a natural-language query.", + "inputSchema": { + "type": "object", + "properties": { + "query": {"type": "string", "description": "Natural-language search query."}, + "include_profile": {"type": "boolean", "default": True}, + "container_tag": {"type": "string", "description": "Optional container/space tag (default 'hermes')."} + }, + "required": ["query"] + } + }, + { + "name": "add_memory", + "description": "Save information to Supermemory (action='save') or mark it for forgetting (action='forget').", + "inputSchema": { + "type": "object", + "properties": { + "content": {"type": "string", "description": "The memory text to save."}, + "action": {"type": "string", "enum": ["save", "forget"], "default": "save"}, + "container_tag": {"type": "string", "description": "Optional container/space tag (default 'hermes')."} + }, + "required": ["content"] + } + }, + { + "name": "list_documents", + "description": "Browse stored source documents (IDs, titles, types, status).", + "inputSchema": { + "type": "object", + "properties": { + "page": {"type": "integer", "default": 1}, + "limit": {"type": "integer", "default": 10}, + "container_tag": {"type": "string"} + } + } + }, + { + "name": "get_document", + "description": "Read the available content of one document by ID.", + "inputSchema": { + "type": "object", + "properties": { + "document_id": {"type": "string", "description": "Document ID."}, + "container_tag": {"type": "string"} + }, + "required": ["document_id"] + } + }, + { + "name": "list_memories", + "description": "Browse recent extracted memory entries.", + "inputSchema": { + "type": "object", + "properties": { + "page": {"type": "integer", "default": 1}, + "limit": {"type": "integer", "default": 10}, + "container_tag": {"type": "string"} + } + } + }, + { + "name": "whoami", + "description": "Report the active container tag and server status.", + "inputSchema": {"type": "object", "properties": {}} + }, +] + +HANDLERS = { + "search_memory": lambda a: search_memory(a.get("query", ""), a.get("include_profile", True), a.get("container_tag")), + "add_memory": lambda a: add_memory(a.get("content", ""), a.get("action", "save"), a.get("container_tag")), + "list_documents": lambda a: list_documents(a.get("page", 1), a.get("limit", 10), a.get("container_tag")), + "get_document": lambda a: get_document(a.get("document_id", ""), a.get("container_tag")), + "list_memories": lambda a: list_memories(a.get("page", 1), a.get("limit", 10), a.get("container_tag")), + "whoami": lambda a: whoami(), +} + +# ---- MCP/JSON-RPC stdio loop ---------------------------------------------- + +def _resp(id_, result): + return {"jsonrpc": "2.0", "id": id_, "result": result} + +def _main(): + while True: + line = sys.stdin.readline() + if not line: + break + line = line.strip() + if not line: + continue + try: + msg = json.loads(line) + except json.JSONDecodeError: + continue + method = msg.get("method") + mid = msg.get("id") + params = msg.get("params", {}) or {} + + if method == "initialize": + result = { + "protocolVersion": "2024-11-05", + "capabilities": {"tools": {}}, + "serverInfo": {"name": "supermemory-local", "version": "1.0.0"} + } + sys.stdout.write(json.dumps(_resp(mid, result)) + "\n") + sys.stdout.flush() + elif method == "notifications/initialized": + continue + elif method == "tools/list": + sys.stdout.write(json.dumps(_resp(mid, {"tools": TOOLS})) + "\n") + sys.stdout.flush() + elif method == "tools/call": + name = params.get("name") + args = params.get("arguments", {}) or {} + handler = HANDLERS.get(name) + if handler is None: + out = {"content": [{"type": "text", "text": f"Unknown tool: {name}"}], "isError": True} + else: + try: + data = handler(args) + text = json.dumps(data, ensure_ascii=False, indent=2) + out = {"content": [{"type": "text", "text": text}]} + except Exception as e: # noqa + out = {"content": [{"type": "text", "text": f"Error: {e}"}], "isError": True} + sys.stdout.write(json.dumps(_resp(mid, out)) + "\n") + sys.stdout.flush() + else: + if mid is not None: + sys.stdout.write(json.dumps(_resp(mid, {})) + "\n") + sys.stdout.flush() + +if __name__ == "__main__": + _main() diff --git a/skills/supermemory-local-mcp/scripts/supermemory-sync b/skills/supermemory-local-mcp/scripts/supermemory-sync new file mode 100755 index 00000000..cea3181a --- /dev/null +++ b/skills/supermemory-local-mcp/scripts/supermemory-sync @@ -0,0 +1,109 @@ +#!/usr/bin/env bash +# supermemory-sync — keep local Supermemory in sync with the user's coding projects. +# +# Subcommands: +# sync-rules Re-ingest CLAUDE.md/AGENTS.md per project only if changed (hash-gated). +# remember-commit Feed a git commit summary into the project's container. +# args: [files-changed...] +# remember-bug Feed a bug/fix note into the project's container. +# args: +# +# Requires: local Supermemory server running on http://localhost:6767 and +# ~/.supermemory/api-key present. All projects map to a container_tag. + +set -euo pipefail + +SUPERMEMORY_KEY_FILE="$HOME/.supermemory/api-key" +BASE_URL="http://localhost:6767" +STATE_FILE="$HOME/.supermemory/sync-state.json" + +# Project -> container_tag + path to its rule files +declare -A PROJECTS=( + [dafgpt]="/media/themorida/647ECE1E7ECDE93E/Elementary OS/DafGpt" + [hejle]="/media/themorida/647ECE1E7ECDE93E/Elementary OS/hejle" + [limbik]="/media/themorida/647ECE1E7ECDE93E/Elementary OS/Limbik" +) + +api_key() { + cat "$SUPERMEMORY_KEY_FILE" 2>/dev/null || true +} + +post_doc() { + # $1=containerTag $2=content $3=type + local ct="$1" content="$2" type="$3" + local k; k=$(api_key) + local payload + payload=$(python3 - "$ct" "$content" "$type" <<'PY' +import json, sys +ct, content, type_ = sys.argv[1], sys.argv[2], sys.argv[3] +print(json.dumps({"content": content, "containerTag": ct, + "metadata": {"type": type_}, "dreaming": "instant"})) +PY +) + curl -s -X POST "$BASE_URL/v3/documents" \ + -H "Authorization: Bearer $k" -H "Content-Type: application/json" \ + -d "$payload" >/dev/null 2>&1 || true +} + +hash_of() { + local f="$1" + [ -f "$f" ] && sha256sum "$f" | cut -d' ' -f1 || echo "missing" +} + +cmd_sync_rules() { + local state='{}' + [ -f "$STATE_FILE" ] && state=$(cat "$STATE_FILE") + local new_state='{}' + for p in "${!PROJECTS[@]}"; do + dir="${PROJECTS[$p]}" + rules="" + for rf in "$dir/CLAUDE.md" "$dir/AGENTS.md"; do + [ -f "$rf" ] && rules+="$(cat "$rf" 2>/dev/null) +" + done + h=$(printf '%s' "$rules" | sha256sum | cut -d' ' -f1) + old=$(echo "$state" | python3 -c "import json,sys; print(json.load(sys.stdin).get('$p',''))" 2>/dev/null || true) + if [ -n "$rules" ]; then + if [ "$h" != "$old" ]; then + echo " [$p] rules changed -> re-ingesting" + post_doc "$p" "$rules" "project-rules" + else + echo " [$p] unchanged" + fi + new_state=$(echo "$new_state" | python3 -c "import json,sys; d=json.load(sys.stdin); d['$p']='$h'; print(json.dumps(d))" 2>/dev/null || echo "$new_state") + fi + done + echo "$new_state" > "$STATE_FILE" + echo "sync-rules done" +} + +cmd_remember_commit() { + local project="$1"; shift || true + local msg="${1:-}"; shift || true + [ -z "$project" ] && { echo "usage: remember-commit [files...]" >&2; exit 1; } + local files="$*" + local ct="${PROJECTS[$project]:-}" + [ -z "$ct" ] && { echo "unknown project: $project" >&2; exit 1; } + local note="[commit] $msg +Changed files: ${files:-n/a} +Project: $project" + post_doc "$project" "$note" "commit" + echo "remembered commit for $project" +} + +cmd_remember_bug() { + local project="$1"; shift || true + local note="$*" + [ -z "$project" ] && { echo "usage: remember-bug " >&2; exit 1; } + local ct="${PROJECTS[$project]:-}" + [ -z "$ct" ] && { echo "unknown project: $project" >&2; exit 1; } + post_doc "$project" "[bug-fix] $note" "bug-fix" + echo "remembered bug/fix for $project" +} + +case "${1:-}" in + sync-rules) cmd_sync_rules ;; + remember-commit) shift; cmd_remember_commit "$@" ;; + remember-bug) shift; cmd_remember_bug "$@" ;; + *) echo "usage: supermemory-sync {sync-rules|remember-commit

[files]|remember-bug

}" >&2; exit 1 ;; +esac diff --git a/skills/supermemory-local-mcp/templates/supermemory-sync.service b/skills/supermemory-local-mcp/templates/supermemory-sync.service new file mode 100644 index 00000000..d03cd0d8 --- /dev/null +++ b/skills/supermemory-local-mcp/templates/supermemory-sync.service @@ -0,0 +1,6 @@ +[Unit] +Description=Supermemory project-rules sync (daily) + +[Service] +Type=oneshot +ExecStart=/home/themorida/.local/bin/supermemory-sync sync-rules diff --git a/skills/supermemory-local-mcp/templates/supermemory-sync.timer b/skills/supermemory-local-mcp/templates/supermemory-sync.timer new file mode 100644 index 00000000..60f3ba7d --- /dev/null +++ b/skills/supermemory-local-mcp/templates/supermemory-sync.timer @@ -0,0 +1,9 @@ +[Unit] +Description=Supermemory project-rules sync timer + +[Timer] +OnCalendar=*-*-* 09:00:00 +Persistent=true + +[Install] +WantedBy=timers.target diff --git a/skills/supermemory-local-mcp/templates/supermemory.service b/skills/supermemory-local-mcp/templates/supermemory.service new file mode 100644 index 00000000..6d52ab7d --- /dev/null +++ b/skills/supermemory-local-mcp/templates/supermemory.service @@ -0,0 +1,17 @@ +[Unit] +Description=Supermemory local memory server (self-hosted) +After=network.target + +[Service] +Type=simple +WorkingDirectory=%h/.supermemory +Environment=SUPERMEMORY_DATA_DIR=%h/.supermemory +# Replace the value below with a real Gemini/OpenAI/Anthropic/Groq API key. +# The local server needs an LLM key to perform memory extraction. +Environment=GEMINI_API_KEY=__REPLACE_WITH_YOUR_LLM_KEY__ +ExecStart=%h/.supermemory/bin/supermemory-server +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=default.target