Skip to main content
Glama
Zenod

Zenod

Official
by zenod-ai
README.md
# Zenod

**An open-source AI memory agent with self-hosted and managed-hosted modes.**

Zenod is the interface between AI agents and your personal knowledge vault. Self-hosted Zenod uses
ordinary Markdown in your own GitHub repository; Zenod Hosted can use either a user-owned GitHub
repository or an app-created Google Drive vault, with real Git history in either case. Agents talk to Zenod through MCP; Zenod reads and writes the vault on their
behalf, enforcing its organization rules so memory compounds instead of rotting.

Named after [Zenodotus of Ephesus](https://en.wikipedia.org/wiki/Zenodotus), first librarian of the Library of Alexandria.

## Philosophy: self-hosted, user-owned

This repository contains both the **open-source self-hosted Zenod runtime** and the shared hosted
runtime deployed at `cloud.zenod.dev`. The deal is simple:

- **Your vault.** Plain markdown in a git repo in *your* GitHub account. Exportable with zero data loss — it's just files. Open it in Obsidian any time.
- **Your server.** One Docker container on your own VPS (we deploy ours with [Dokploy](https://dokploy.com)). One volume for state. No external services required beyond GitHub and the Anthropic API.
- **Your keys.** You bring your own Anthropic API key and GitHub token. They live on your box, configured through Zenod's own settings UI.
- **Auditable memory.** Every memory Zenod stores is a git commit in your vault. `git log` is the audit trail; every fact has a provenance link back to the evidence that produced it.

The hosted service uses the same engine and image with tenant-scoped storage, encrypted credential
custody, Google or GitHub sign-in, user-selected Drive or GitHub vault authority, Stripe billing, and
fail-closed production-readiness checks. GitHub issue/code tasking remains an optional connection;
memory and local Markdown backlog work do not require it. Self-hosting does
not depend on the hosted customer layer: if you can run a container, you never need the hosted service.

## What Zenod does

Two roles, one engine (full doctrine in [docs/LIBRARIAN-DOCTRINE.md](docs/LIBRARIAN-DOCTRINE.md)):

1. **The librarian** — runs on every message. Files the verbatim **evidence** (append-only, immutable, block-ID citations), then updates the living **meaning pages** (Areas, Projects, Notes) that the evidence touches, with a citation link for every claim. When unsure where something belongs, it asks instead of guessing.
2. **The compactor** *(later milestone)* — runs periodically. Merges duplicates, connects pages, tightens bloat. Adds no information.

Agents never get raw file CRUD. The write path is the product.

## Status

**Early access / hosted beta.** The engine, REST API, authenticated remote MCP endpoint, settings UI,
Docker image, multi-tenant hosted runtime, GitHub onboarding, subscription lifecycle, billing portal,
and production-readiness gate are implemented. Public paid signup remains closed automatically unless
live billing, legal version, tax handling, support contact, and a recent restore verification are all
configured.

## Quick start (self-host)

```sh
docker build -t zenod .
docker run -d --name zenod -p 8080:8080 -v zenod-data:/data zenod
```

Open `http://localhost:8080` and the setup wizard takes it from there: create an admin password, connect your vault repo with a GitHub fine-grained PAT (Contents: read & write), add your Anthropic API key, and copy the MCP connection snippet. All state — settings, conversation history, and the vault clone — lives on the single `/data` volume. If your vault is a plain Obsidian vault, Zenod adds the machine schema (`.brain/config.yml`, `Areas/`, templates) on first connect with a `schema: v1` commit.

Connect Claude Code to the deployed instance:

```sh
claude mcp add --transport http zenod https://your-host/mcp --header "Authorization: Bearer <token from settings>"
```

## Architecture at a glance

```
┌─────────────────────────── one container ───────────────────────────┐
│                                                                      │
│  Web UI (React/Vite/shadcn) ──┐                                      │
│  MCP endpoint (Streamable HTTP)├──► Brain engine ──► vault workdir   │
│  HTTP API / CLI ──────────────┘    store · ask · chat     │          │
│                                    search · get · lint    │ git      │
│  SQLite (settings, conversations,                         ▼          │
│  job queue) on a volume                          your GitHub vault   │
└──────────────────────────────────────────────────────────────────────┘
```

- **Engine spec:** [docs/M0-SPEC.md](docs/M0-SPEC.md)
- **Vault rules:** [docs/LIBRARIAN-DOCTRINE.md](docs/LIBRARIAN-DOCTRINE.md)
- **Self-test chat harness:** [docs/SELF-TEST-HARNESS.md](docs/SELF-TEST-HARNESS.md)
- **C1 deployment discipline:** [docs/C1-DEPLOYMENT.md](docs/C1-DEPLOYMENT.md)
- **Hosted production gate:** [docs/PRODUCTION-READINESS.md](docs/PRODUCTION-READINESS.md)
- **Stack:** TypeScript / Node 22+, Claude Agent SDK, simple-git, ripgrep, SQLite, React + Vite + shadcn/ui.

## License

[AGPL-3.0](LICENSE). Your vault content is yours; this license covers the code.