Skip to main content

graph-me

A local knowledge graph of your personal data (files, mail, WhatsApp) that your AI agent can query. Think graphify, for your own life.

Status: alpha (0.1.0). Search over files, mail, chats and contacts, people and birthdays, sync, use from Claude Code (skill + MCP server), Tier 1 AI enrichment and a local web UI. See CHANGELOG.md for what changed and docs/ for the design.

Install

graph-me runs on a Python managed by uv, so you don't need Python installed.

curl -LsSf https://astral.sh/uv/install.sh | sh     # once, if uv is missing
uv tool install --managed-python graph-me
graph-me init          # writes ~/graph-me/config.yaml from config-template.yaml
graph-me where

Edit config.yaml to list your sources. config-template.yaml documents every option.

graph-me scan                      # index your files (Tier 0: no AI, offline)
graph-me sync                      # later: add new items, update changed ones, forget deleted ones
graph-me query "lease agreement"   # cited results: path, snippet, source, date, trust
graph-me query "wifi" --json       # the context pack an agent receives
graph-me who "Sophie"              # a person: identifiers, facts, closest contacts
graph-me fact Sophie birthday      # one fact, with the messages and cards it came from

Tier 1: AI enrichment

uv tool install --managed-python "graph-me[medium]"   # adds the local model and sqlite-vec
graph-me enrich --dry-run    # how much there is to do
graph-me enrich              # agent mode: writes batch files for your agent, then embeds
graph-me ingest --all        # after your agent answered the batches

Tier 1 labels only short strings, so it stays cheap on large archives:

  • file names and folders get a type, a topic and keywords in English and French (the two languages of v1), so "rental contract" finds apartment_2025.pdf;
  • contacts get a relation to you ("sibling", "landlord"...), so "when is my sister's birthday?" finds Sophie without her name.

Who labels is up to you (extraction.medium.llm): your agent (default: no API key, just ask Claude Code "use graph-me to enrich the db"), a local Ollama model, the Claude API, or any OpenAI-compatible server. graph-me asks before sending names to an API. Every answer is checked against a strict schema; a label containing instructions, an unknown value or an unknown item is rejected, so a malicious file name can at worst get a wrong label.

Meaning-based search runs a small multilingual model on your computer (downloaded once, about 220 MB): "car insurance" finds "vehicle policy renewal". It is combined with word search.

Use it from Claude Code (or any MCP client)

graph-me install-skill                        # ~/.claude/skills/graph-me/SKILL.md
claude mcp add graph-me -- graph-me mcp       # read-only MCP server over stdio

Then ask: "use graph-me: where is the lease PDF my landlord emailed me, and when is my sister's birthday?". The MCP tools are search, find_document, who_is, get_fact, timeline, related, get_item and status. All are read-only, and none can reveal redacted secrets: an agent that just read a malicious email must not be able to ask for them. graph-me query "..." --format markdown gives the same results to agents without MCP.

After every scan and sync, graph-out/REPORT.md summarizes what was indexed, the people you deal with most, upcoming birthdays, communities and questions worth asking; graph.json holds the graph for other tools.

Web UI

uv tool install --managed-python "graph-me[ui]"
graph-me ui                  # opens http://127.0.0.1:<port>/?token=...

Four pages: Search (files, mails, chats and contacts, with filters by kind, source and date), Graph (people, projects and documents; coloured by kind or group; click a node to see its neighbours, double-click to open it), entity pages (identifiers, facts with their confidence, relations, latest items) and Status (sources, last runs, blacklist, flagged items). Every fact has a "Why do I know this?" link to the messages and files it came from.

The UI is read-only and runs on your machine only (127.0.0.1). The URL carries a random token, new at each start: anyone with it can read your graph while graph-me ui runs. Message HTML is never rendered, only its text, and redacted secrets stay redacted (graph-me query --reveal in a terminal is the only way to see them). The front-end libraries are bundled, so it works offline.

Keeping up to date, and forgetting

graph-me sync mirrors your sources. A file you delete, a message deleted in msgvault (for example spam deleted in Gmail and synced by msgvault), or a whole source removed from config.yaml is forgotten, along with everything learned only from it. A fact backed by something else stays: Sophie's birthday survives deleting one message if her contact card still says it. Sync is manual: run it when you want.

Two safety nets protect the index. A source that can't be reached (unplugged drive, missing folder, missing msgvault database) is skipped, never wiped. And a sync that would forget more than half of a source (above 50 items) stops and asks for --allow-mass-forget. Files that are still on disk but now skipped by your config (build folders, caches) don't count.

Mail, chats and contacts

We recommend msgvault for mail and chats: it syncs or imports Gmail, IMAP, Microsoft 365, MBOX, PST, WhatsApp, iMessage, Slack, Discord and more into a local archive. Add it as a msgvault source; graph-me reads its database read-only. msgvault is not required: graph-me builds its own people and facts from any connector's messages. For contacts without msgvault, point a vcard source at .vcf exports.

msgvault's Gmail login asks for the gmail.modify scope, used by msgvault's own deletion flow. graph-me itself never writes to msgvault or to your accounts.

People are recognized by email and phone number (never by name alone), so two "Sophie" stay two people. Birthdays come from contact cards, and from birthday wishes you sent to one person, with a confidence that grows each year the same date comes back. Set people.phone_country_code so national numbers ("07700 900123") match international ones ("+44 7700 900123").

Tier 0 uses no model at all, so results are less convincing than with AI: it matches words in file names and contents (English and French in v1, accents ignored). Secrets such as IBANs, card numbers, API keys and passwords are redacted in results unless you pass --reveal.

Principles

  • Local-first: your data stays on your machine.
  • Read-only: graph-me never writes, sends or deletes anything in your sources.
  • Free by default: Tier 0 uses no model and no network. Tier 1 and 2 add AI for better results.
  • Every fact is cited: answers point back to the file or message they came from.

Development

uv sync --all-extras
uv run pytest
uv run ruff check
uv run graph-me where      # inside the clone, data goes to ./graph-out
uv run python scripts/benchmark.py --config ~/graph-me/config.yaml   # scan time, DB size, query latency

The benchmark scans into a throwaway folder and prints numbers only (no names, paths or text), so its table is safe to share.

License

MIT

Metadata

Release files for graph-me 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for graph-me 0.1.0
File Size Uploaded
graph_me-0.1.0.tar.gz 372.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for graph-me 0.1.0
File Interpreter ABI Platform
graph_me-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 568.5 kB

Release files / graph_me-0.1.0.tar.gz

Download URL graph_me-0.1.0.tar.gz
Size 372.5 kB
Tags Source
SHA-256 checksum
How to use checksums
97c94e3e276139b7c856b39e7c2e6a87a1eab49dab5fcae8e826b44d9ea4562e
BLAKE2b-256 checksum
How to use checksums
51c27479696931a93ed7195015156befa092a6cfd6676d9cee8a3ea3659e76a6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / graph_me-0.1.0-py3-none-any.whl

Download URL graph_me-0.1.0-py3-none-any.whl
Size 196.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
664e87c5c41e2f2b68c6048b321ef419aa459a9cfa8568d003b3be8119821f9c
BLAKE2b-256 checksum
How to use checksums
5d84d4be0646da20658bb08a6bfae5ddb7f6746f3f81176e7aa0644025afd5c2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page