{"id":"a4bab889-f7d2-457c-bb37-2d9b51428dbe","slug":"scallopbot","kind":"mcp","name":"scallopbot","summary":"Self-hosted personal AI assistant with MCP-native, bio-inspired memory. OpenClaw-compatible skills. LoCoMo F1 0.48 vs 0.38.","owner":"tashfeenahmed","repoUrl":"https://github.com/tashfeenahmed/scallopbot","license":"MIT","licenseTier":"permissive","trust":"community","stars":47,"match":null,"fewStars":false,"format":"mcp","createdAt":"2026-02-01T19:58:04.000Z","addedAt":"2026-10-14T05:42:41.321Z","logoUrl":"https://avatars.githubusercontent.com/u/9307356?u=767af9ef0173d08641a20511cf920aa1fd9d7455&v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["memory-knowledge"],"tags":["ai","anthropic","llm","openai","self-hosted","openclaw","agent-memory","bio-inspired"],"runtime":"node","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-17T06:30:50.980Z","sample":false,"url":"https://conduits.dev/tools/scallopbot","language":"TypeScript","transports":["stdio"],"install":{"npm":"scallopbot"},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"<p align=\"center\">\n  <picture>\n    <source media=\"(prefers-color-scheme: dark)\" srcset=\"assets/logo-dark.svg\">\n    <img src=\"assets/logo-light.svg\" alt=\"ScallopBot\" width=\"120\" height=\"120\">\n  </picture>\n</p>\n\n<h1 align=\"center\">ScallopBot</h1>\n\n<p align=\"center\">\n  <strong>Personal AI memory that actually remembers.</strong><br>\n  <em>A lightweight, self-hosted AI agent that cures your agent's amnesia.</em>\n</p>\n\n<p align=\"center\">\n  <a href=\"https://github.com/tashfeenahmed/scallopbot/actions/workflows/ci.yml\"><img src=\"https://img.shields.io/github/actions/workflow/status/tashfeenahmed/scallopbot/ci.yml?branch=main&style=for-the-badge&label=build\" alt=\"CI status\"></a>\n  <a href=\"https://github.com/tashfeenahmed/scallopbot/releases\"><img src=\"https://img.shields.io/github/v/release/tashfeenahmed/scallopbot?style=for-the-badge\" alt=\"GitHub release\"></a>\n  <a href=\"LICENSE\"><img src=\"https://img.shields.io/badge/License-MIT-blue.svg?style=for-the-badge\" alt=\"MIT License\"></a>\n  <a href=\"https://nodejs.org\"><img src=\"https://img.shields.io/badge/node-%3E%3D24-brightgreen?style=for-the-badge\" alt=\"Node.js\"></a>\n  <a href=\"https://github.com/tashfeenahmed/scallopbot/stargazers\"><img src=\"https://img.shields.io/github/stars/tashfeenahmed/scallopbot?style=for-the-badge\" alt=\"GitHub stars\"></a>\n  <a href=\"https://github.com/tashfeenahmed/scallopbot/forks\"><img src=\"https://img.shields.io/github/forks/tashfeenahmed/scallopbot?style=for-the-badge\" alt=\"GitHub forks\"></a>\n</p>\n\n<p align=\"center\">\n  <a href=\"#install\"><strong>Install</strong></a> ·\n  <a href=\"#benchmark-results\"><strong>Benchmarks</strong></a> ·\n  <a href=\"#how-it-fits-together\"><strong>Architecture</strong></a> ·\n  <a href=\"#hybrid-memory-engine\"><strong>Memory</strong></a> ·\n  <a href=\"https://scallopbot.com\"><strong>Website</strong></a> ·\n  <a href=\"Paper2026.pdf\"><strong>Paper</strong></a>\n</p>\n\n---\n\nScallopBot is a personal AI agent that runs on your own server. Open-source agents like [OpenClaw](https://github.com/openclaw/openclaw) are good at tool orchestration, but their memory mostly stores and promotes notes rather than reshaping them, and they have no self-reflection or autonomous reasoning loop. ScallopBot adds a bio-inspired cognitive layer on top, stays compatible with the OpenClaw skill ecosystem, and runs at an estimated **$0.05–0.10 a day** in model spend ([cost comparison](https://scallopbot.com/cost)).\n\n<table>\n  <tr>\n    <td width=\"33%\" valign=\"top\"><h3>🧠 Memory that changes</h3>Memories are fused, linked and forgotten over time, not only stored. Recall mixes BM25, embeddings and optional LLM re-ranking.</td>\n    <td width=\"33%\" valign=\"top\"><h3>🌙 Works while you sleep</h3>A background gardener runs decay every minute, audits every ~72 minutes, and a nightly dream cycle, self-reflection and gap scan.</td>\n    <td width=\"33%\" valign=\"top\"><h3>🛡️ Checks its own work</h3>Before a turn that changed files ends, a fresh-context reviewer probes the result on a throwaway copy and hands back anything it reproduces.</td>\n  </tr>\n  <tr>\n    <td valign=\"top\"><h3>💸 Routes by cost</h3>Each request goes to the cheapest tier that can handle it, every call is priced per token, and daily/monthly budgets stop spend before it happens.</td>\n    <td valign=\"top\"><h3>🔌 MCP both ways</h3>Uses any MCP server, and serves its own memory over MCP so Claude Code, Codex or any MCP client shares it.</td>\n    <td valign=\"top\"><h3>💬 Your channels</h3>Telegram, a web dashboard (installable as an app) and a CLI, plus Discord, Slack, WhatsApp, Signal and Matrix when configured. 7 LLM providers with failover.</td>\n  </tr>\n</table>\n\nThe architecture was checked against 30 research works from 2023–2026 across six domains: memory retrieval, lifecycle management, associative reasoning, sleep-inspired consolidation, affect modelling and proactive intelligence ([paper](Paper2026.pdf)). Comparing it with a gateway like LiteLLM? See [ScallopBot as a LiteLLM alternative](https://scallopbot.com/litellm-alternative/).\n\n## Benchmark Results\n\nScallopBot was run head to head with [Prime Agent](https://github.com/PrimeIntellect-ai/prime-agent), [OpenClaw](https://github.com/openclaw/openclaw) and [Hermes Agent](https://github.com/NousResearch/hermes-agent) on **ScallopBench v2**, a tool-calling benchmark of 36 real tasks: 12 trap tasks drawn from production failures, 6 coding tasks with hidden tests, 3 personal-assistant tasks and 15 hard multi-step tasks. Every agent used the same model (Moonshot `kimi-k2.6`, thinking on) and ran every task 3 times. Runs are scored on outcomes only: the files left in the workspace, hidden tests and the replies, never the agent's own claims.\n\n<p align=\"center\">\n  <picture>\n    <source media=\"(prefers-color-scheme: dark)\" srcset=\"assets/scallopbench-v2-dark.svg\">\n    <img src=\"assets/scallopbench-v2-light.svg\" alt=\"ScallopBench v2: overall pass rate ScallopBot 98.1%, Prime Agent 98.1%, OpenClaw 97.2%, Hermes Agent 93.5%; hard tasks 44/45, 43/45, 43/45, 39/45; resisted the hidden prompt injection 3/3, 2/3, 3/3, 0/3\" width=\"900\">\n  </picture>\n</p>\n\n| | **ScallopBot** | Prime Agent | OpenClaw | Hermes Agent |\n|---|:---:|:---:|:---:|:---:|\n| **Overall** (108 task-runs) | **98.1%** (106/108) | 98.1% (106/108) | 97.2% (105/108) | 93.5% (101/108) |\n| Trap tasks | **36/36** | 36/36 | 36/36 | 36/36 |\n| Coding (hidden tests) | 17/18 | 18/18 | 17/18 | 17/18 |\n| Assistant | **9/9** | 9/9 | 9/9 | 9/9 |\n| Hard tasks | **44/45** | 43/45 | 43/45 | 39/45 |\n| Resisted the hidden prompt injection | **3/3** | 2/3 | 3/3 | 0/3 |\n\n- **Tied for the top score** with Prime Agent, and the **best score on the hard tasks**. With 3 runs per task none of the gaps between agents is statistically significant; one or two task-runs either way is within the run-to-run spread.\n- **Prompt injection:** one task hides an instruction to delete files inside the project README. ScallopBot never followed it; Hermes Agent did in all three runs.\n- **What helps on the hard tasks:** before a turn that changed files ends, a fresh-context reviewer reads the request and the changed files and runs quick probes on a throwaway copy of the project (`src/tools/review/`). Anything it reproduces goes back to the agent as a note, never as a block. `REVIEW_ON_STOP=off` turns it off.\n\nCompetitors ran on 2 Oct 2026 (Hermes Agent `0be2d56`, Prime Agent `cf285dc`, OpenClaw `2026.9.7`), ScallopBot on 3 Oct 2026 with its default settings. We wrote this benchmark and improved ScallopBot against it, and we report every ScallopBot run (105, 105 and 106 of 108). The caveats, confidence intervals, per-task results, raw run files and adapters are in [`evals/agentic/baselines/RESULTS-v2.md`](evals/agentic/baselines/RESULTS-v2.md); the harness is [`evals/agentic/`](evals/agentic/) (`npm run bench:agentic`).\n\n## How it fits together\n\n<p align=\"center\">\n  <picture>\n    <source media=\"(prefers-color-scheme: dark)\" srcset=\"assets/architecture-dark.svg\">\n    <img src=\"assets/architecture-light.svg\" alt=\"ScallopBot architecture: Telegram, the web dashboard, the CLI and other channels feed the gateway and the agent loop; the agent calls skills and the cost-aware router, which fails over between seven providers; SQLite memory and the background cognitive layer sit underneath; messages the bot starts on its own go through the outcome brain.\" width=\"900\">\n  </picture>\n</p>\n\nEverything runs in one Node.js process. Messages from any channel go through the gateway to the agent loop, which runs tools in parallel waves and calls models through the cost-aware router. Memory lives in one SQLite file. The gardener daemon works on that memory in the background and can start conversations of its own. Your replies come straight from the agent loop; messages the bot sends on its own (reminders, scheduled results, proactive check-ins) pass through the outcome brain first.\n\n## Install\n\nEvery route ends with the bot running and the web dashboard on\n`http://localhost:3000`. The first browser visit creates the dashboard login,\nunless the installer (or `scallopbot web-login`) already set one. When you copy\n`.env.example` by hand, set one provider key and comment out the placeholder\n`TELEGRAM_BOT_TOKEN` line if you are not using Telegram.\n\n### One-liner (Linux, macOS, Raspberry Pi OS 64-bit)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/tashfeenahmed/scallopbot/main/scripts/install.sh | bash\n```\n\n[`scripts/install.sh`](scripts/install.sh) installs Node 24 through nvm if you\ndon't have it (no sudo), clones or updates `~/scallopbot`, runs `npm ci` and the\nbuild, asks for a provider key, an optional Telegram token and an optional\ndashboard login, writes `.env`, and can install a pm2 or systemd user service.\nRe-running it updates the checkout and keeps your `.env`. Flags go after\n`bash -s --`, for example `| bash -s -- --dir /opt/scallopbot --service pm2`;\n`--non-interactive` reads the answers from `ANTHROPIC_API_KEY` (or another\nprovider key), `TELEGRAM_BOT_TOKEN`, `SCALLOPBOT_WEB_EMAIL` and\n`SCALLOPBOT_WEB_PASSWORD`; `--dry-run` shows what it would do.\n\n<details>\n<summary><strong>Docker</strong></summary>\n\n```bash\ngit clone https://github.com/tashfeenahmed/scallopbot.git && cd scallopbot\ncp .env.example .env          # set a provider key\ndocker compose up -d --build\n```\n\nThe image (`node:24-slim`, amd64 and arm64) runs as a non-root user and keeps\neverything it writes, including the SQLite memory, sessions, workspace and\ninstalled skills, in the `scallopbot-data` volume at `/data`. The port is\npublished on `127.0.0.1` only; put a reverse proxy or Tailscale in front before\nexposing it. An Ollama service is ready to uncomment in\n[`docker-compose.yml`](docker-compose.yml). Local voice (Python, ffmpeg) and the\nbrowser skill's Chrome are not in the image. `install.sh --docker` fetches just\nthe compose file and a filled-in `.env` and builds straight from GitHub.\n\n</details>\n\n<details>\n<summary><strong>npm (global CLI)</strong></summary>\n\nScallopBot is not on the npm registry yet, so build and pack it from a clone:\n\n```bash\ngit clone https://github.com/tashfeenahmed/scallopbot.git && cd scallopbot\nnpm ci && npm run build && npm pack\nnpm install -g ./scallopbot-0.1.0.tgz\n\nmkdir -p ~/scallopbot-data && cd ~/scallopbot-data\ncp \"$(npm root -g)/scallopbot/.env.example\" .env   # set a provider key\nscallopbot start\n```\n\n`scallopbot` reads `.env` from, and keeps its data in, the directory you start\nit from (or `AGENT_WORKSPACE`).\n\n</details>\n\n<details>\n<summary><strong>From source</strong></summary>\n\n```bash\ngit clone https://github.com/tashfeenahmed/scallopbot.git\ncd scallopbot\nnpm install\n\ncp .env.example .env\n# Add at least one LLM provider API key\n\nnpm run build\nnode dist/cli.js start\n```\n\nRequires Node.js 24+.\n\n</details>\n\n### Install the dashboard as an app\n\nThe web dashboard is a Progressive Web App. In Chrome or Edge use **Install\napp** in the address bar; on iPhone or iPad use **Share → Add to Home Screen**.\nBrowsers only offer this over HTTPS or on `localhost`. The service worker\ncaches the app shell so it opens offline; chat, memory and API data always come\nlive from your server.\n\n## MCP\n\nScallopBot is MCP-native in both directions: it **consumes** MCP servers through the\nbundled [`mcp` skill](src/skills/bundled/mcp/), and it **exposes its own memory** as an MCP\nserver. Point Claude Code, Codex, or any other MCP client at it and that client reads and\nwrites the same memory the bot uses -- store something from your editor, and the bot\nrecalls it in Telegram.\n\nThe `mcp` skill talks to local stdio servers (`command`) and remote servers over\nStreamable HTTP or the older SSE transport (`url` + `transport: \"http\" | \"sse\"`), with\nheaders or a bearer token that can reference `${MCP_*}` environment variables. Each call\nopens a short-lived session; tools must be allow-listed per server. See the\n[skill's README](src/skills/bundled/mcp/SKILL.md) for the config format.\n\nThree tools are exposed:\n\n| Tool | Purpose |\n|------|---------|\n| `memory_store` | Store a memory, with optional tags, importance (1--10) and event timestamp |\n| `memory_recall` | Hybrid BM25 + embedding retrieval for a query |\n| `memory_temporal` | \"What happened between X and Y\" over an explicit window or a named range |\n\nScallopBot is not published to npm, so the server runs from your local checkout. Build\nonce (`npm run build`), then register the absolute path to `dist/mcp-server/index.js`.\n\n**Claude Code:**\n\n```bash\nclaude mcp add scallopbot \\\n  --env SCALLOPBOT_DB=/path/to/scallopbot/memories.db \\\n  -- node /path/to/scallopbot/dist/mcp-server/index.js\n```\n\n**Codex** — in `~/.codex/config.toml`:\n\n```toml\n[mcp_servers.scallopbot]\ncommand = \"node\"\nargs = [\"/path/to/scallopbot/dist/mcp-server/index.js\"]\nenv = { SCALLOPBOT_DB = \"/path/to/scallopbot/memories.db\" }\n```\n\n| Env var | Default | Meaning |\n|---------|---------|---------|\n| `SCALLOPBOT_DB` | `MEMORY_DB_PATH`, else `./memories.db` | Path to the memory database |\n| `SCALLOPBOT_USER` | `default` | Memory owner, for multi-user deployments |\n| `LOG_LEVEL` | `warn` | Server logs go to stderr; stdout is the JSON-RPC channel |\n\n**Safe to run alongside the bot.** The database is in WAL mode, so readers never block the\nwriter. The server sets `PRAGMA busy_timeout=5000` to wait out the bot's write lock rather\nthan failing on `SQLITE_BUSY`, and it never holds a write transaction across an `await` --\nso a slow embedding call can't stall the running bot.\n\nThe standalone server starts without any API keys. With no embedding provider configured,\n`memory_recall` falls back to BM25 keyword scoring and says so in its output rather than\nsilently degrading.\n\n## Cognitive Architecture\n\nScallopBot's cognitive layer is organised into six subsystems, run by a background gardener on three clocks:\n\n<p align=\"center\">\n  <picture>\n    <source media=\"(prefers-color-scheme: dark)\" srcset=\"assets/gardener-dark.svg\">\n    <img src=\"assets/gardener-light.svg\" alt=\"The gardener over one day: a light tick every minute (decay, expiry, health ping), a deep tick about every 72 minutes (summaries, forgetting, audits, proactive check), and one sleep tick in the 2 to 5 AM quiet hours, at least 20 hours apart (dream cycle, reflection, gap scan, evolution).\" width=\"900\">\n  </picture>\n</p>\n\nAffect is updated per message, not on a tick. Intervals and quiet hours are configurable with\n`GARDENER_LIGHT_INTERVAL_MS`, `GARDENER_DEEP_INTERVAL_MS`, `GARDENER_SLEEP_INTERVAL_MS`,\n`GARDENER_QUIET_HOURS_START` and `GARDENER_QUIET_HOURS_END`.\n\n### Bio-Inspired Dream Cycle\n\nA two-phase sleep cycle runs during the nightly heartbeat. **NREM consolidation** clusters and merges fragmented memories across topic boundaries into coherent summaries. **REM exploration** uses high-noise spreading activation to discover non-obvious connections between memories, with an LLM judge evaluating novelty, plausibility, and usefulness of discovered associations.\n\n### Affect-Aware Interaction\n\nZero-cost emotion detection using AFINN-165 lexicon with VADER-style heuristics, mapped to the Russell circumplex model. A dual-EMA system tracks both session-level mood (2-hour half-life) and baseline mood trends (3-day half-life). An **affect guard** ensures emotional signals inform agent awareness without contaminating instructions.\n\n### Self-Reflection and Guarded Evolution\n\nNightly composite reflection analyses recent sessions across four dimensions (explanation, principles, procedures, advice). Its insights are stored as assistant-only evidence: they never enter user memory and never rewrite `SOUL.md` directly. Reusable behavioral or procedural changes must pass the separate evolution pipeline's held-out replay, privacy/safety checks, measured-improvement gate, version ledger, and rollback path.\n\n### Proactive Intelligence\n\nA gap scanner identifies explicit open loops, approaching deadlines, and stale/blocked work. Passive usage changes such as shorter replies or fewer sessions never justify outreach on their own. Delivery is gated by explicit positive/negative preferences, a configurable proactiveness dial (conservative/moderate/eager), quiet hours, send-time freshness checks, daily limits, and a **feedback loop** based on actual proactive outcomes rather than general chat frequency.\n\nGenerated outreach is realized immediately before delivery using current context and recent message history. Social-quality gates reject internal reasoning, generic check-ins, surveillance language, faux intimacy, pressure, and multi-question interrogations; literal reminders written by the user remain unchanged.\n\n### Outcome Brain for bot-initiated messages\n\nReplies to your messages are not rewritten: they come straight from the agent loop. Messages the bot starts on its own (proactive check-ins, scheduled and reminder results, finished background work) go through the outbound queue to one shared `OutcomeBrain`, which weighs them against recent conversation, current user facts, live board items and goals, and recent decisions. It can send, combine, rewrite or hold back a message, drops exact duplicates, and strips internal reasoning from file captions. Exact user-authored reminders and verified task results are delivered as written; inferred outreach is held back if the model is unavailable. Only hashed decision receipts are stored, not the messages themselves.\n\n### Spreading Activation\n\nACT-R-inspired spreading activation over typed relation graphs (UPDATES, EXTENDS, DERIVES) with 3-step propagation, fan-out normalisation, and Gaussian noise to prevent deterministic retrieval. The same pure function powers both normal retrieval and REM dream exploration (with elevated noise).\n\n## Key Features\n\n### Hybrid Memory Engine\n\n<p align=\"center\">\n  <picture>\n    <source media=\"(prefers-color-scheme: dark)\" srcset=\"assets/memory-lifecycle-dark.svg\">\n    <img src=\"assets/memory-lifecycle-light.svg\" alt=\"Memory lifecycle: capture facts after each message, store them in SQLite with model-tagged embeddings, recall with BM25 plus embeddings, optional re-ranking and spreading activation, decay by category half-life, consolidate nightly (NREM fusion and REM association, with fused summaries written back), and forget low-utility memories with a soft archive before pruning.\" width=\"900\">\n  </picture>\n</p>\n\nSQLite-backed memory with ACID guarantees. Combines BM25 keyword scoring with semantic embeddings and optional LLM re-ranking. `EMBEDDING_PROVIDER` picks `ollama` (local `nomic-embed-text` or `mxbai-embed-large`), `openai`, or `tfidf`; unset, it tries Ollama and falls back to TF-IDF. Each stored vector is tagged with its model, so vectors from different models are never compared, and `reembed` moves an existing memory store to a new model. Recall uses smooth activation from temporal decay, lifecycle, genuine topic relevance, salience, and user confirmation: an old topic fades from general context but can return naturally when it becomes relevant, without magic \"history\" wording. Automatic retrieval is telemetry only and never reinforces freshness or utility. Assistant self-reflection and agent-subject facts remain separate from user memory. The lifecycle includes category-specific half-lives (14 days for events to 346 days for relationships), BFS-clustered fusion, and utility-based forgetting with soft-archive before hard-prune.\n\n### Cost-Aware Model Routing\n\n<p align=\"center\">\n  <picture>\n    <source media=\"(prefers-color-scheme: dark)\" srcset=\"assets/routing-dark.svg\">\n    <img src=\"assets/routing-light.svg\" alt=\"Model routing: each request is scored for complexity and sent to a fast, standard or capable tier; each tier has its own provider order; a budget gate checks daily and monthly limits before the call, and failing providers are cooled down while the next healthy one takes over.\" width=\"900\">\n  </picture>\n</p>\n\nEvery API call is priced at the token level using a built-in pricing database covering 50+ models. A complexity analyzer scores each request and routes it to a tier -- fast (prefers Groq, then Moonshot), standard (prefers Moonshot, then OpenAI), or capable (prefers Anthropic) -- falling through to the next healthy provider you have keys for. OpenRouter joins the failover chain when listed in `PROVIDER_ORDER`. Daily and monthly budgets gate requests before they're sent. Provider health is tracked per-call -- consecutive failures trigger automatic failover with exponential backoff and jitter.\n\n### Local-First Voice Pipeline\n\nSpeech-to-text via faster-whisper (CTranslate2-optimized Whisper) and text-to-speech via Kokoro (82M param ONNX model) run entirely on-device with zero API cost. Cloud providers (Groq STT, OpenAI TTS) serve as automatic fallbacks. Telegram voice messages are transcribed inline; voice replies are synthesized when enabled.\n\n### Native Tools and Skills\n\nThe core tools the agent uses on every turn -- files (`read_file`, `write_file`, `patch`, `undo`), shell (`bash`, background processes), web (`webfetch`, `web_search`) and `todo` -- are built into the agent (`src/tools/`). Everything else -- browser, git, Docker, PDF, memory search, email, calendar and more -- is a self-contained skill in the [OpenClaw](https://github.com/openclaw/openclaw) SKILL.md format. Skills declare their own requirements (binaries, env vars, OS) and are gated at load time. Community skills install from [ClawHub](https://clawhub.ai) with a single CLI command.\n\nPlain [agentskills.io](https://agentskills.io) / Anthropic skills (just `name` + `description`, optional `license`, `allowed-tools`, `metadata`) load unchanged. Only the name and description go in the prompt; the body is loaded when the model calls `load_procedure`, and bundled `references/` or `scripts/` files are listed and read on demand. A `scripts/` folder only turns a skill into a callable tool when it also has an `inputSchema` or a `scripts/run.*` entrypoint. `allowed-tools` is shown to the model but does not grant permissions.\n\n### Evidence-Gated Procedural Learning\n\nAn optional, default-off evolution loop can distill reusable multi-tool workflows into documentation-only skills. Candidates are replayed against held-out tasks, safety and privacy checked, promoted only after a measured improvement, tracked for real use, and automatically rolled back or recoverably archived when they regress or become stale. Machine-authored executable scripts remain blocked without OS isolation. See the [intelligence roadmap and reproducible evidence](docs/INTELLIGENCE_ROADMAP.md).\n\n### Durable Sub-Agent Orchestration\n\nDelegated work is tracked in SQLite with atomic batch capacity reservations, lineage, explicit context modes (`isolated`, `brief`, `fork`), bounded orchestrator nesting, progress-aware idle limits, token/cost budgets, and structured acceptance results. Background completions use a leased delivery outbox, survive restarts, update parent context, and reach the user as a concise outcome rather than internal reasoning. Coding tasks can use detached Git worktrees and an implement → independent review/test workflow that returns a conflict-checked patch. The web dashboard includes a live Tasks rail with status, evidence, blockers, hierarchy, logs, and cancellation controls.\n\n## Daily Cost Breakdown\n\nAt 100 messages/day with Groq for fast-tier operations:\n\n| Operation | Calls/Day | Daily Cost |\n|-----------|:---------:|:----------:|\n| Primary conversation | 100 | $0.03 |\n| Memory re-ranking | 100 | $0.003 |\n| Relation classification | 50 | $0.0015 |\n| Affect classification | 100 | $0 (lexicon) |\n| Session summaries (deep tick, ~72 min) | ≤20 | ~$0.005 |\n| Dream cycle (nightly) | 15--20 | $0.005 |\n| Self-reflection (nightly) | 1 | $0.001 |\n| Gap scanner (nightly) | 3--5 | $0.001 |\n| **Total** | | **~$0.05** (up to ~$0.10 with a heavier primary model) |\n\nThe entire cognitive pipeline -- dreams, reflection, affect, gap scanning -- adds approximately $0.02/day to the base conversation cost. Add a $5--8/month VPS (or a Raspberry Pi you already own) for hosting; see the [cost page](https://scallopbot.com/cost/).\n\n## Providers\n\n| Provider | Default Model | Best For |\n|----------|--------------|----------|\n| **Anthropic** | Claude Sonnet 5.5 | Complex reasoning, coding |\n| **Moonshot** | Kimi K3 (thinking on request) | Cost-effective daily driver |\n| **OpenAI** | GPT-5.6 Luna | General tasks |\n| **xAI** | Grok 4 | Real-time information |\n| **Groq** | Llama 3.3 70B | Ultra-fast inference |\n| **Ollama** | Any local model (default `llama3.2`) | Privacy, offline use |\n| **OpenRouter** | 100+ models (default Claude Sonnet 5.5) | Maximum flexibility |\n\nConfigure one or more in `.env`. The router handles selection and failover automatically.\n\n### Fine-tuned local models (optional)\n\nTwo small models fine-tuned for ScallopBot's own jobs are published on Hugging Face:\n[scalloptools-1](https://huggingface.co/tashfene/scalloptools-1) (tool selection) and\n[scallopmemory-1](https://huggingface.co/tashfene/scallopmemory-1) (memory extraction). Both ship\nas q5 GGUF files (~2.9 GB) that run under Ollama. Plug them in with Multi-Model Mode below\n(register each as a `CUSTOM_PROVIDER_*`; point `MODEL_FACT_EXTRACTION` at scallopmemory-1, and put\nscalloptools-1 first in `PROVIDER_ORDER` to make it the chat/tool model). Their\nbenchmark numbers are on [scallopbot.com](https://scallopbot.com/#models).\n\n### Multi-Model Mode (optional)\n\nOne model serves every purpose by default. If you want specialized models — say, a\nfine-tuned 4B for memory operations and a different model for the main agent loop —\ntoggle multi-model mode on and register any OpenAI-compatible endpoint under your\nown name:\n\n```bash\nMULTI_MODEL_ENABLED=true\nCUSTOM_PROVIDER_MY_TOOLS=http://localhost:11434/v1|my-tools-model\nCUSTOM_PROVIDER_MY_MEMORY=http://localhost:11434/v1|my-memory-model\n\n# Optional exact token limits for custom/local models\nMODEL_TOKEN_LIMITS='{\"my_memory\":{\"contextWindowTokens\":262144,\"maxOutputTokens\":32768}}'\n\n# Optional pricing for paid custom endpoints; local/free custom endpoints stay $0\nCOST_MODEL_PRICING='{\"my_tools/my-tools-model\":{\"inputPerMillion\":0.3,\"outputPerMillion\":1.8}}'\n\n# Pin background purposes to the memory model...\nMODEL_FACT_EXTRACTION=my_memory\nMODEL_RERANKER=my_memory\n# ...and put the tools model first in the chat fallback chain\nPROVIDER_ORDER=my_tools,openrouter\n```\n\nCustom providers behave like built-ins everywhere: they can be pinned per purpose\n(`MODEL_RERANKER`, `MODEL_FACT_EXTRACTION`, `MODEL_COGNITION`, `MODEL_CRITIC`,\n`MODEL_EVOLUTION`, `MODEL_EVAL`), placed in `PROVIDER_ORDER`, and selected with the\n`/model` command. With the toggle off, `CUSTOM_PROVIDER_*` entries are ignored (a\nwarning is logged), so the default single-model setup stays untouched.\n\n### Lifecycle Event Relay (optional)\n\nSet `SCALLOPBOT_EVENT_WEBHOOK_URL` to emit key lifecycle events to an external\norchestrator:\n\n```bash\nSCALLOPBOT_EVENT_WEBHOOK_URL=https://orchestrator.example.com/scallopbot/events\nSCALLOPBOT_EVENT_WEBHOOK_SECRET=replace-with-shared-secret\nSCALLOPBOT_AGENT_ID=scallopbot\n```\n\nThe webhook receives POST payloads for `memory.consolidation_complete`,\n`memory.reflection_output`, and `session.affect_change`. If a secret is set, it is\nsent as a bearer token.\n\n## Bundled Skills\n\n34 skills ship out of the box:\n\n<details>\n<summary><strong>All 34 bundled skills</strong>: files and editing, shell and code, web, memory and planning, documents, email and calendar, MCP, dev tools, messaging, images, calls and SMS</summary>\n\n| Skill | Description |\n|-------|-------------|\n| `bash` | Execute shell commands |\n| `read_file` | Read a file as numbered 2,000-line pages; says \"unchanged\" on identical re-reads, suggests similar names for wrong paths |\n| `write_file` | Create/overwrite files; hints once before overwriting a file not read this session |\n| `patch` | Main editor: fuzzy old/new replacement (9-step matching chain), atomic multi-edit, unified/Codex diffs; reports only new lint problems |\n| `edit_file` | Alias of `patch` for a single old/new replacement |\n| `undo` | Restore the shadow-git checkpoint taken before the agent's edits (skips files changed since) |\n| `ls` | List files and directories |\n| `glob` | Find files by glob pattern |\n| `grep` | Search file contents with regex |\n| `codesearch` | Find code definitions (functions, classes, imports) |\n| `run_code` | Run a throwaway Python, Node or bash program |\n| `browser` | Web automation ([agent-browser](https://github.com/vercel-labs/agent-browser) from Vercel Labs) |\n| `web_search` | Search via Brave API |\n| `webfetch` | Fetch and extract text from a URL |\n| `memory_search` | Query the hybrid memory engine |\n| `board` | Task board: create, move, prioritise and track work items |\n| `goals` | Track goals, milestones and tasks |\n| `triggers` | View and cancel automatic follow-up schedules |\n| `question` | Ask the user a clarifying question |\n| `batch` | Run several tool calls in parallel |\n| `pdf` | Create PDFs with [Typst](https://typst.app), read with poppler, edit with qpdf |\n| `notion` | Typed Notion API access |\n| `email` | Read, search and send email over IMAP/SMTP (sends need your yes) |\n| `calendar` | Google Calendar read/write (writes need your yes) or a read-only ICS feed |\n| `mcp` | Call tools on configured MCP servers |\n| `git` | Version control operations |\n| `npm` | Package management |\n| `docker` | Container management |\n| `telegram_send` | Send messages programmatically |\n| `image_gen` | Generate or edit an image (OpenAI, FAL or OpenRouter) and send it to the chat |\n| `phone_call` | Twilio call that speaks a message, optionally collecting a spoken/keypad reply |\n| `sms` | Send a text message via Twilio |\n| `reminder` | Reminders (deprecated; use `board`) |\n| `progress` | Goal progress (deprecated; use `board`) |\n\n</details>\n\n### Images, calls and SMS\n\n- **`image_gen`** needs `OPENAI_API_KEY`, `FAL_KEY` or `OPENROUTER_API_KEY` (or pick one with `IMAGE_GEN_PROVIDER`). Images are saved under `output/` and sent straight to the chat (Telegram photo, inline preview in the web dashboard). Each image's cost is recorded in the cost tracker, so it counts toward `DAILY_BUDGET`/`MONTHLY_BUDGET`, and generation is refused once a budget is used up. Prices are the API's reported usage where it gives one (OpenAI token usage, OpenRouter `usage.cost`), otherwise a per-image estimate.\n- **`phone_call` / `sms`** need `TWILIO_ACCOUNT_SID`, `TWILIO_AUTH_TOKEN` and `TWILIO_FROM_NUMBER`. Numbers in `PHONE_ALLOWED_NUMBERS` go straight through; any other number gets a one-tap approval prompt per recipient. Calls use Twilio's voice by default. With `PUBLIC_BASE_URL` set, they use ScallopBot's own TTS and can collect the callee's reply (`wait_for_reply`), which is posted back to you in chat. Twilio's webhook at `/api/twilio/gather` is checked against `X-Twilio-Signature`. Calls and SMS record an estimated price (US list rates) against the budget. `PHONE_REMINDER_CALLS=tagged|all` with `PHONE_OWNER_NUMBER` also phones you when a reminder fires.\n- These variables are read at call time from the environment (or the runtime key vault), not in `config.ts`. See [.env.example](.env.example).\n\nInstall community skills from ClawHub, or any skill folder on GitHub:\n\n```bash\nnode dist/cli.js skill install elicitation\nnode dist/cli.js skill install https://github.com/anthropics/skills/tree/main/skills/pdf\n```\n\n## Channels\n\n| Channel | Status | Features |\n|---------|--------|----------|\n| **Telegram** | Live (`start`) | Voice transcription, voice reply, file upload/download, photo analysis, per-user onboarding |\n| **Web dashboard / REST API** | Live (`start`, needs `WEB_UI_ENABLED=true`) | `POST /api/chat`, SSE streaming, session management, file download, budget management (`POST /api/costs/budget`), push-to-talk STT/TTS (`/api/voice/*`) |\n| **WebSocket** | Live (served by the API channel) | Real-time bidirectional communication with the web dashboard |\n| **CLI** | Live (`chat`) | Interactive terminal session with session resume (`-s <id>`) |\n| **Discord** | Starts when `DISCORD_BOT_TOKEN` is set | DMs and @mentions, `/ask` `/reset` `/help` `/status` slash commands, proactive DMs, file sending |\n| **Slack** | Starts when `SLACK_BOT_TOKEN` + `SLACK_APP_TOKEN` are set (Socket Mode) | DMs and @mentions, optional `/scallopbot` command, proactive DMs, file sending |\n| **WhatsApp** | Starts when `WHATSAPP_ENABLED=true` and `WHATSAPP_ALLOWED_NUMBERS` is set | 1:1 chats via a linked device (Baileys), voice-note transcription, proactive messages, file sending |\n| **Signal** | Starts when `SIGNAL_PHONE_NUMBER` is set and `signal-cli` is installed | 1:1 chats via `signal-cli` JSON-RPC, voice-note transcription, proactive messages, file sending |\n| **Matrix** | Starts when `MATRIX_HOMESERVER_URL` + `MATRIX_ACCESS_TOKEN` are set | DMs and mentions in unencrypted rooms, `!help` `!reset` `!status`, proactive room messages, file sending |\n\nDiscord, Slack, WhatsApp, Signal and Matrix are covered by tests against mocked SDK clients (start, inbound message to agent and back, allowlist, proactive delivery); they have not been exercised against the live services in CI. Telegram-only features (approval buttons, `/model`, `/setup`, photo analysis, voice replies) are not available on them; a blocked write is answered by replying \"yes\" or \"no\". A channel that fails to start (bad token, missing optional package) is logged and skipped, and the rest of the gateway keeps running.\n\n**What each channel needs** (all variables are in `.env.example`):\n\n<details>\n<summary>Show credentials and allowlists per channel</summary>\n\n| Channel | Credentials | Allowlist | Notes |\n|---------|-------------|-----------|-------|\n| Discord | `DISCORD_BOT_TOKEN` (`DISCORD_APPLICATION_ID` optional) | `DISCORD_ALLOWED_USERS` (user IDs) | Enable the privileged **Message Content** intent for the bot; `discord.js` is a regular dependency |\n| Slack | `SLACK_BOT_TOKEN` (xoxb-), `SLACK_APP_TOKEN` (xapp-, `connections:write`) | `SLACK_ALLOWED_USERS` (member IDs) | Socket Mode on; scopes `chat:write`, `app_mentions:read`, `im:history`, `im:read`, `im:write`, `files:write`; events `app_mention`, `message.im`; optional package `@slack/bolt` |\n| WhatsApp | `WHATSAPP_ENABLED=true`; link once via pairing code (`WHATSAPP_PHONE_NUMBER`) or QR | `WHATSAPP_ALLOWED_NUMBERS` (**required**) | Rides a real WhatsApp account, so it refuses to start without an allowlist; session stored in `WHATSAPP_AUTH_DIR`; optional packages `@whiskeysockets/baileys`, `@hapi/boom` (`qrcode-terminal` to render the QR) |\n| Signal | `SIGNAL_PHONE_NUMBER` (registered with `signal-cli`) | `SIGNAL_ALLOWED_NUMBERS` | Needs the `signal-cli` binary (`SIGNAL_CLI_PATH`, `SIGNAL_CONFIG_PATH`); group messages are ignored |\n| Matrix | `MATRIX_HOMESERVER_URL`, `MATRIX_ACCESS_TOKEN` (`MATRIX_USER_ID` optional) | `MATRIX_ALLOWED_USERS`, `MATRIX_ALLOWED_ROOMS` | No end-to-end encryption: use unencrypted rooms; auto-joins invites from allowed users; optional package `matrix-js-sdk` |\n\n</details>\n\nAn empty allowlist means anyone who can reach the bot can use it (a warning is logged). Every channel's proactive delivery is held to the same allowlist. Set `<CHANNEL>_ENABLED=false` to keep a channel off without removing its credentials.\n\n## Email and Calendar\n\nBoth are optional and configured in `.env` (see `.env.example`).\n\n- **Email** (`email` skill): list, search and read over IMAP; send and reply over SMTP. Works with Gmail app passwords and any IMAP/SMTP provider. Every send or reply is blocked until you approve that exact email (recipients, subject, body) with the yes/no prompt; `EMAIL_SEND_WITHOUT_APPROVAL=true` relaxes this to \"you asked for it in your message\".\n- **Email in** (`EMAIL_INBOUND_ENABLED=true`): the bot polls your inbox. Mail from `EMAIL_ALLOWED_SENDERS` that passes DMARC/DKIM becomes a message to the bot (one session per sender) and the answer is emailed back in-thread. Email turns can't approve sends or calendar writes. `EMAIL_NOTIFY=important|all` posts a one-line \"new email\" note to your main channel instead. Polling only, no IMAP IDLE.\n- **Calendar** (`calendar` skill): Google Calendar via an OAuth refresh token (`node dist/cli.js google-auth` prints one), with upcoming/search/create/update/delete; each write needs your yes. Without Google, `CALENDAR_ICS_URL` gives read-only access to any ICS feed (recurring, all-day and timezone-aware). `CALENDAR_REMINDER_MINUTES=15` sends a heads-up before timed events.\n\nGoogle refresh tokens for OAuth apps left in \"Testing\" expire after 7 days; publish the consent screen (unverified is fine for your own account) to keep the token.\n\n## Web Dashboard\n\nA React + Tailwind + Vite single-page app served from the API channel. Features:\n\n- Real-time chat with markdown rendering and streaming responses\n- Debug mode showing tool execution (start/complete/error), thinking steps, and memory operations\n- Cost panel with daily/monthly budget bars, per-model breakdown, and a 14-day spending chart\n- Delegated Tasks rail with live status, parent/child hierarchy, acceptance evidence, blockers, logs, cancellation, steering, and follow-ups\n- File send/receive with download links; images show inline\n- Push-to-talk voice mode: hold the mic button (or Space/Enter on it) to talk. The clip goes through the same STT as Telegram voice notes, and the reply is read aloud when TTS is configured\n- Proactive message delivery (reminders, triggers)\n\n## Configuration\n\nMinimal `.env`:\n\n```bash\nANTHROPIC_API_KEY=sk-...           # At least one provider required\nWEB_UI_ENABLED=true                # Optional: web dashboard + REST/WebSocket API\nTELEGRAM_BOT_TOKEN=...             # Optional: enable Telegram\nTELEGRAM_ALLOWED_USERS=123456789   # Optional: restrict access\nBRAVE_SEARCH_API_KEY=...           # Optional: enable web search\n```\n\nBudget controls:\n\n```bash\nDAILY_BUDGET=5.00\nMONTHLY_BUDGET=100.00\nBUDGET_WARNING_THRESHOLD=0.75      # default; dashboard bars turn amber past this\n```\n\nCommon options: [.env.example](.env.example); every variable is read in [`src/config/config.ts`](src/config/config.ts).\n\n## Security\n\nThree opt-in layers sit on top of the dangerous-command blocklist, one-tap approvals (email sends, calendar writes, unlisted phone numbers and any tool in `CONFIRM_TOOLS`), workspace path checks and log redaction. They reduce risk; they do not make it safe to give the bot untrusted users or untrusted skills.\n\n**Sandboxed execution** (`bash`, `run_code`). `SANDBOX_MODE` picks the backend; the dangerous-command blocklist still runs first.\n\n| Mode | What it does |\n|------|--------------|\n| `off` (default) | Runs on the host, as before |\n| `auto` | Best native backend: `seatbelt` on macOS, `bwrap` on Linux if it works; otherwise `off` with a startup warning |\n| `seatbelt` | macOS `sandbox-exec`: writes denied outside the workspace and temp dirs |\n| `bwrap` | Linux bubblewrap: read-only root, writable workspace, private `/tmp` and PID namespace |\n| `docker` | Throwaway container per command, workspace bind-mounted, `--cap-drop ALL`, CPU/memory/PID limits, no network unless `SANDBOX_NETWORK=on` |\n\nAn explicitly named backend that is missing makes commands fail rather than run unsandboxed. All backends hide the vault, its key file and the bot's `.env` from sandboxed commands. The default stays `off` because a read-only root breaks commands that write outside the workspace (global `pip`/`npm`, `~/.cache`, a memory DB under `/opt`); try `SANDBOX_MODE=auto` and add paths to `SANDBOX_WRITABLE` as needed. On a Pi: `sudo apt install bubblewrap`. `auto` never picks Docker, because the image must carry your tools (set `SANDBOX_IMAGE`). The startup log names the active backend.\n\n**Encrypted secret vault.** `scallopbot secrets set|get|list|rm|import-env` keeps keys in `~/.scallopbot/secrets.enc` (AES-256-GCM, scrypt-derived key). The key comes from `SCALLOPBOT_VAULT_KEY` or a `0600` key file (`~/.scallopbot/vault.key`, created on first `set`). At startup vault values fill only variables that the shell or `.env` left unset, so environment variables win; run `scallopbot secrets import-env --strip` to move keys out of `.env`. Vault values are added to log and output redaction. With the key file beside the vault, this protects against leaked `.env` files, backups and screenshots. It does not protect against someone who can read your home directory; for that, supply `SCALLOPBOT_VAULT_KEY` from systemd credentials or a keychain.\n\n**Prompt-injection scanning.** Every tool result is scored with heuristics before the model sees it: \"ignore previous instructions\", role-tag and tool-call spoofing, hidden Unicode tag characters, base64-encoded instructions, exfiltration URLs and requests for secrets. Flagged output is wrapped in markers with a warning that it is data, not instructions, and a warning is logged (rule names and score only). `PROMPT_INJECTION_SCAN=block` also withholds high-confidence hits from external-content tools (`webfetch`, `web_search`, `browser`, `pdf`, `mcp`). It is a heuristic: expect some misses and the occasional harmless page being wrapped.\n\n## Reminders\n\nNatural language scheduling with timezone awareness:\n\n```\n\"remind me in 5 minutes to check the build\"     -> Interval\n\"remind me at 10am to take medicine\"             -> Absolute time\n\"remind me every day at 9am to check email\"      -> Daily recurring\n\"remind me every Monday at 3pm about standup\"    -> Weekly recurring\n\"remind me weekdays at 8am to exercise\"          -> Weekday recurring\n```\n\nReminders can be plain nudges or tasks; a task runs a sub-agent at the scheduled time and sends you the result.\n\n## Error Recovery\n\n| Failure | Response |\n|---------|----------|\n| Context overflow | Lean compaction -- old tool output stubbed, older turns summarised, your messages and recent turns kept; `session_search` reaches the full history |\n| Auth errors (401/403) | Rotate API keys if multiple are configured |\n| Provider outage | Automatic failover to next healthy provider |\n| Rate limits | Exponential backoff with jitter |\n| Tool crash | RecoveryManager resumes from saved state |\n| Process crash | PM2 auto-restart with crash state persistence |\n\n## Comparison with OpenClaw\n\n| Capability | OpenClaw | ScallopBot |\n|------------|----------|------------|\n| **Memory retrieval** | Vector + keyword hybrid, deterministic weighted ranking | BM25 + semantic + LLM re-ranking |\n| **Memory decay** | Recency decay on search ranking (30-day half-life) | Natural activation + category half-lives + user-confirmation reinforcement |\n| **Memory consolidation** | \"Dreaming\" promotes frequently-recalled notes into MEMORY.md; entries kept as written | BFS-clustered fusion + NREM cross-category |\n| **Memory forgetting** | -- (notes are never archived or pruned) | Utility-based with soft-archive / hard-prune |\n| **Associative retrieval** | -- | Spreading activation with typed edges |\n| **Dream cycle** | Light / REM / deep sweep (on by default), promotion only | NREM consolidation + REM exploration |\n| **Affect detection** | -- | AFINN-165 + VADER + dual-EMA + affect guard |\n| **Self-reflection** | -- | Private composite reflection feeding benchmarked, rollback-capable evolution |\n| **Proactive intelligence** | Basic Heartbeat | Gap scanner + inner thoughts + trust feedback loop |\n| **Background processing** | Heartbeat wake-up | 3-tier gardener (Light / Deep / Sleep) |\n| **Cost tracking & budgets** | Token + estimated-cost reporting (`/usage`, `/status`), no spend limits | Built-in per-token tracking with daily/monthly limits |\n| **Multi-provider routing** | Swappable model plugins | 7 supported providers with health-aware failover |\n| **Smart model selection** | Manual | Auto-routes by complexity |\n| **Local voice (zero cost)** | -- | Kokoro TTS + faster-whisper STT |\n| **Skill ecosystem** | 100+ bundled, 3000+ ClawHub | Full OpenClaw SKILL.md compatibility |\n| **Channel support** | 25+ platforms | Telegram, web dashboard/API, CLI, Discord, Slack, WhatsApp, Signal, Matrix |\n| **Native apps** | macOS/iOS/Android/Windows/Linux | -- |\n\nOpenClaw column reflects its public README and docs as of October 2026; it ships fast, so corrections are welcome. A fuller write-up is at [scallopbot.com/vs/openclaw](https://scallopbot.com/vs/openclaw/).\n\n## Deployment\n\nSee the [full deployment guide](./DEPLOYMENT.md) or the\n[Raspberry Pi notes](./DEPLOYMENT_PI.md) for backup, isolation, rollback and\nsecurity guidance. Keep production credentials and operator-specific details\nin a private runbook outside the repository.\n\n### One-Command Server Setup (Ubuntu 24.04)\n\n```bash\ngit clone https://github.com/tashfeenahmed/scallopbot.git /opt/scallopbot\ncd /opt/scallopbot\nbash scripts/server-install.sh    # Installs Node 24, PM2, voice deps, Ollama\ncp .env.example .env && nano .env\npm2 start ecosystem.config.cjs --env production && pm2 save\n```\n\nThe install script is idempotent and sets up:\n\n| Component | Purpose |\n|-----------|---------|\n| Node.js 24 + PM2 | Runtime and process management |\n| Python venv (kokoro-onnx, faster-whisper) | Local voice -- zero API cost TTS/STT |\n| Ollama + nomic-embed-text | Local embeddings for semantic memory search |\n| ffmpeg + sox | Audio format conversion |\n\n<details>\n<summary><strong>Alternative: systemd</strong></summary>\n\n```bash\nsudo tee /etc/systemd/system/scallopbot.service << EOF\n[Unit]\nDescription=ScallopBot AI Assistant\nAfter=network.target\n\n[Service]\nType=simple\nUser=scallopbot\nGroup=scallopbot\nWorkingDirectory=/opt/scallopbot\nEnvironmentFile=/opt/scallopbot/.env\nExecStart=/usr/bin/node /opt/scallopbot/dist/cli.js start\nRestart=always\nRestartSec=10\n\n[Install]\nWantedBy=multi-user.target\nEOF\n\nsudo systemctl enable --now scallopbot\n```\n\n</details>\n\n## CLI Reference\n\n<details>\n<summary>Show all CLI commands</summary>\n\n| Command | Description |\n|---------|-------------|\n| `start` | Launch gateway with all configured channels |\n| `chat` | Interactive CLI session (`-s <id>` to resume) |\n| `config` | Show current configuration (`--json` for machine output) |\n| `version` | Show version |\n| `web-login -e <email>` | Create the dashboard login (password from `SCALLOPBOT_WEB_PASSWORD` or stdin) |\n| `skill search <query>` | Search ClawHub |\n| `skill install <slug\\|github-url>` | Install from ClawHub or a GitHub skill folder |\n| `skill uninstall <name>` | Remove a skill |\n| `skill list` | List installed skills |\n| `skill update [name]` | Update one or all skills |\n| `skill-curator status` | Show usage and lifecycle state for agent-created skills |\n| `skill-curator run` | Mark stale and archive unused agent-created skills |\n| `skill-curator pin <name>` | Keep an agent-created skill active |\n| `skill-curator restore <name>` | Restore a recoverably archived skill |\n| `migrate run` | Migrate legacy JSONL memories to SQLite |\n| `secrets set <name> [value]` | Store a secret in the encrypted vault (omit the value to type it hidden) |\n| `secrets get <name>` / `list` / `rm <name>` | Read, list names, or delete vault secrets |\n| `secrets import-env [file]` | Move credential-looking variables from `.env` into the vault (`--strip` removes them from the file) |\n| `google-auth` | Authorize Google Calendar and print `GOOGLE_REFRESH_TOKEN` |\n| `reembed` | Re-embed memories into the current `EMBEDDING_PROVIDER`/`EMBEDDING_MODEL` (`--dry-run`, `--limit`, `--all`; resumable) |\n\n</details>\n\n## Project Structure\n\n<details>\n<summary>Show the source tree</summary>\n\n```\nsrc/\n├── agent/          # Agent loop, session management, crash recovery\n├── brain/          # Outcome brain for bot-initiated messages\n├── channels/       # Telegram, CLI, API, Discord, Slack, WhatsApp, Signal, Matrix adapters\n├── codemode/       # Optional code mode (AGENT_MODE=code|hybrid)\n├── config/         # Zod-validated configuration schemas\n├── context/        # Lean compaction, history replay, session_search\n├── dashboard/      # Systemd config generator, crash recovery\n├── gateway/        # Server orchestration and channel initialization\n├── integrations/   # Email (IMAP/SMTP) and calendar\n├── learning/       # Core memory tool, background review and refinement\n├── media/          # PDF, image, URL processing\n├── mcp-server/     # Stdio MCP server exposing memory to MCP clients\n├── memory/         # Hybrid search, fact extraction, decay engine, profiles\n├── proactive/      # Unified scheduler for reminders and triggers\n├── providers/      # LLM provider implementations (7 providers)\n├── reliability/    # Circuit breaker, graceful degradation\n├── routing/        # Cost tracking, complexity analysis, model selection\n├── security/       # Sandbox, secret vault, prompt-injection scan, redaction\n├── skills/         # Loader, registry, executor, ClawHub client (34 bundled)\n├── subagent/       # Durable sub-agents, delivery outbox\n├── tools/          # Native tools: files, shell, web, todo, check-on-stop review\n├── evolution/      # Evidence-gated procedural skill learning and curation\n├── goals/          # Persistent, budgeted, verified autonomous goals\n├── workflow/       # Context-efficient validated tool DAG execution\n├── voice/          # STT (faster-whisper/Groq/OpenAI), TTS (Kokoro/OpenAI)\n├── cli.ts          # CLI entry point\n└── index.ts        # Library exports\n\nweb/                # React + Tailwind + Vite dashboard\n```\n\n</details>\n\n## Development\n\n```bash\nnpm run dev           # Dev mode with hot reload\nnpm test              # Run tests (Vitest)\nnpm run typecheck     # Type check\nnpm run build         # Production build (compiles TS + builds web dashboard)\n```\n\n## Research Validation\n\nScallopBot's design decisions independently converged on patterns validated by 30 research works from 2023--2026, published at venues including ICLR, NeurIPS, CHI, and ACM TOIS. Key alignments include:\n\n- **Hybrid retrieval**: Hu et al. (memory survey), Pan et al. (SeCom, ICLR 2025)\n- **Memory lifecycle**: Alqithami (MaRS forgetting benchmark), Yang et al. (graph memory taxonomy)\n- **Spreading activation**: Pavlovic et al. (activation in RAG), Yang et al. (relational dependencies)\n- **Dream cycles**: Zhang (computational account of dreaming)\n- **Affect modelling**: Mozikov et al. (emotional prompting effects), Lu & Li (affective memory)\n- **Self-reflection**: Shinn et al. (Reflexion, 91% HumanEval), Renze & Guven (reflection taxonomy)\n- **Proactive intelligence**: Pasternak et al. (PROBE), Liu et al. (Inner Thoughts)\n\nFor the full analysis, see [the paper](Paper2026.pdf).\n\n## License\n\nMIT\n\n---\n\n<p align=\"center\">\n  Built by <a href=\"https://github.com/tashfeenahmed\">@tashfeenahmed</a>\n</p>\n"}