{
  "markdown": "<h1 align=\"center\">Titen</h1>\n\n<p align=\"center\">\n  <strong>Agent memory that runs with no API key, no LLM, and no embedding provider.</strong><br>\n  Every memory keeps its source, who may read it, and the evidence that contradicts it.\n</p>\n\n<p align=\"center\">\n  <a href=\"https://titen.dev\"><img src=\"https://raw.githubusercontent.com/RamaAditya49/titen/main/docs/assets/readme/titen-hero.svg\" alt=\"Titen — self-hosted agent memory with no API key and no LLM. Zero LLM calls, zero embedding calls, dependencies empty, and recall@1 0.880 on LongMemEval-S in the per-instance scoped condition, which falls to 0.524, 0.364, 0.308 and 0.246 as the store pools to 1k, 5k, 10k and 19,829 sessions\" width=\"100%\"></a>\n</p>\n\n<p align=\"center\">\n  <a href=\"https://titen.dev\"><strong>Website</strong></a> ·\n  <a href=\"https://github.com/RamaAditya49/titen/blob/main/docs/README.md\">Documentation</a> ·\n  <a href=\"https://www.npmjs.com/package/titen-memory\">npm</a> ·\n  <a href=\"https://github.com/RamaAditya49/titen/blob/main/CHANGELOG.md\">Changelog</a>\n</p>\n\n<p align=\"center\">\n  <a href=\"https://www.npmjs.com/package/titen-memory\"><img alt=\"npm version\" src=\"https://img.shields.io/npm/v/titen-memory?style=flat&amp;labelColor=3E3630&amp;color=A9552A\"></a>\n  <a href=\"https://www.npmjs.com/package/titen-memory\"><img alt=\"npm downloads\" src=\"https://img.shields.io/npm/dm/titen-memory?style=flat&amp;labelColor=3E3630&amp;color=223A57\"></a>\n  <a href=\"https://github.com/RamaAditya49/titen/blob/main/LICENSE\"><img alt=\"Apache-2.0 license\" src=\"https://img.shields.io/badge/license-Apache--2.0-171310?style=flat&amp;labelColor=3E3630\"></a>\n</p>\n\n<p align=\"center\">\n  Built with <a href=\"https://cadis.digital/\">C.A.D.I.S Agent</a>.\n</p>\n\n## Try it in 30 seconds\n\nNo account, no key, no configuration — but the CLI runs on\n**[Bun](https://bun.sh/) 1.2 or newer**, and refuses to start without it:\n\n```bash\ncurl -fsSL https://bun.sh/install | bash   # skip if you already have Bun\nnpx titen-memory mcp\n```\n\nWith no environment set, that opens or creates `~/.titen/memory.db`, writes a\nreal organization, workspace, project and owner into it, and serves MCP over\nstdio in-process — no HTTP hop, no key to paste, and **no outbound network\ncall**. Retrieval is FTS5, so nothing needs an embedding provider or a model.\n\n`curl -fsSL https://titen.dev/install.sh | bash` does the same in one step: it\nadds Bun when it is missing, then installs the `titen` command.\n\nPoint an agent at it:\n\n```bash\nclaude mcp add --transport stdio --scope user titen -- npx -y titen-memory mcp\n```\n\nAlready using `@modelcontextprotocol/server-memory`? Titen serves the same nine\ntool names with the same schemas, and answers `memory://knowledge-graph` too, so\na client does not notice the swap. On the first local-mode start it imports your\nexisting graph. **Pass the old store's path**, because that server writes beside\nits own install rather than in the directory you launch it from:\n\n```bash\nclaude mcp add --transport stdio --scope user titen \\\n  --env MEMORY_FILE_PATH=/path/to/memory.jsonl -- npx -y titen-memory mcp\n```\n\nWithout it Titen still checks the working directory, its `node_modules`, and\nnpm's `npx` cache — and says on stderr when it found nothing, rather than\nstarting empty in silence. Point `titen` at a served instance later by setting\n`TITEN_MCP_URL` and `TITEN_API_KEY` — [full setup below](#install-and-connect-an-agent).\n\nAudit what any agent memory store has accumulated, including one Titen does not\nown:\n\n```bash\nnpx titen-memory audit ./memory.json\n```\n\n## What is different about it\n\n- **No provider, no key, no account.** FTS5 lexical retrieval is the default\n  operating point, not a fallback. Embeddings and model enrichment are opt-in\n  projections that degrade cleanly when they are absent.\n- **No runtime dependencies.** `package.json` declares none. What it needs is\n  Bun and one SQLite file; everything else is the standard library and Web APIs.\n- **Drop-in for `@modelcontextprotocol/server-memory`.** Eighteen tools — the\n  nine `titen_*` plus the nine reference-server names — with `search_nodes`\n  routed through real retrieval rather than a substring scan, and your existing\n  `memory.json` imported on first run.\n- **It audits stores it does not own.** `titen audit` reads a reference-server\n  `memory.json`, a Mem0 export, or a Titen store, and reports duplicates,\n  recall loops, secret patterns and staleness with per-item evidence you can\n  check by hand.\n- **The benchmark publishes the losses.** Two of the five pre-registered\n  falsifiers fired against Titen, and they are printed on the chart below\n  rather than left out of it.\n\n## Already running `@modelcontextprotocol/server-memory`?\n\nThat server had **106,662 downloads in the week of 31 July 2026** — it is the\ndefault memory for a large part of the MCP ecosystem, and it is deliberately\nminimal. Reading its published `2026.7.4` tarball: the store is one\nnewline-delimited JSON file rewritten in full on every mutation, and a search is\n\n```js\ngraph.entities.filter(e => e.name.toLowerCase().includes(query.toLowerCase()) || ...)\n```\n\n`String.includes` on a lowercased needle. No tokenizer, no stemming, no ranking\n— results arrive in insertion order — no scoping or authorization, and no\neviction, so the file grows without bound and every call is O(n) in the whole\ngraph. Ask it *\"which service handles refunds\"* and it matches nothing unless\nthat exact sentence is stored.\n\nTiten answers the same nine tool names, with the same argument schemas, and the\nsame `memory://knowledge-graph` resource, so a client does not notice the swap.\nWhat changes is underneath: `search_nodes` runs the real retrieval path — FTS5\nwith stemming, ranked best-first, and the vector index when one is configured —\nand every read is scoped to a subject and filtered by authorization before it is\nretrieved, not after.\n\n| | `@modelcontextprotocol/server-memory` | Titen |\n| --- | --- | --- |\n| Search | `String.includes`, insertion order | FTS5 + stemming, ranked, optional vectors |\n| Scope | the whole graph, always | org / subject / project / workspace, enforced pre-retrieval |\n| Contradictions | overwritten | kept, linked to evidence, flagged |\n| Growth | full-file rewrite, unbounded | SQLite, retention and eviction policies |\n| Provider | none | none — no key, no LLM, no embedding provider |\n\nImport is on first start; [the switch is above](#try-it-in-30-seconds).\n\n## Audit any agent memory store\n\nEvery published memory benchmark measures retrieval on a corpus somebody\ncurated. The failure people actually report is on the write side: a store fills\nwith copies of its own output. The one public audit of a production store found\n97.8% of 10,134 entries were junk after 32 days. Nothing measures that.\n\n```sh\nnpx titen-memory audit ~/.titen/memory.db        # a Titen store\nnpx titen-memory audit ./memory.jsonl            # @modelcontextprotocol/server-memory\nnpx titen-memory audit ./mem0-export.json --json # a Mem0 export\n```\n\nFive counts — exact duplicate, near duplicate, recall loop, secret pattern,\nstale — each with per-item evidence you can check by hand. **No network, no\nmodel, no upload:** it opens the path read-only and prints a report; sharing it\nis your decision. A store that lacks the signal a metric needs is reported as\n*not measurable from this export*, never as a failure. There is no composite\nscore and there is no leaderboard.\n\nThe detection rules are published in\n[audit rules](https://github.com/RamaAditya49/titen/blob/main/docs/reference/audit.md).\nTiten's own numbers — including 17.9% duplicates and 96.7% stale in its own\nstore, and a compatibility-surface defect the tool found in Titen itself — are in\n[the self-report](https://github.com/RamaAditya49/titen/blob/main/docs/testing/2026-08-07-titen-audit-self-report.md).\n\n## You author the claims\n\n**Titen's default memory model is caller-authored claims.** `consolidate()`\ntakes statements you wrote, each explicitly linked to a source observation you\nalready recorded. Titen does not read a transcript and decide on its own what is\nworth remembering.\n\nThat is deliberate. Every claim has an author, a source, and a scope, which is\nwhat makes provenance, permission, conflict, and audit answerable at all. It is\nalso a real cost, and it is the honest comparison point: systems that derive\nmemory from raw dialogue do work Titen hands back to you.\n\nModel-assisted derivation and reflection are implemented and ship in the\npackage, but they are activation-gated and **no candidate model has passed the\ngate** — the best result on record is 65.56% against a 90% contract threshold.\nTreat them as unfinished work with a public gate, not as a feature you can\nsimply switch on. The [roadmap](https://github.com/RamaAditya49/titen/blob/main/docs/ROADMAP.md#maturity-matrix)\ncarries the current evidence.\n\n<p align=\"center\"><img src=\"https://raw.githubusercontent.com/RamaAditya49/titen/main/docs/assets/readme/titen-flow.svg\" alt=\"The kernel loop in four steps under one authorization and evidence boundary: observe posts an observation with a required source ref, consolidate posts caller-authored claims linked to those observations, compile returns a bounded context pack with scope applied before retrieval and every item marked untrusted, and evidence walks a claim back to its supporting, contradicting and qualifying observations\" width=\"100%\"></p>\n\n## The questions Titen answers\n\n| Question | Titen's answer |\n| --- | --- |\n| Where did this memory come from? | Every claim points back to source observations and keeps its version history. |\n| May this agent see it? | Organization, subject, project, workspace, and visibility checks run before retrieval. |\n| What if two sources disagree? | Contradictions remain visible until an explicit lifecycle action resolves them. |\n| Who is doing the work? | Leases prevent silent double ownership; checkpoints and handoffs make work resumable. |\n| Can we audit or move it? | Canonical records live in SQL, with authenticated audit trails and versioned JSONL export/import. |\n| Do we need an LLM or vector database? | No. The default install is FTS-only with no provider at all; embeddings and model enrichment are opt-in projections. Whether the vector arm helps depends on the store shape — [see below](#measured-against-the-field). |\n\nAgents connect through authenticated REST, Streamable HTTP MCP, the `titen mcp`\nstdio bridge, or the TypeScript SDK. Titen never treats retrieved memory as an\ninstruction, and it does not run agent loops.\n\n## Measured against the field\n\nOn [LongMemEval-S](https://github.com/xiaowu0162/LongMemEval) (MIT, externally\nauthored, 500 instances, 246,930 turns), our own scorer, failures kept in the\ndenominator, protocol pre-registered before each run. Full table and method at\n[titen.dev/benchmark](https://titen.dev/benchmark).\n\n**Every figure below names its condition, because the condition moves recall@1\nby 63 points on the same corpus.** *Per-instance (scoped)* gives each question\nits own ~50-session haystack — the single-subject shape a product actually\nserves. *Pooled* puts all 19,829 sessions in one unscoped store and asks the\nsame 500 questions. These are two conditions of one corpus, not two\nmeasurements of one thing, and a number quoted without its condition is\nmeaningless.\n\n<p align=\"center\"><img src=\"https://raw.githubusercontent.com/RamaAditya49/titen/main/docs/assets/readme/titen-benchmark.svg\" alt=\"LongMemEval-S recall@1, n=500, in two store conditions on separate axes. Per-instance scoped: Titen FTS+vector 0.900, Titen FTS-only 0.880, verbatim-RAG router control 0.854, MemPalace 0.804. Pooled across all 19,829 sessions: Titen FTS-only 0.246, Titen FTS+vector 0.212, Mem0 infer=False 0.182, router control 0.174, MemPalace 0.164, fastembed control 0.124. Caveats printed on the chart cover the sign tests, the vector arm reversing sign between conditions, the two fired falsifiers, and the flat answer-accuracy null\" width=\"100%\"></p>\n\n### Condition A — per-instance (scoped)\n\n| Lane, n=500, `titen-memory` 0.6.0 | recall@1 | MRR@10 | LLM calls | embedding calls |\n| --- | ---: | ---: | ---: | ---: |\n| Titen 0.6.0, FTS + vector | **0.900** | 0.9384 | 0 | 4,989 |\n| Titen 0.6.0, FTS-only | 0.880 | 0.9147 | **0** | **0** |\n| verbatim-RAG control (~100 lines of cosine) | 0.854 | 0.9067 | 0 | 877 |\n| MemPalace 3.6.0 | 0.804 | 0.8717 | 0 | — |\n\n**This condition barely separates anything.** recall@10 is 0.982 and saturated,\nwith 2.2 points of spread across the serious lanes. Exactly one of the three\npaired sign tests reaches significance, and it does not say what it looks like\nit says:\n\n- FTS+vector vs the dense control: 35/12/453, **p = 0.0011** — significant.\n- FTS+vector vs FTS-only: 27/17/456, p = 0.174 — **the vector arm is not proven\n  to be the cause of that win.**\n- FTS-only vs that control: 44/31/425, p = 0.165 — not significant.\n\n**We do not beat Mem0's LLM-free mode here.** Mem0 `infer=False` scores 0.8667\non the shared n=60 subsample, and Titen FTS+vector against it is 3/4/53,\n**p = 1.0** — indistinguishable. Its default `infer=True` mode spends 2,981 LLM\ncalls to score *lower* (0.8333), so Mem0's own extraction bought nothing\nmeasurable here. Any cost claim must name the configuration it measured.\n\n**Answer accuracy is a flat null.** With one reader pinned across every lane,\neight pre-registered comparisons produce nothing significant (best p = 0.41).\nRetrieval significance does not transfer to answers.\n\n### Condition B — pooled, all 19,829 sessions in one store\n\n| Lane, pooled 19,829, `titen-memory` 0.7.0 | recall@1 | MRR@10 | tax vs its own per-instance cell |\n| --- | ---: | ---: | ---: |\n| **Titen 0.7.0, FTS-only** | **0.246** | 0.3259 | −63.4 |\n| Titen 0.7.0, FTS + vector | 0.212 | 0.3153 | −68.8 |\n| Mem0 OSS 2.0.15 `infer=False` | 0.182 | 0.2716 | −68.5 ¹ |\n| verbatim-RAG control, router embeddings | 0.174 | 0.2459 | −68.0 |\n| MemPalace 3.6.0, published shape | 0.164 | 0.2152 | −64.0 |\n| verbatim-RAG control, fastembed | 0.124 | 0.1868 | −64.8 |\n| MCP reference server | 0.000 | 0.0000 | could not serve a store this size at all |\n\n¹ against Mem0's n=60 per-instance cell, not n=500.\n\n**Titen's zero-provider lane is significantly above every measured competitor at\nthis condition** — every pair below is written Titen-first, wins/losses/ties:\n86/25/389 (**p < 0.0001**) against the fastembed control, 76/35/389\n(**p = 0.0001**) against MemPalace, 59/27 (**p = 0.0007**) against Mem0\n`infer=False`, 65/29 (**p = 0.0003**) against the router control. Those are the\nfirst significant lane-vs-lane retrieval separations this programme has produced\non this corpus, at 363.8 s of ingest with zero provider calls against Mem0's\n3,953 s and 205,641 embedding calls.\n\n**Two of the five pre-registered falsifiers fired against Titen, and they get the\nsame prominence as that win.**\n\n- **The prediction was wrong by more than 45 points.** We pre-registered\n  full-pool recall@1 at 0.70–0.85 and measured **0.246**. LongMemEval-S personas\n  share topics by construction, so pooling makes the store *denser* in\n  cross-persona near-duplicates rather than sparser: all 377 rank-1 misses\n  retrieved a cross-instance session, and **zero** retrieved a wrong session\n  from the question's own haystack.\n- **Compile p95 is 864.9 ms against our own pre-registered 250 ms kill line**,\n  already crossed at the 10,000-session cell (430.8 ms). Published anyway, as\n  promised.\n\nNobody's architecture escapes the pooled tax — MemPalace loses 64.0 points and\nthe strongest dense control 68.0, against Titen's 63.4. And **the vector arm\nreverses sign between the conditions**: +2.0 points per-instance (unproven,\np = 0.174) and **−3.4 points pooled** (0.212 against 0.246, p = 0.082), at 2.8x\nthe compile latency after a 9,054 s index drain. Three embedding families now\nland 7.2–16.8 points below FTS-only at pooled density, so the vector arm is\ndocumented for scoped stores only. Full report:\n[the pooled-store condition](https://github.com/RamaAditya49/titen/blob/main/docs/testing/2026-08-07-pooled-store.md).\n\n### Scoping is the largest lever we have measured\n\nSame corpus, same tarball, same 500 questions — one arm scoped to its subject,\none not:\n\n| Store shape, `titen-memory` 0.7.0 | recall@1 | compile p95 |\n| --- | ---: | ---: |\n| Subject-scoped anchor, 424,168 claims | **0.880** | **138.1 ms** |\n| Unscoped pooled, 342,129 claims | 0.246 | 864.9 ms |\n\n**+63.4 points of recall@1 and 6.3x less latency.** That is the measured value\nof authorization-before-retrieval, and the measured answer to \"just scope by\n`user_id`\" — scoping *is* the authorization layer, and Titen's runs before\nretrieval by construction.\n\nThe FTS-only curve across store shapes is 0.880 scoped, then 0.524 / 0.364 /\n0.308 / 0.246 at 1k / 5k / 10k / 19,829 pooled sessions. Do not read the 0.880\nwithout it.\n\n### The improvement cycle failed every gate\n\nOn 2026-08-08 we pre-registered a cycle to move those numbers — a candidate cap\nfor latency, six ranking variants, and a third embedding family — and **every\ngate in it failed. Nothing shipped.** All six ranking variants failed their gate:\nterm coverage −2.4, proximity −14.4, chunk-sum −11.8, combined −3.6, a local\ncross-encoder −1.2 at +642 ms per compile, RRF fusion +0.2 at p = 1.0. The five\nthat were run against the scoped anchor regressed that too. The candidate cap\nwas worth **4.5%** of p95 against a predicted 30–60%, so the latency falsifier\nstands. The third embedding family scored 0.078. Full report:\n[the pooled-improvement cycle](https://github.com/RamaAditya49/titen/blob/main/docs/testing/2026-08-08-pooled-improvements.md).\n\nThat failure bought two things, both evidence rather than features:\n\n- **The shipped ranking is now ablation-backed, not incidental.** Best-chunk\n  aggregation beats sum-of-chunks by 11.8 points, and shipped BM25 order beats\n  coverage, proximity, their combination, RRF fusion, and a local cross-encoder\n  on both conditions.\n- **The +26.2-point top-10 ceiling is real, open, and unclaimed.** Gold sits in\n  the pooled top-10 at 0.508 against 0.246 at k=1. The cheap lexical class of\n  fixes is spent; reaching it needs a signal that is not question-term overlap.\n\nWhat survives every configuration argument is the dependency floor: **Titen's\nFTS-only lane made zero LLM calls and zero embedding calls in both conditions.**\nMem0 without an LLM still needs an embedding provider. `dependencies: {}`, zero\nexternal imports in `src/core/`, and exactly two outbound calls in the whole\ncodebase, both opt-in.\n\nOther published losses: FTS-only recall@1 falls from 1.00 to 0.49 between 10³\nand 10⁵ claims on a synthetic corpus — which *understated* the real-data\ndegradation above — one process saturates one core at 10k claims, there is no\nreranking stage, and no external suite scores the governance and collaboration\nprimitives at all.\n\n## Memory for a team, not a chatbot\n\nA storage-only memory saves text. A retrieval-only memory embeds it and returns\nnearby passages. Both leave the caller to decide what is current, permitted, or\ntrue, and neither stops two agents from quietly claiming the same work.\n\nTiten's Level 5 kernel turns source observations into evidence-linked, temporal\nclaims and compiles only the context a caller is allowed to see. Level 6 joins\nthat kernel to checkpoints, leases, handoffs, governance, audit, and signed\nfederation.\n\n<p align=\"center\">\n  <code>Level 6 = evidence-grounded context + coordinated work + governance</code>\n</p>\n\n<p align=\"center\"><img src=\"https://raw.githubusercontent.com/RamaAditya49/titen/main/docs/assets/readme/titen-levels.svg\" alt=\"Four memory models as rising steps: logs and files, vector recall, Titen's Level 5 kernel, and Titen's Level 6 fabric, each labelled with what it can do and where it stops. Level 6 is Titen's product model, not an external certification\" width=\"100%\"></p>\n\n| Memory model | What it can do | Where it stops |\n| --- | --- | --- |\n| Logs and files | Keep past text | The caller must decide what is current, trusted, and relevant |\n| Vector recall | Find semantically similar passages | Similarity does not prove provenance, permission, or truth |\n| Titen Level 5 kernel | Compile bounded context from scoped evidence, claims, time, trust, and conflicts | It remembers well, but does not coordinate parallel work by itself |\n| Titen Level 6 fabric | Add task ownership, resumable state, handoffs, policy, audit, and federation | Titen records coordination; your agents or orchestrator still choose what runs next |\n\nLevel 6 is Titen's product model, not an external certification. The distinction\nis observable in the API: memory and collaboration share one authorization,\nevidence, and audit boundary.\n\n## Project status\n\n**Titen is pre-1.0.** Per [SemVer clause 4](https://semver.org/spec/v2.0.0.html#spec-item-4),\nthe public API is not yet stable. Below `1.0.0` the **minor** slot is the only\nbreaking-change signal consumers get: `0.5.7` to `0.6.0` may break you, and\n`^0.5.0` does not match `0.6.0`. Pin an exact version and read the\n[changelog](https://github.com/RamaAditya49/titen/blob/main/CHANGELOG.md) before\nupgrading.\n\nWhere the word *stable* appears around Titen — the npm `latest` dist-tag,\n`\"channel\": \"stable\"` in [`titen.dev/version.json`](https://titen.dev/version.json),\nand `titen version --check` — it names the **release channel**: a deliberate\nrelease rather than a prerelease on `next`. It never describes API stability,\nand it is not a maturity badge. See\n[versioning and channels](https://github.com/RamaAditya49/titen/blob/main/docs/engineering/release.md#versioning-and-channels).\n\nThe current release includes the memory kernel, REST API, MCP server,\nTypeScript SDK, collaboration tools, enterprise governance, signed federation,\nand the operator dashboard.\n\nYou can run Titen on Bun with SQLite or on Cloudflare Workers with D1. Semantic\nretrieval is optional: use `sqlite-vec` on Bun, or Vectorize and Workers AI on\nCloudflare — verified live only on the maintainer's isolated the maintainer release stack\nstack, which is test production and not general availability\n([scope note](#architecture)). Titen runs in your own infrastructure.\n\n**Clients.** Titen ships a TypeScript/JavaScript SDK, the `titen` CLI, and a\nminimal Python client in\n[`clients/python/`](https://github.com/RamaAditya49/titen/tree/main/clients/python).\nThe Python client is one standard-library-only file covering\n`observe → consolidate → compile → evidence`, with a generic `request` for every\nother route. **It is not published to PyPI**: install it from a checkout with\n`pip install ./clients/python`, or vendor `titen.py`. There is no client for any\nother language — those callers use the authenticated REST API directly, and\nevery route, scope, and error shape is in the\n[API reference](https://github.com/RamaAditya49/titen/blob/main/docs/reference/api.md).\n\nSee the [maturity matrix](https://github.com/RamaAditya49/titen/blob/main/docs/ROADMAP.md#maturity-matrix)\nfor detailed runtime evidence and remaining gates, or the\n[changelog](https://github.com/RamaAditya49/titen/blob/main/CHANGELOG.md) for\nrelease history.\n\n## Install and connect an agent\n\nThis section is the **served** deployment: a long-running instance with its own\nAPI keys, reachable over HTTP by more than one agent. If you only want memory\nfor the agent on this machine, [the 30-second path](#try-it-in-30-seconds)\nabove is the whole setup and you can skip to\n[optional semantic retrieval](#optional-semantic-retrieval).\n\nThe local server needs [Bun 1.2 or newer](https://bun.sh/). The website\ninstaller adds Bun when needed, then installs the `titen` command for your\ncurrent user:\n\n```bash\ncurl -fsSL https://titen.dev/install.sh | bash\ntiten --version\n```\n\nWindows PowerShell:\n\n```powershell\nirm https://titen.dev/install.ps1 | iex\ntiten --version\n```\n\nYou can also run `bun add --global titen-memory@latest`. npm and pnpm global\ninstalls work when Bun is already on `PATH`.\n\nThe published package includes the current operator dashboard. After installing\nthe CLI, run `titen dashboard` to serve that exact release's `/dashboard/`\nassets; it does not enable live data or expose a listener beyond loopback.\n\n### 1. Create the store\n\nRun this once. Without `--db`, Bun service commands use the stable per-user\nstore at `~/.titen/service.db` regardless of the current directory:\n\n```bash\ntiten bootstrap --org \"My Org\"\n```\n\nSave the organization ID, API key, and temporary dashboard password from the\noutput. Titen stores only their hashes. The dashboard user is `owner` and must\nchange its password at first login.\n\nAn existing release that used `./titen.db` is never moved automatically. Keep\nusing it explicitly with `--db /absolute/path/to/titen.db`, then use the same\nflag for `serve`, key administration, migration, and backup.\n\nCreate a separate revocable key for each agent host. Replace the organization\nID and choose a stable principal name:\n\n```bash\ntiten key create \\\n  --org-id org_replace_me \\\n  --principal agent-codex \\\n  --kind agent \\\n  --scopes \"mcp:call,projects:create\" \\\n  --trust asserted \\\n  --label codex\n```\n\n`mcp:call` includes write-capable memory and coordination tools. Do not share\none key across every agent.\n\n### 2. Start the service\n\n```bash\ntiten serve\n```\n\nOpen another shell and check readiness:\n\n```bash\ncurl --fail http://127.0.0.1:8787/readyz\nexport TITEN_MCP_URL=\"http://127.0.0.1:8787/mcp\"\nexport TITEN_API_KEY=\"paste-the-agent-key-here\"\n```\n\nKeep the key in your shell, service environment, or secret manager. Never put\nit in a repository. If the agent runs in a container or on another machine,\n`127.0.0.1` points at that agent, not the Titen server; use a private HTTPS,\nTailscale, or trusted tunnel URL instead.\n\n### 3. Connect your agent host\n\nCodex can connect to Titen's HTTP endpoint directly. It stores the environment\nvariable name, not the key:\n\n```bash\ncodex mcp add titen --url \"$TITEN_MCP_URL\" \\\n  --bearer-token-env-var TITEN_API_KEY\ncodex mcp get titen --json\n```\n\nClaude Code can launch the bundled stdio bridge. It inherits the two variables\nfrom the Claude process:\n\n```bash\nclaude mcp add --transport stdio --scope user titen -- titen mcp\nclaude mcp get titen\n```\n\nOpenClaw services read durable environment values from `~/.openclaw/.env`.\nPlace `TITEN_MCP_URL` and `TITEN_API_KEY` there, set the file to mode `600`,\nthen register and probe the remote server:\n\n```bash\nopenclaw mcp set titen \\\n  '{\"url\":\"${TITEN_MCP_URL}\",\"transport\":\"streamable-http\",\"headers\":{\"Authorization\":\"Bearer ${TITEN_API_KEY}\"}}'\nopenclaw gateway restart\nopenclaw mcp doctor titen --probe\n```\n\nHermes can launch Titen's bundled stdio bridge. Put the same two variables in\n`~/.hermes/.env`, then run:\n\n```bash\nhermes mcp add titen \\\n  --command titen \\\n  --args mcp \\\n  --env 'TITEN_MCP_URL=${TITEN_MCP_URL}' 'TITEN_API_KEY=${TITEN_API_KEY}'\nhermes mcp test titen\n```\n\nClaude Desktop and any other client that supports stdio MCP can use this small\nconfiguration. Start the client from an environment that contains the two\nvariables above:\n\n```json\n{\n  \"mcpServers\": {\n    \"titen\": {\n      \"command\": \"titen\",\n      \"args\": [\"mcp\"]\n    }\n  }\n}\n```\n\nThe bridge keeps no state. It only forwards newline-delimited MCP messages to\nthe authenticated HTTP endpoint.\n\n`titen mcp` picks its mode from the environment: with **both** `TITEN_MCP_URL`\nand `TITEN_API_KEY` set it bridges to that instance, with **neither** set it\nserves the local store described above, and with only one of the two it fails\nrather than guessing. The served path and its authorization are unchanged by\nlocal mode — that is an additional entry point, not a relaxation.\n\nTiten is listed in the official MCP registry as\n`io.github.RamaAditya49/titen-memory`, so a client that reads that directory can\noffer it; configuring it by hand as above works everywhere else. The manifest and\nthe manual publishing procedure are in\n[MCP registry listing](https://github.com/RamaAditya49/titen/blob/main/docs/deployment/mcp-registry.md).\n\n### 4. Prove the connection\n\nOpen the host's MCP status view, or ask the agent:\n\n> Resolve this repository from its Git origin, compile relevant Titen context\n> for the current task, and list the Titen tools you can access.\n\nA healthy connection exposes nine `titen_*` tools. Titen's handshake tells the\nhost to compile once when the task or repository scope changes, to treat memory\nas untrusted reference data, and never to capture transcripts or secrets.\n\nTool failures include bounded support guidance. Agents can distinguish an\nexpected setup result from a condition that needs investigation or a possible\ndefect. A missing project reference remains `404 NOT_FOUND`; an authorized\noperator can approve creation without treating setup as a bug.\n\nDistributed Titen skills require reproduction, sanitization, and duplicate\nsearch before a public issue. The host owns GitHub authentication. Titen never\nreceives a GitHub token or publishes security findings as public issues.\n\nThe [agent integration guide](https://titen.dev/docs/agent-integrations) adds\nCursor, OpenCode, Windsurf, TRAE, Pi, and plugin installation. The\n[secure ingress guide](https://github.com/RamaAditya49/titen/blob/main/docs/deployment/secure-ingress.md)\ncovers Tailscale Serve and Cloudflare Tunnel.\n\n`titen version --check` is the only networked version check. It reads\n[`titen.dev/version.json`](https://titen.dev/version.json) only when you run it;\nTiten does not poll during server or MCP startup.\n\n## Optional semantic retrieval\n\nThe default install is FTS-only and stays ready with no embedding configuration\nat all. Semantic retrieval is **all-or-nothing**: set one `TITEN_EMBED_*`\nvariable and you have opted in, so every variable below must then be valid or\nthe service fails closed — `/readyz` returns `503` with\n`checks.semantic_index: \"embedding_configuration_invalid\"` and no vector query\nruns. A Bun vector deployment must also add `sqlite-vec@0.1.9`.\n\nOnce semantic retrieval is valid, normal pending projection work reports\n`checks.semantic_index: \"index_projection_pending\"` while `/readyz` remains\nHTTP 200: canonical SQL/FTS requests are ready and the semantic index is\nsyncing. An observed embedder/vector failure or incompatible fingerprint still\nreturns 503.\n\n| Variable | Required | Shipped default | Absent or invalid |\n| --- | --- | --- | --- |\n| `TITEN_EMBED_BASE_URL` | yes | none | `configured_error`; must be `http:`/`https:` with no credentials, query, or fragment |\n| `TITEN_EMBED_MODEL` | yes | none on Bun; `@cf/baai/bge-base-en-v1.5` on Workers | `configured_error` |\n| `TITEN_EMBED_DIMS` | yes | none on Bun; `768` on Workers | `configured_error`; integer 1–65,536, must equal the index dimension |\n| `TITEN_EMBED_REVISION` | yes | **none** | `configured_error` |\n| `TITEN_EMBED_PROFILE` | yes | **none** | `configured_error`; exactly one value is accepted per model family |\n| `TITEN_EMBED_MIN_COSINE` | yes | **none** | `configured_error`; every operator calibrates this alone |\n| `TITEN_EMBED_API_KEY` | only if the provider needs a bearer token | none | supplying it *without* the rest still opts in, and then fails closed |\n\nThree of these have no default anywhere and no value can be guessed safely:\n\n- **`TITEN_EMBED_REVISION`** is an opaque immutable identifier for the exact\n  weights behind the endpoint, ≤200 characters. It is not validated for shape —\n  it is recorded in the stored index fingerprint, so changing it invalidates the\n  index and forces a rebuild. That is the point: it is how you promise Titen the\n  vectors already in the store came from the same weights as the next query. A\n  provider that cannot name an immutable revision should stay FTS-only.\n- **`TITEN_EMBED_PROFILE`** selects the query/document input transform, and the\n  accepted value is *forced by the model id*. Any model id containing\n  `embeddinggemma` (case- and punctuation-insensitive) accepts **only**\n  `embeddinggemma-retrieval-v1`; every other model accepts **only**\n  `raw-unit-v1`. There is no way to run an EmbeddingGemma model on raw\n  untransformed input, and no way to apply the EmbeddingGemma prompts to another\n  model. A mismatch is `configured_error`, not a warning.\n- **`TITEN_EMBED_MIN_COSINE`** has **no shipped default**. An unset variable\n  reads as the empty string, which is rejected, so semantic retrieval fails\n  closed rather than silently accepting weak matches. Titen ships no universal\n  or pre-inspected threshold: derive it from a locked evaluation of that exact\n  provider, model, revision, and profile. `0` is a valid, deliberate value\n  meaning \"accept every candidate the index returns and let ranking decide\".\n\nWorked EmbeddingGemma example — an OpenAI-compatible endpoint serving\n`embeddinggemma` at 768 dimensions:\n\n```bash\nbun add titen-memory sqlite-vec@0.1.9\n\nTITEN_EMBED_BASE_URL=http://127.0.0.1:11434/v1 \\\nTITEN_EMBED_MODEL=embeddinggemma \\\nTITEN_EMBED_DIMS=768 \\\nTITEN_EMBED_REVISION=embeddinggemma-q4-2026-07-31 \\\nTITEN_EMBED_PROFILE=embeddinggemma-retrieval-v1 \\\nTITEN_EMBED_MIN_COSINE=0.32 \\\nbunx titen-memory serve\n```\n\n`embeddinggemma-retrieval-v1` is the only profile that model id will accept.\n`embeddinggemma-q4-2026-07-31` is a placeholder: substitute the immutable\nrevision your provider reports, and treat any change to it as an index rebuild.\n`0.32` is a placeholder too — replace it with your own calibrated floor and\nrecord how you measured it. Verify with `curl --fail http://127.0.0.1:8787/readyz`;\na healthy vector deployment reports `capabilities.vector: \"enabled\"`.\n\nThe packaged vector path is verified on glibc Linux x64 with Bun 1.3.13; other\nplatforms need their own ready, drain, and query smoke.\n\nFor backups, key rotation, containers, and durable service setup, use the\n[Bun/VPS deployment guide](https://github.com/RamaAditya49/titen/blob/main/docs/deployment/vps.md).\n\n## Use the SDK\n\nThe SDK uses `fetch` and runs on Node 22+, Bun, Deno, and edge runtimes.\n\n`titen-memory` is **ESM-only** — it has no CommonJS entry — so the consuming\nproject must be ESM too. `npm init -y` writes `\"type\": \"commonjs\"`, which is why\nthe second line below is not optional: without it Node fails with\n`SyntaxError: Cannot use import statement outside a module` before it reaches\nany Titen code.\n\n```bash\nnpm install titen-memory\nnpm pkg set type=module\n```\n\nSave this as `titen-example.js` and run `node titen-example.js`:\n\n```js\nimport { TitenClient } from \"titen-memory\";\n\nconst titen = new TitenClient({\n  url: process.env.TITEN_URL ?? \"http://127.0.0.1:8787\",\n  key: process.env.TITEN_API_KEY,\n});\n\nconst subject = \"release-runbook\";\nconst observation = await titen.observe({\n  subject_id: subject,\n  kind: \"imported_source\",\n  content: \"The release runbook requires a rollback smoke test after deployment.\",\n  source: { type: \"runbook\", ref: \"ops/release.md\" },\n  trust: \"verified\",\n});\n\nawait titen.consolidate(subject, [\n  {\n    kind: \"procedural\",\n    statement: \"Run a rollback smoke test after deployment.\",\n    sources: [\n      { observation_id: observation.observation_id, relation: \"supports\" },\n    ],\n  },\n]);\n\nconst context = await titen.compile({\n  subject_id: subject,\n  task: \"rollback smoke after deployment\",\n  max_tokens: 900,\n});\n\nconsole.log(context.items);\n```\n\nThe script needs a running service and a key: start one with\n`titen bootstrap --org \"My Org\"` and `titen serve`, then export\n`TITEN_API_KEY`. In TypeScript the same file works unchanged as\n`titen-example.ts` on Node 22.18+ or Bun; write `process.env.TITEN_API_KEY!`\nthere to satisfy strict null checks. Skipping `npm pkg set type=module` and\nnaming the file `.mjs`/`.mts` also works — those extensions are ESM regardless\nof `package.json`.\n\n`max_tokens` accepts 128 through 32,000. Every returned memory item includes\n`untrusted: true`; the client still owns prompt boundaries and action policy.\n\nPython callers use\n[`clients/python/`](https://github.com/RamaAditya49/titen/tree/main/clients/python),\nwhich is not on PyPI and installs from a checkout. Any other language calls the\nREST API in the\n[API reference](https://github.com/RamaAditya49/titen/blob/main/docs/reference/api.md)\ndirectly.\n\nTyped methods cover common agent operations. `request()` and `requestRaw()`\ncover the remaining authenticated JSON and streaming routes. Mutations accept\nan `idempotencyKey` for safe retries.\n\nSee the [agent guide](https://github.com/RamaAditya49/titen/blob/main/docs/agent-guide.md)\nand [API reference](https://github.com/RamaAditya49/titen/blob/main/docs/reference/api.md)\nfor request contracts and scope rules.\n\n## Architecture\n\nOne Web-Standards TypeScript core serves both runtimes:\n\n| Capability | Bun / VPS | Cloudflare |\n| --- | --- | --- |\n| HTTP | `Bun.serve` | Worker `fetch` |\n| Canonical SQL | `bun:sqlite` | D1 |\n| Lexical retrieval | SQLite FTS5 | D1 FTS5 |\n| Optional vectors | `sqlite-vec` | Vectorize (see the scope note below) |\n| Automatic model enrichment | Implemented, opt-in compatible HTTP | Implemented, opt-in compatible HTTP |\n| Background work | Startup and bounded timer | Scheduled handler; trigger provisioning varies |\n\n**Vectorize scope.** Vectorize and Workers AI are implemented and verified live\non the maintainer release stack, an isolated stack on the maintainer's own Cloudflare account,\nwith scoped BGE-M3 retrieval, bounded repair, Cron, persistence, and rollback.\nThat is test production and **not a general-availability claim**: no customer\ndeployment runs it, and your account needs its own ready, drain, and query\nsmoke before you rely on it. Without an AI/Vectorize binding a Worker stays\nready and retrieval is lexical D1 FTS5. The\n[maturity matrix](https://github.com/RamaAditya49/titen/blob/main/docs/ROADMAP.md#maturity-matrix)\nholds the exact evidence.\n\nAutomatic model-assisted claim derivation and reflection are implemented as an\nopt-in capability with durable jobs, bounded validation, and separate\nreadiness. They are not production-activated: no candidate model has passed the\nfrozen activation gate, and the locked evaluation and real-runtime smokes are\nnot recorded. Callers author evidence-linked claims explicitly, as described in\n[You author the claims](#you-author-the-claims).\n\nThe base service does not require Docker, Redis, Postgres, a graph database, or\na vector database. Authorization runs before retrieval, and every candidate is\nhydrated from canonical SQL before Titen returns it.\n\nRead the [architecture overview](https://github.com/RamaAditya49/titen/blob/main/docs/architecture/overview.md)\nfor component and failure boundaries. Cloudflare operators should start with\nthe [Cloudflare deployment guide](https://github.com/RamaAditya49/titen/blob/main/docs/deployment/cloudflare.md).\n\n## Dashboard\n\nThe checked-in Astro client at `/dashboard/` is a live fifteen-destination\noperator surface spanning memory, collaboration, operations, administration,\ngovernance, and Profile. Each person signs\nin with a username/password; the loopback adapter keeps the resulting\nshort-lived key behind an opaque HttpOnly session and never writes either secret\nto browser storage. Bootstrap creates `owner` with a random temporary password,\nand Add User follows the same forced-first-change flow. A persistent SQL\nthrottle limits password guessing across restarts. Optional WebAuthn passkeys\nuse staged sessions and once-only recovery codes without blocking public API\nclients. API keys remain for agents, services, SDKs, and recovery. There is no\nfixture fallback when the service is disconnected or denies a request.\n\nEach data area uses a task-specific table, list, or fact view. Select a record\nto open its inspector. Row actions operate on that exact record. The full\nauthorized response remains available in a closed **Technical payload**\ndisclosure for diagnosis.\n\n![Projects directory with task-specific columns](https://raw.githubusercontent.com/RamaAditya49/titen/main/docs/assets/screenshots/dashboard-operator-projects.png)\n\nThe [dashboard guide](https://github.com/RamaAditya49/titen/blob/main/docs/dashboard.md)\ncovers configuration and verification. Use the\n[secure ingress guide](https://github.com/RamaAditya49/titen/blob/main/docs/deployment/secure-ingress.md)\nfor private Tailscale Serve access or Cloudflare Tunnel protected by Access.\n\nFor a packaged install, start the adapter from the same release:\n\n```bash\nTITEN_DASHBOARD_LIVE=true \\\nTITEN_DASHBOARD_AUTH=session \\\nTITEN_API_URL=http://127.0.0.1:8787 \\\ntiten dashboard\n```\n\n## Documentation\n\n| Read this | For |\n| --- | --- |\n| [Golden path](https://github.com/RamaAditya49/titen/blob/main/docs/guides/golden-path.md) | A complete small-team example |\n| [API reference](https://github.com/RamaAditya49/titen/blob/main/docs/reference/api.md) | REST, MCP, errors, and compatibility |\n| [Source-memory import](https://github.com/RamaAditya49/titen/blob/main/docs/reference/source-import.md) | Preview and import curated memory from 16 explicit source profiles |\n| [Architecture](https://github.com/RamaAditya49/titen/blob/main/docs/architecture/overview.md) | Core, runtime, storage, and policy boundaries |\n| [Agent integrations](https://github.com/RamaAditya49/titen/blob/main/docs/agent-plugins.md) | Host-specific MCP and skill setup |\n| [VPS deployment](https://github.com/RamaAditya49/titen/blob/main/docs/deployment/vps.md) | Bun, containers, persistence, and hardening |\n| [Cloudflare deployment](https://github.com/RamaAditya49/titen/blob/main/docs/deployment/cloudflare.md) | Worker and D1 setup |\n| [Secure dashboard ingress](https://github.com/RamaAditya49/titen/blob/main/docs/deployment/secure-ingress.md) | Tailscale Serve or Cloudflare Tunnel with Access |\n| [MCP registry listing](https://github.com/RamaAditya49/titen/blob/main/docs/deployment/mcp-registry.md) | Publishing `server.json` to the official MCP registry |\n| [Audit rules](https://github.com/RamaAditya49/titen/blob/main/docs/reference/audit.md) | How `titen audit` counts duplicates, recall loops, secrets, and staleness |\n| [Roadmap](https://github.com/RamaAditya49/titen/blob/main/docs/ROADMAP.md) | Evidence-based maturity and planned work |\n| [Documentation index](https://github.com/RamaAditya49/titen/blob/main/docs/README.md) | Product, engineering, security, and research docs |\n\n## Development\n\nThe repository requires Node 22+, Bun 1.2+, and pnpm.\n\n```bash\ngit clone https://github.com/RamaAditya49/titen.git\ncd titen\npnpm install\npnpm test\npnpm check:workflow\n```\n\nChanges follow `spec -> plan -> implement -> done`. Read\n[CONTRIBUTING.md](https://github.com/RamaAditya49/titen/blob/main/CONTRIBUTING.md)\nbefore changing public behavior, storage, authorization, or runtime contracts.\n\n## Security\n\nKeep Titen bound to `127.0.0.1`. Remote agents should use a private network or\na trusted TLS reverse proxy. When that proxy exposes `/mcp`, set\n`TITEN_MCP_ORIGIN` to its exact public origin. Use `TITEN_SECRET_KEYS` as the\nexternal encryption keyring for persisted webhook and federation signing\nsecrets, and set `TITEN_WEBHOOK_ALLOWED_HOSTNAMES` before enabling outbound\nwebhooks. The [VPS security guide](https://github.com/RamaAditya49/titen/blob/main/docs/deployment/vps.md#configuration)\ndefines the formats and rotation procedure.\n\nDo not report vulnerabilities in a public issue. Use\n[GitHub Private Vulnerability Reporting](https://github.com/RamaAditya49/titen/security/advisories/new)\nand follow [SECURITY.md](https://github.com/RamaAditya49/titen/blob/main/SECURITY.md).\nNever include real credentials or private memory content in a report.\n\n## License\n\nTiten is licensed under the\n[Apache License 2.0](https://github.com/RamaAditya49/titen/blob/main/LICENSE).\n",
  "bytes": 43701,
  "sha": "333d63b08ee9b3f6a2ddf5773cdf0e31dd80c858be49f8e7d0d9728e5e9198be",
  "repo_slug": "ramaaditya49/titen",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_ramaaditya49_titen_memory_3a76267b/readme"
}