From nanotars-claude-mem
Adds persistent claude-mem to NanoTars agent Docker containers by creating systemd worker daemon service and configuring env vars. Run once after claude-mem plugin install.
npx claudepluginhub terrifiedbug/nanotars-skills --plugin nanotars-claude-memThis skill uses the workspace's default tool permissions.
Run all commands automatically. Only pause if a step fails.
Automates Mem9 persistent memory setup in Claude Code: checks config, provisions tenant, updates settings.json, installs mem9 plugin. Restart to activate.
Guides installation, configuration, self-bootstrapping, troubleshooting, and operation of Mnemos for persistent scoped agent memory in Claude Code, OpenClaw, Cursor, Codex, and MCP hosts.
Guides setup, configuration, customization, and debugging of NanoClaw, a lightweight containerized Claude AI assistant for WhatsApp, Telegram, Slack, Discord, Gmail with per-group memory and scheduled jobs.
Share bugs, ideas, or general feedback.
Run all commands automatically. Only pause if a step fails.
UX Note: When asking the user questions, prefer using the AskUserQuestion tool instead of just outputting text.
The claude-mem worker daemon runs on the host (port 37777, bound to 0.0.0.0) and stores observations in a SQLite + vector DB at /root/.claude-mem/. Docker containers reach the host via host.docker.internal using the --add-host=host.docker.internal:host-gateway flag (configured in container-runtime.ts).
Before installing, verify NanoTars is set up:
[ -d node_modules ] && echo "DEPS: ok" || echo "DEPS: missing"
docker image inspect nanoclaw-agent:latest &>/dev/null && echo "IMAGE: ok" || echo "IMAGE: not built"
if grep -q "ANTHROPIC_API_KEY\|CLAUDE_CODE_OAUTH_TOKEN" .env 2>/dev/null || [ -f "$HOME/.claude/.credentials.json" ]; then echo "AUTH: ok"; else echo "AUTH: missing"; fi
If any check fails, tell the user to run /nanotars-setup first and stop.
claude plugin add @thedotmack/claude-mem)Verify prerequisites:
ls /root/.claude-mem/claude-mem.db
ls /root/.claude/plugins/cache/thedotmack/claude-mem/*/scripts/worker-service.cjs 2>/dev/null | head -1
BUN_PATH=$(which bun 2>/dev/null || echo "/root/.bun/bin/bun")
$BUN_PATH --version
If the database does not exist, stop and tell the user to install claude-mem first.
Kill orphaned worker processes:
pkill -f 'worker-service.cjs.*--daemon' 2>/dev/null || true
sleep 2
curl -s --max-time 2 http://127.0.0.1:37777/api/health >/dev/null 2>&1 && echo "WARNING: Port 37777 still in use" || echo "Port 37777 is free"
Create wrapper scripts at /root/.claude-mem/:
/root/.claude-mem/run-worker.sh:
#!/bin/bash
PLUGIN_DIR="/root/.claude/plugins/cache/thedotmack/claude-mem"
WORKER=$(ls -td "$PLUGIN_DIR"/*/scripts/worker-service.cjs 2>/dev/null | head -1)
if [ -z "$WORKER" ]; then
echo "Error: claude-mem worker script not found in $PLUGIN_DIR" >&2
exit 1
fi
echo "Starting worker from: $WORKER"
exec /root/.bun/bin/bun "$WORKER" start
/root/.claude-mem/stop-worker.sh:
#!/bin/bash
PLUGIN_DIR="/root/.claude/plugins/cache/thedotmack/claude-mem"
WORKER=$(ls -td "$PLUGIN_DIR"/*/scripts/worker-service.cjs 2>/dev/null | head -1)
if [ -z "$WORKER" ]; then
curl -s -X POST http://127.0.0.1:37777/api/admin/shutdown 2>/dev/null
exit 0
fi
exec /root/.bun/bin/bun "$WORKER" stop
Make executable: chmod +x /root/.claude-mem/run-worker.sh /root/.claude-mem/stop-worker.sh
Create systemd service for claude-mem worker at /etc/systemd/system/claude-mem-worker.service:
[Unit]
Description=Claude-Mem Worker Daemon
After=network.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/root/.claude-mem/run-worker.sh
ExecStop=/root/.claude-mem/stop-worker.sh
WorkingDirectory=/root/.claude-mem
Environment=HOME=/root
Environment=PATH=/root/.bun/bin:/root/.local/bin:/usr/local/bin:/usr/bin:/bin
[Install]
WantedBy=multi-user.target
Enable and start service:
systemctl daemon-reload
systemctl enable claude-mem-worker
systemctl start claude-mem-worker
sleep 3
curl -s http://127.0.0.1:37777/api/health
Test connectivity from a container:
docker run --rm --add-host=host.docker.internal:host-gateway \
--entrypoint node nanoclaw-agent:latest \
-e "fetch('http://host.docker.internal:37777/api/health').then(r=>r.json()).then(d=>console.log('OK:',JSON.stringify(d))).catch(e=>console.error('FAIL:',e.message))"
Add environment variable:
grep -q "^CLAUDE_MEM_URL=" .env 2>/dev/null || echo "CLAUDE_MEM_URL=http://host.docker.internal:37777" >> .env
Copy plugin files:
cp -r ${CLAUDE_PLUGIN_ROOT}/files/ plugins/claude-mem/
Plugin Configuration: By default this plugin is available to all groups and channel types. To restrict access, edit plugins/claude-mem/plugin.json and set:
"groups" to specific group folder names (e.g., ["main"]) instead of ["*"]"channels" to specific channel types (e.g., ["whatsapp"]) instead of ["*"]Ask the user if they want to restrict access. Most users will keep the defaults.
Rebuild and restart:
npm run build
nanotars restart
Tell the user:
Setup is complete. Test it by sending a WhatsApp message like "remember that my favorite coffee is a flat white" and then in a new conversation ask "what's my favorite coffee?"
The wrapper scripts dynamically resolve the plugin version at runtime. After upgrading:
systemctl stop claude-mem-worker
pkill -f 'worker-service.cjs' 2>/dev/null; sleep 2
systemctl start claude-mem-worker
journalctl -u claude-mem-worker -f and check /root/.claude-mem/logs/--add-host=host.docker.internal:host-gateway is in container-runtime.ts extraRunArgs()lsof -i :37777 -- kill orphaned workers firstsystemctl status claude-mem-workerPer-group credential overrides: Not applicable. Claude-mem is a system-wide service shared across all groups.
Stop the service:
sudo systemctl stop claude-mem-worker
sudo systemctl disable claude-mem-worker
Remove the plugin:
rm -rf plugins/claude-mem/
Remove CLAUDE_MEM_URL from .env
Rebuild and restart NanoTars
Warning: Do NOT delete /root/.claude-mem/. This directory contains the shared memory database used by both the host and container agents. Removing the plugin only stops container access — the host's claude-mem continues to function independently.