ClawStash
by fo0
README.md
# ClawStash
**Persistent storage for AI agents.** Store text, code, configs, and files — retrieve them via MCP or REST API.
Built for agents like [OpenClaw](https://github.com/openclaw/openclaw) that need a reliable place to save and recall information across sessions.
## Why ClawStash?
AI agents lose context between sessions. ClawStash gives them a persistent memory:
- **Store anything** — code snippets, configs, notes, multi-file projects
- **Organize with tags & metadata** — structured key-value metadata and tags for easy retrieval
- **Full-text search** — find stashes by content, name, description, or tags
- **Token-efficient** — MCP tools return summaries first, full content only on demand
- **Version history** — every change is tracked, diffable, and restorable; the last 200 snapshots per stash are kept (`STASH_VERSION_LIMIT`, `0` = keep everything — [what gets deleted, and when](docs/deployment.md#stash_version_limit--the-one-variable-that-deletes-data))
- **Duplicate a stash** — open any stash as a pre-filled new one and use it as a template
- **Import files from disk** — drop text files onto the editor (or pick them) to add them as file rows, instead of copy-pasting each one
- **GitHub backup** — mirror all stashes into a GitHub repo (scheduled, on change, or manual) with "Sign in with GitHub" or a PAT — see [docs/backup.md](docs/backup.md)
- **Mermaid diagrams** — `.mmd` files and inline ` ```mermaid ` blocks in Markdown render as diagrams (lazy-loaded, no bundle bloat)
- **One-click code copy** — every fenced code block in rendered Markdown gets a copy button (keyboard reachable, always visible on touch)
- **Maximize a file** — blow any one file of a stash (HTML preview, Mermaid diagram, Markdown, code) up to fill the screen; the Restore button or a backdrop click restores it, Esc too once focus is outside the HTML preview
- **Web GUI included** — dark-themed dashboard to browse, search, and manage stashes manually, with a resizable sidebar that remembers its width
- **Update notice** — the footer says when a newer commit is on `main` and links to the commits since your build
## Get Started
### 1. Let your agent do it (recommended)
Copy this into your OpenClaw agent — it installs ClawStash, creates test stashes, and sets up MCP automatically:
```
Install ClawStash (ghcr.io/fo0/clawstash) on my server and set it up as your default persistent storage via MCP. Server: <HOST_OR_IP>, User: <SSH_USER>, Auth: <PASSWORD_OR_KEY>. Use port <PORT> (docker compose port mapping "<PORT>:3000"). Set ADMIN_PASSWORD to a secure value. After install: create an API token (scopes: read, write, mcp), create 2 test stashes to verify, then fetch /api/mcp-onboarding to read the full MCP spec and configure yourself. Details: https://raw.githubusercontent.com/fo0/clawstash/main/docs/openclaw-onboarding-prompt.md
```
Replace the `<...>` placeholders with your server details — your agent handles the rest.
> Step-by-step version: [docs/openclaw-onboarding-prompt.md](docs/openclaw-onboarding-prompt.md)
### 2. Manual setup
Run this on your server — no clone needed:
```bash
mkdir clawstash && cd clawstash && cat > docker-compose.yml <<'EOF'
services:
clawstash:
image: ghcr.io/fo0/clawstash:latest
ports:
- "3000:3000"
volumes:
- ./data:/app/data
environment:
- NODE_ENV=production
- DATABASE_PATH=/app/data/clawstash.db
# - ADMIN_PASSWORD=your-secret-password
restart: unless-stopped
EOF
docker compose up -d
```
Open http://localhost:3000 — done. Database persists in `./data/`.
> Change port mapping (e.g. `"8080:3000"`) for a different port. Uncomment `ADMIN_PASSWORD` to protect the instance.
> If login fails and the logs show `SQLITE_READONLY` (data directory created by an older version), run `sudo chown -R 1000:1000 ./data` once and restart — details in [Deployment → Bind mounts & file permissions](docs/deployment.md#bind-mounts--file-permissions).
After starting, hand your AI agent the onboarding prompt from **Settings → API & Tokens → MCP API** ("Copy onboarding prompt for your agent" — the token banner offers the same prompt with a freshly created token filled in). Or point the agent at the server's own guides:
```
GET http://<HOST_OR_IP>:<PORT>/api/agent-skill # SKILL.md — when to store, workflow, conventions, limits, errors, maintenance
GET http://<HOST_OR_IP>:<PORT>/api/mcp-onboarding # the skill plus the complete MCP specification (every tool's JSON Schema)
GET http://<HOST_OR_IP>:<PORT>/llms.txt # discovery index when the agent only knows the host
```
Connected via MCP, the agent gets the same guidance without fetching anything: the server hands out usage `instructions` on `initialize`, exposes the two guides as resources (`clawstash://guide/skill`, `clawstash://guide/onboarding`), and `get_server_info` returns the token's scopes, the callable tools, the size limits and every endpoint in one call.
## MCP Connection
Add to your MCP client config (OpenClaw, Claude Code, Cursor, etc.):
```json
{
"mcpServers": {
"clawstash": {
"type": "streamable-http",
"url": "http://<HOST_OR_IP>:<PORT>/mcp",
"headers": { "Authorization": "Bearer YOUR_TOKEN" }
}
}
}
```
Create API tokens in the web GUI under **Settings > API & Tokens** (scopes: `read`, `write`, `mcp`).
> **Breaking change — MCP tokens need `read` / `write`.** The `mcp` scope is a transport
> gate: it lets a token connect to `/mcp`, and nothing more. Each MCP tool is authorized
> separately, with the same scope its REST equivalent requires — `read` to read stashes,
> `write` for `create_stash`, `update_stash`, `archive_stash` and `delete_stash`. Until
> now the MCP endpoint checked only `mcp`, so a token carrying just that scope could write
> through MCP while every REST write route rejected it.
>
> **Who is affected:** anyone whose agent uses a token with `mcp` but without `write` (or
> without `read`). Its calls now come back as MCP tool errors naming the missing scope.
> **Fix:** issue a new token with `read`, `write` and `mcp` and swap it into the agent's
> MCP config. Expect to need this: the scope combination was recommended here and in
> [docs/openclaw-onboarding-prompt.md](docs/openclaw-onboarding-prompt.md), but the
> self-onboarding endpoint `GET /api/mcp-onboarding` and [docs/mcp.md](docs/mcp.md) named
> only `mcp` until this release — a token created by following those two must be reissued.
> Unaffected: tokens that already carry `read`/`write`/`mcp` (or `admin`), and the local
> **stdio** transport, which carries no token at all.
## MCP Tools
| Tool | What it does |
| ------------------- | -------------------------------------------------- |
| `create_stash` | Store new content with files, tags, metadata |
| `read_stash` | Get stash metadata + file list (content on demand) |
| `read_stash_file` | Read a single file — most token-efficient |
| `list_stashes` | Browse all stashes with summaries |
| `search_stashes` | Full-text search with ranked results |
| `update_stash` | Update existing stash content |
| `delete_stash` | Remove a stash |
| `archive_stash` | Archive/unarchive a stash without deleting |
| `list_tags` | List all tags with usage counts |
| `get_tag_graph` | Explore tag relationships |
| `get_stats` | Storage statistics |
| `get_rest_api_spec` | Fetch the OpenAPI 3.0 schema (JSON) |
| `get_mcp_spec` | Fetch the full MCP specification (markdown) |
| `refresh_tools` | Get latest tool specs (for connected agents) |
| `check_version` | Check for updates (with upgrade instructions) |
| `get_server_info` | Orient: scopes, callable tools, limits, endpoints |
## Documentation
| Doc | Content |
| --------------------------------------------------------- | ------------------------------------------------------ |
| [OpenClaw Onboarding](docs/openclaw-onboarding-prompt.md) | Copy-paste prompt for full agent-driven setup |
| [API Reference](docs/api-reference.md) | REST endpoints, examples, query parameters |
| [MCP Guide](docs/mcp.md) | MCP tools, token-efficient patterns, transport options |
| [Authentication](docs/authentication.md) | Admin login, API tokens, scopes |
| [GitHub Backup](docs/backup.md) | Mirror stashes into a GitHub repo: setup, security |
| [Deployment](docs/deployment.md) | Docker, CI/CD, GHCR, production setup |
## Development
**Prerequisites:** Node.js 22+ in practice. `package.json` declares `engines: { "node": ">=20.9.0" }`, so `npm install` prints an `EBADENGINE` warning below 20.9 — but `better-sqlite3` 13.x declares `engines: { "node": ">=22" }`, which warns on Node 20.x and 21.x as well. Docker and CI run Node 26.
```bash
git clone https://github.com/fo0/clawstash.git
cd clawstash
npm install
cp .env.example .env # adjust DATABASE_PATH / ADMIN_PASSWORD as needed
npm run dev # Next.js dev server at http://localhost:3000
npm run format # auto-format with Prettier (CI verifies formatting via format:check)
npm run lint # ESLint (correctness rules; formatting stays with Prettier)
npx tsc --noEmit # TypeScript type check (no npm script — CI runs this exact command)
npm test # vitest test suite (npm run test:watch for watch mode)
npm run build # production build
npm start # serve the production build
npm run mcp # MCP server (stdio transport, for local MCP client testing)
```
`docker-publish.yml` runs that same chain (`format:check` → `tsc --noEmit` → `lint` → `test` → `build`, in
that order) before it builds the image — but it is `workflow_dispatch`-only, so it does **not** run
on a push or a pull request. The only checks that run automatically on a PR are `docs-format.yml`
(Prettier on `**.md`) and GitHub's CodeQL analysis. The local chain above is therefore the real gate
for correctness: run it before every push.
See [CONTRIBUTING.md](CONTRIBUTING.md) for code-style rules and the PR workflow.
## License
[MIT](LICENSE)
This server cannot be deployed
Maintenance
ActivityActive
ResponsivenessResponsive