granite-mem
v0.1.12
Published
Local-first markdown memory system for humans and AI agents: MCP server, typed knowledge graph, deterministic garden planning.
Maintainers
Readme
Granite
The personal OS your agent runs on. Markdown files. One SQLite index. A typed contract your agent already knows how to operate.
The wow moment
Paste this into Claude Code, Cursor, or any MCP-capable agent:
Install Granite as my personal OS.
1. `npm install -g granite-mem`
2. `granite init --template founder-os` (vault at ~/.granite)
3. `claude mcp add granite -- granite mcp --vault ~/.granite`
4. Restart yourself so the MCP server loads.
5. Call `granite_wakeup`, then propose three notes you would write
first based on what you know about me so far. Capture them as
drafts with --source agent.Sixty seconds later you have a live vault, a connected agent that knows how to use it, and three starter notes in ~/.granite/notes/. No system prompt. No config. No cloud.
That's the thesis of this project.
See it
What is Granite?
A local-first markdown store with an opinionated flow. No AI inside — just plain files on disk, indexed by SQLite, queried deterministically.
- Imposed flow. Capture, compile, query, output, lint. The shape is fixed; the content is yours.
- Four default note types —
note,source,synthesis,output. Add your own ingranite.ymlwhen your life grows a new shape. - A specialized MCP that teaches your agent how to use the vault. Drop any MCP-capable agent on it and it knows how to operate, no system prompt required.
Your agent brings the intelligence. Granite holds the ground truth.
Try it standalone
npm install -g granite-mem
granite init
granite serveThat starts with the default knowledge model: note, source, synthesis, and output. Add --template founder-os when you want people, organizations, meetings, and learnings wired in from the start.
Agent-native MCP
"A thin MCP server exposes capabilities. A strong MCP server shapes behavior."
Granite's MCP surface is intention-first:
granite_wakeupto orientgranite_research_topicto inspect existing knowledge before writinggranite_queryfor structured filters over typed notesgranite_compile_contextto assemble a graph-aware briefgranite_plan_gardento decide what to improve nextgranite_capture_knowledgeto write with protocol fields and type contracts
The point is not to give an agent a file browser. The point is to give it a workflow it can follow.
Types as active contracts
This is what makes the agent feel native rather than bolted-on.
# granite.yml — every note type is an executable contract
note_types:
meeting:
folder: notes/meetings
fields:
date: { type: date, required: true }
organization: { type: wikilink, target_types: [organization] }
attendees: { type: wikilink, target_types: [person] }
on_create:
- { action: set_default, field: date, value: "${today}" }
- { action: resolve_wikilinks, fields: [organization, attendees], auto_stub: true }
indexed_fields: [date, organization]
lifecycle:
states: [active, archived]
transitions:
- { from: active, to: archived, trigger: stale_days, days: 180 }set_default— fills${today}automaticallyresolve_wikilinks + auto_stub— turnsorganization: Acme Corpinto the slugacme-corp, creating the org note if missing (with a globally-unique slug so nothing gets silently overwritten)indexed_fields— makesgranite_query { type: meeting, where: { date: { gte: "2026-01-01" } } }O(1) and deterministiclifecycle—granite doctorsurfaces stale notes so gardening never drifts
Add a type when your life has a new shape. The core stays small. For the formal protocol, see docs/GRANITE_OBJECT_STANDARD.md.
Templates
granite init # minimal: note / source / synthesis / output
granite init --template founder-os # + person / organization / meeting / learningfounder-os is the full personal-OS starter: people you talk to, orgs you work with, meetings you had, things you learned. Eight types, already wired with hooks, indexed fields, and lifecycles. Open templates/founder-os.yml — it's 150 lines of pure YAML.
The hard boundary
Granite will never:
- embed an LLM, run prompts, or hold an API key
- compute embeddings or ship a vector store
- run background agents or a scheduler
- add overlapping CLI/MCP endpoints that blur the loop
This is why your agent can be trusted with write access. The vault is a deterministic substrate. The intelligence is yours (or Claude's, or GPT's, or whoever you pay this quarter).
Protocol fields
Every note carries five shared fields so humans and agents share ground truth:
| Field | Values | Purpose |
|----------------|---------------------------------------|--------------------------------------|
| status | inbox · active · archived | operational state |
| source | human · agent · extraction | who wrote it |
| review_state | draft · reviewed · locked | editorial state |
| durability | canonical · working · ephemeral | keep / may drift / throwaway |
| derived_from | [slug, …] | provenance for syntheses and outputs |
Your agent reads these before writing and sets them as it works. You inherit a fully auditable trail.
Local-first, by design
- Markdown files are the source of truth; the SQLite index in
~/.granite/index.dbis derived state and can be rebuilt at any time - no cloud, no telemetry, no account
git inityour vault and you have versioning for freegranite servegives you a local web UI — browse, search, explore local and cloud graphsgranite daemon startruns MCP + web UI in one background process
Your vault in the cloud
One command deploys a personal serverless Granite on Fly.io Sprites: a real persistent filesystem, an MCP endpoint that wakes on request (100–500 ms warm) and sleeps when idle. Idle cost ≈ storage only — a markdown vault is a few MB, so cents per month.
export SPRITES_TOKEN=… # from sprites.dev — your account, your sprite, your data
npx granite-mem deployOr store the Sprites API token once in a user-scoped Granite credentials file:
granite deploy login --token <sprites-token>That writes ~/.granite/config/sprites.json (mode 0600 where supported). It works on macOS, Linux, and Windows via the user's home directory. Commands resolve credentials in this order: --token, SPRITES_TOKEN, then the stored file. Remove it with granite deploy logout.
That prints an MCP URL + bearer token ready to paste into Claude Code or Cursor:
claude mcp add --transport http granite https://<your-sprite>.sprites.app/mcp \
--header "Authorization: Bearer <token>"There is no central admin, no Granite cloud account, no relay: granite deploy provisions a sprite you own and pay for directly.
Manage instances from any machine after deploy login, or with SPRITES_TOKEN:
granite deploy login --token <sprites-token>
granite deploy work # a second instance (own vault, own token, own URL)
granite deploy list # all instances: version, health, MCP URL
granite deploy status --show-token
granite deploy # re-run = upgrade that instance to your CLI version
granite deploy --all # bulk remote update of every instance
granite deploy destroy work # permanent — asks for confirmationBrowse local and deployed vaults from the same local UI:
SPRITES_TOKEN=… granite servegranite serve discovers your managed Sprites using SPRITES_TOKEN or the stored ~/.granite/config/sprites.json token. It keeps MCP bearer tokens on the local server and proxies read-only graph/search/note requests to the selected cloud instance. Use granite serve --no-cloud to browse only the local vault.
Notes:
- Document parsing (PDF/DOCX/XLSX/PPTX) is disabled in cloud deployments (
GRANITE_DISABLE_DOCUMENT_PARSING=1). Extract and import documents on your local Granite. - Cloud instances expose MCP plus an authenticated read-only web API for the local UI switcher; note creation in the web UI remains local-only.
- The Sprites API token is local user configuration at
~/.granite/config/sprites.json; it is not written to the vault notes and is excluded from Granite sync manifests. - The vault lives at
/home/sprite/.graniteon the sprite, on durable object-storage-backed disk. There is no export/backup command in v1 — treat the sprite as the single copy for now.
Advanced: run the HTTP MCP server yourself
Granite can expose the MCP server over HTTP anywhere you can run Node. When binding outside localhost, a bearer token is required:
export GRANITE_MCP_TOKEN="$(openssl rand -hex 32)"
granite mcp --vault ~/.granite \
--transport http \
--host 0.0.0.0 \
--port 3321 \
--web-apiClients must send the token on every MCP request:
claude mcp add --transport http granite https://granite.example.com/mcp \
--header "Authorization: Bearer $GRANITE_MCP_TOKEN"A generic Dockerfile is included for self-hosting on your own infra (build it yourself; no public image is published). The /health endpoint is unauthenticated for platform checks. Do not expose granite serve or the web UI port 4321 on the public internet; the web UI is local-only and has no authentication. If --web-api is enabled on the HTTP MCP server, /api/* and /assets/* are guarded by the same bearer token as /mcp.
Direct sync
Granite sync is direct machine-to-machine. Run it over LAN, Tailscale, or a private DNS name; there is no relay, hosted worker, billing tier, or cloud authority.
# Machine A
granite sync access grant ipad --role read
granite sync access grant desktop --role write
granite sync serve --host 0.0.0.0 --port 8765
# Read-only Machine B
granite sync remote add macbook http://100.x.y.z:8765 --token <read-token>
granite sync pull macbook
granite sync watch macbook --direction pull --interval 30
# Write-capable Machine C
granite sync remote add macbook http://100.x.y.z:8765 --token <write-token>
granite sync run macbook
granite sync watch macbook --interval 30Conflicts default to manual preservation with .conflict.<device>.<timestamp>.md files. For a personal multi-device setup, pick the device that wins conflicts:
granite sync config --policy primary-wins --primary-this-deviceMCP is scoped to one vault per server. Launch a read-only MCP server when an agent should inspect a synced vault without mutating it:
granite mcp --vault ~/.granite --role read
granite mcp --vault ~/.granite --role writeFor the full CLI, run granite --help. For development, see CLAUDE.md.
Roadmap & status
Granite is pre-1.0. The current release is v0.1.9, with the major agent-native loop pieces now in place: typed contracts, wakeup snapshots, deterministic garden planning, document import, daemon mode, and the constellation graph.
Read CHANGELOG.md for release history. The product boundary stays fixed: Granite stores and indexes local knowledge; agents bring the intelligence.
Contributing
Issues and focused PRs are welcome.
For local development, read CLAUDE.md. The key product rule is simple: no embedded LLM, no vector store, no autonomous scheduler inside Granite.
Karpathy wrote that there was room for "an incredible new product instead of a hacky collection of scripts" around LLM knowledge bases.
Granite is the product that answers that call.
Philosophy
- local-first beats cloud dependence for personal memory
- plain markdown beats proprietary formats
- types as active contracts beat types as folders
- tools for humans should also be legible to agents
- protocol belongs in the core; agent policy belongs outside it
- a personal OS is a thing you own — not a thing you rent
