Montauk
README.md
# Montauk
Relationship memory for personal agents. An MCP server giving a personal-assistant agent
durable, private, human-readable memory of the people in one human user's life.
The canonical database is a directory of Markdown person files (`data/people/*.md`). SQLite
and a semantic vector index are derived, fully disposable acceleration layers that can be
deleted and rebuilt at any time without data loss. See `montauk_phase1_build_spec.md` for the
full Phase 1 specification this implementation follows.
## Quick start (local, stdio)
```bash
uv sync
uv run montauk init --data-dir ~/.local/share/montauk
uv run montauk agents create --name my-agent --role read_write --data-dir ~/.local/share/montauk
# prints a token once -- save it
export MONTAUK_AGENT_TOKEN=<the token printed above>
uv run montauk serve --config ~/.local/share/montauk/config.yaml
```
`serve` reads `MONTAUK_AGENT_TOKEN` once at startup to resolve the single stdio client's
identity (there is exactly one client on stdio, so there's no per-request header to read).
Point an MCP-compatible agent host at that `serve` command as a local stdio server. Try it
against the bundled Simpsons fixture instead of an empty repo by pointing `--data-dir` at
`examples/simpsons/`.
## Setting up your private data repository
`montauk init` scaffolds a deployment: it creates the data directory (`people/`, `archive/`),
writes a starter `config.yaml`, and initialises a **local** git repository for the canonical
Markdown -- on branch `main`, with an initial commit, and a `.gitignore` that excludes the
derived indexes (`index/`), agent credentials (`auth/`), and logs.
```bash
uv run montauk init --data-dir ~/.local/share/montauk
```
Choose a data directory **outside** this source checkout -- `~/.local/share/montauk` for a
personal deployment, `/var/lib/montauk` for a system service. Never put it inside a synced
folder (Dropbox/iCloud/Drive): sync races corrupt the git repo and it copies plaintext personal
data to a third party.
This data repository holds real personal information, so keep it **private and separate** from
the Montauk source code. Montauk deliberately never adds a git remote and never pushes (spec
§29) -- that is yours to wire up:
```bash
cd ~/.local/share/montauk
# create an EMPTY private repo on your git host first (no README / license / .gitignore)
git remote add origin git@github.com:<you>/<your-data-repo>.git
git push -u origin main
```
While `montauk serve` runs it makes at most one local commit per day, when a person file has
changed. Pushing those commits to your remote is up to you -- e.g. a cron entry:
```
15 3 * * * cd ~/.local/share/montauk && git push -q origin main
```
`montauk init` is idempotent and never clobbers an existing `config.yaml`, so it is safe to
re-run.
## Configuration
Non-secret settings live in a YAML config file; copy `config/config.example.yaml` and adjust
`data_dir`, transport mode, git snapshot time, and search/embedding settings. Validate a config
without starting the server:
```bash
uv run montauk config-check --config config.yaml
```
Secrets are never read from config files -- agent credentials live in
`<data_dir>/auth/credentials.sqlite`, managed only via `montauk agents ...`. See `.env.example`
for the one environment variable the stdio transport reads (`MONTAUK_AGENT_TOKEN`).
## Admin CLI
```
montauk init --data-dir PATH # scaffold a new deployment + private data repo
montauk validate # scan + validate; exit 1 if unhealthy
montauk status # health summary
montauk rebuild-index # rebuild the derived SQLite index from Markdown
montauk rebuild-vectors # rebuild the derived semantic index from Markdown
montauk git-snapshot # commit data/people + data/archive now, if changed
montauk agents list
montauk agents create --name X --role read_only|read_write
montauk agents revoke <agent-id>
montauk config-check --config config.yaml
montauk serve # the only long-running command
```
Every command accepts `--data-dir PATH` for quick/direct use, or `--config PATH` to load a full
YAML config (data-dir overrides the config's `data_dir` if both are given). Person *content* is
never edited through this CLI -- only through MCP tools or by hand-editing the Markdown directly
(changes take effect after the next server restart or `rebuild-index`).
## Remote (authenticated HTTPS) deployment
Set `transport.mode: remote` in the config. Montauk refuses to start a remote transport bound to
`0.0.0.0`/`::` unless auth is configured (it is, by default) -- put a TLS-terminating reverse
proxy in front for real internet-facing deployments; Montauk itself only speaks plain HTTP.
Each remote agent authenticates with `Authorization: Bearer <token>` from
`montauk agents create`.
## Docker
```bash
docker build -t montauk-mcp .
docker volume create montauk-data
docker run --rm -v montauk-data:/data montauk-mcp agents create --name my-agent --role read_write --data-dir /data
docker run --rm -i -v montauk-data:/data -e MONTAUK_AGENT_TOKEN=<token> montauk-mcp serve --data-dir /data
```
The image pre-downloads the default embedding model at build time, so a fresh container needs
no network access on first run. Persistent data (`/data`) is a volume, never baked into the
image.
**Bind mounts and file ownership:** the container runs as a non-root user (uid 1000). A Docker
*named volume* (as above) works out of the box -- Docker initializes it from the image's `/data`
ownership on first use. A host *bind mount* (`-v /path/on/host:/data`) does not: the host
directory's existing ownership wins, so if it isn't already owned by uid 1000, `montauk` won't be
able to write to it. Either `chown -R 1000:1000` the host directory first, or run the container
with `--user "$(id -u):$(id -g)"` to match your host user instead.
## Development
```bash
uv sync
uv run pytest
```
`examples/simpsons/` is a synthetic fixture (recognizable fictional characters, not real people)
used by the test suite and handy for manual exploration -- it includes a duplicate-name
collision, a missing-birth-year birthday, a person with a contact cadence but no recorded
interactions, an archived person, and one deliberately malformed file, exercising the
corresponding edge cases end to end.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues