████████╗██╗ ██╗██╗███╗ ██╗ ╚══██╔══╝██║ ██║██║████╗ ██║ ██║ ██║ █╗ ██║██║██╔██╗ ██║ ██║ ██║███╗██║██║██║╚██╗██║ ██║ ╚███╔███╔╝██║██║ ╚████║ ╚═╝ ╚══╝╚══╝ ╚═╝╚═╝ ╚═══╝
> █
# a single source of truth every agent can read and write.
# hosted api · many surfaces · local-first llms · graph-native. write once, surface everywhere.
// 01 the graph
every document is a node. every extracted fact is an edge. every person, project, and class has exactly one canonical entity, so email #1 and meeting #400 referencing the same person resolve to the same graph node. an entity resolver does the work automatically.
// 02 philosophy
most memory systems die because the maintenance cost is higher than the capture cost. twin flips that: you drop anything in from any surface; auto-classifiers, auto-extractors, and an entity resolver do the organizing. every mention of a person, project, or class collapses into one canonical node.
1. ingest → connectors + share-sheet, zero friction 2. organize → auto-classify, resolve entities, extract facts 3. retrieve → hybrid vector + graph walk via mcp / chat
// 03 architecture
claude code (mcp) web chat (twin.arshsingh.net) telegram bot ios app + share-sheet browser extension cli
POST /ingest raw content in GET /search hybrid vector + graph GET /graph/walk n-hop entity neighbors GET /entities/:id canonical page + facts GET /export markdown dump, portable POST /mcp model context protocol
classify type, area, tags, title embed nomic-embed-text → vector extract-facts (subject, predicate, object) resolve-entity fuzzy + embedding → canonical merge contradiction → history sync per-connector pull loop
postgres + pgvector docs, facts, history qdrant vectors at scale neo4j (m2+) many-hop graph s3 / r2 attachments redis queue + cache
ollama (default) local, private, free qwen2.5:7b classify + extract nomic-embed-text embeddings claude sonnet chat + hard cases zero-retention + pii redaction pre-call
m1: gmail, gcal
m2: imessage, telegram, notion,
browser ext, screenshots
m3: discord, slack, github, rss,
voice (whisper)
// 04 surface
# mcp tools any agent can call. same api powers web chat, telegram, mobile.
| tool | synopsis | purpose |
|---|---|---|
| search | query [type] [area] [since] | hybrid vector + graph + recency rerank |
| graph_walk | entity_id [hops=1] | neighbors via shared facts + mentions |
| get_entity | name_or_id | canonical page + live facts + recent docs |
| add_note | text [type] [area] | manual ingest, auto-classified + linked |
| daily_brief | [date] [project] | today's meetings, open threads, action items |
| export_markdown | [scope] | portable obsidian-compatible vault dump |
| entity.merge | src dst | collapse duplicate canonical pages (audited) |
| entity.undo | audit_id | revert any auto-action from the audit log |
| review.approve | queue_id | confirm low-confidence auto-classifications |
| connector.add | kind [filters] | authorize gmail, gcal, notion, etc. |
// 05 phases
// 06 join waitlist
# twin is in private build. drop your email — you'll hear when alpha is ready.
// 07 field log
$ tail -n 20 /var/log/twin/ingest.log [2026-04-17 08:14] connector/gmail synced 42 new messages [2026-04-17 08:14] classify: 38 auto-filed, 4 queued for review [2026-04-17 08:15] resolve-entity: merged "sarah k" → [[alex-doe]] [2026-04-17 08:16] extract-facts: 61 triples → graph (ollama/qwen2.5) [2026-04-17 09:02] connector/gcal added meeting → [[project-alpha]] [2026-04-17 09:03] pre-linked 3 attendees from canonical people [2026-04-17 10:44] mcp/search "decisions affecting alpha" → 14 hits [2026-04-17 10:44] graph-walk 2 hops → 12 nodes, 22 edges [2026-04-17 12:30] contradiction: job-title fact superseded (valid_until set) [2026-04-17 12:30] history preserved · graph density 3.41 edges/node [OK]