Team memory for AI coding agents.
Your AI agents forget everything between sessions. Every decision re-litigated. Every convention re-explained. Every past mistake repeated by the next agent that touches the same code.
Personal memory tools patch the symptom: store some facts, retrieve them later. That works for solo developers who remember what they stored. It breaks down when teams ship with AI — when three developers are using agents on the same codebase, when onboarding requires transferring institutional knowledge, when the wrong memory survives a refactor because no one audited it.
Memory isn't storage. It's a team practice.
Tages treats codebase memory as a managed artifact: structured types, quality scoring, audit trails, sharpen passes that rewrite vague notes into imperative agent instructions. One developer's architecture decision becomes every agent's context. A bad memory gets flagged and corrected before it misleads the next session.
Start in under 60 seconds with one command. Add team features when your workflow demands them.
claude mcp add tages -- npx -y @tages/server| Tages | Zep | Mem0 | |
|---|---|---|---|
| Install | One line (claude mcp add) |
Docker + API key | API key + SDK |
| Local-only mode | Yes (SQLite, zero config) | Self-hosted only | No (cloud-only) |
| Team sharing | Yes (RBAC, federation) | Yes (cloud) | No |
| Dashboard | Yes (Next.js, analytics) | Yes | Basic |
| Quality control | Audit, sharpen, enforce | No | No |
| Memory types | 11 structured types | Knowledge graph (Graphiti) | Structured |
| MCP tools | 56 | N/A | N/A |
| Search | Trigram + semantic + decay | Temporal knowledge graph | Vector |
| Workflow integration | Git hooks, CI/CD, briefs | SDK calls | SDK calls |
| Pricing | Free local / $14 Pro | Open-source / Cloud | $19-$249/mo |
Source code tells agents what exists. Tages tells them why it was built, how to work with it, and what not to do.
| Type | Example |
|---|---|
| Convention | "Always use snake_case for API routes" |
| Decision | "Chose Postgres over MongoDB for pg_trgm fuzzy search" |
| Architecture | "Auth middleware in lib/auth.ts, JWT in httpOnly cookies" |
| Lesson | "Don't cache the Supabase mock — tests need fresh state" |
| Anti-pattern | "Never pass id in upsert with onConflict — causes FK violation" |
| Pattern | "All API errors return { error, code, status }" |
Plus: entity, execution, operational, environment, preference (11 types total).
- Install —
tages initconnects to your project, or install the Claude Code plugin for zero-config setup - Remember — Store decisions and conventions manually, via git hooks, or by importing CLAUDE.md
- Recall — Every session gets full project context in <10ms from local SQLite cache
When running as a Claude Code plugin or MCP server, Tages automatically detects which project you're in:
.tages/config.json— explicit marker file (created bytages link)- Git remote — matches the repo name against registered projects
- Directory name — matches the folder name against registered project slugs
- Auto-create — if authenticated, creates a new cloud project automatically; otherwise uses local-only mode
No tages init required per directory. Use tages link [slug] to explicitly bind a directory to a project.
Install Tages as a Claude Code plugin for automatic session memory:
/plugin https://github.com/ryantlee25-droid/tages
Claude Code, Cursor, Codex, Gemini — anything that speaks MCP.
- 56 MCP tools — remember, recall, audit, sharpen, import, federation, analytics, and more
- 53 CLI commands — full control from the terminal
- Web dashboard — browse, search, and edit memories with dark-mode UI
- Auto-indexing — git hooks extract decisions from commits via Ollama or Claude Haiku
- Import — seed from existing CLAUDE.md, ARCHITECTURE.md, or JSON files
tages brief— generate a cached context document for system prompt injectiontages audit— score your memory coverage and get suggestions for improvementtages sharpen— rewrite memories into imperative form for better agent consumption- Local-first — SQLite cache for sub-10ms queries, works offline
- Hybrid search — pg_trgm trigram matching + pgvector semantic search
- Team sharing — multiple developers share one codebase memory (Pro)
Reproducible LongMemEval and coding-memory benchmark results are published under eval/ with full methodology, judge configuration, and run notebooks. Results are reproducible against the published harness; raw numbers are in each eval's results/ directory.
packages/
server/ MCP server (56 tools, stdio transport, 605 tests)
cli/ CLI (53 commands, npm global install, 163 tests)
shared/ TypeScript types + Supabase client
apps/
dashboard/ Next.js 16, Supabase Auth, Tailwind, shadcn/ui
supabase/
migrations/ 56 migrations (tables, RLS, pgvector, RBAC, encryption)
- Encryption at rest — AES-256-GCM for memory values (opt-in)
- RBAC — Owner/admin write, member read-only
- Row Level Security — All tables enforce project membership at the database layer
- Auth — Supabase Auth + GitHub OAuth; API tokens SHA-256 hashed with expiration
- Secret detection — Memories scanned for API keys, credentials, PII before storage
- Audit logging — Auth events, exports, and token validation tracked
See SECURITY.md for our full security policy and responsible disclosure process. See PRIVACY.md for our privacy policy.
| Plan | Price | Includes |
|---|---|---|
| Free | $0 | 1 project (cloud sync), 10,000 memories, 20 core MCP tools, local SQLite |
| Pro | $14/mo | Up to 10 projects, 50K memories, all 56 tools, cloud sync |
| Team | $19/seat/mo | Up to 20 projects, 100K memories, federation, RBAC, audit logging |
| Self-hosted | Free forever | Bring your own Supabase, no limits, MIT license |
See CONTRIBUTING.md for development setup and guidelines.
- A1 — Governance page indexed: removed
robots: 'noindex, nofollow'from/governancemetadata. The page is now crawlable and eligible for Google Search Console indexing. Added/governancelink to both the desktop nav (after Security, before GitHub) and the mobile menu using the same styling as adjacent links. - A4 follow-up — publish.yml pnpm/action-setup aligned to v6: bumped
pnpm/action-setup@v5to@v6in.github/workflows/publish.yml. PR #31 (Dependabot) is bringingci.ymlto v6; without this bumppublish.ymlwould be left on v5 — functional but inconsistent and easy to forget before the v0.3.1 tag push. - B1 —
get_memory_provenanceno longer returns raw auth.users UUID (migration 0058):create or replace functioninsupabase/migrations/0058_drop_provenance_user_id.sqlremoves theuser_id uuidcolumn from the function'sreturns table(...)and the correspondingm.updated_by as user_idfrom the SELECT. All other columns retained. The function still returnsuser_display(full_name → email-prefix → "Unknown") which is sufficient for every caller. Zero callers in the codebase (grep -r get_memory_provenance apps/ packages/returns no hits). Closes White W1 review finding from PR #55. Migration must be applied to prod viasupabase db push --linkedafter merge.
- Behavioral drift algorithm: replaced the v1
insufficient_datastub inbehavioral-drift.tswith a real Jensen-Shannon divergence implementation. Per-agent temporal drift: for each agent active in both windows with ≥5 calls per window, compute JSD(baseline_distribution, current_distribution) over the union tool vocabulary with Laplace smoothing, normalize to [0,1] by dividing by ln(2), and average across eligible agents (max 20). ReturnsBehavioralDriftReportwithscore,status,note,jsd(raw),agentCount,agentDistributions(top-3 tools per agent), andwindowA/windowBboundary metadata. - Type layer: new
BehavioralDriftReport,AgentToolDistribution,BehavioralWindowinterfaces intypes.ts.DriftReport.behavioralretyped fromMetricStubtoBehavioralDriftReport(superset — no breaking change for callers readingscore/status/note).DriftInputextended withbaselineSince?andcurrentSince?. - Weight rebalance:
WEIGHTSincompute.tsshifted from{semantic: 1.0, coordination: 0, behavioral: 0}to{semantic: 0.7, coordination: 0, behavioral: 0.3}. For projects without tool_call_log volume, behavioral returnsinsufficient_dataand contributes 0 — overall drift score drops ~30% relative to the v1 number for projects with sufficient behavioral data. Next target{0.5, 0.25, 0.25}when coordination ships. - CLI: new
--baseline-since <window>and--current-since <window>flags ontages drift. Both must appear together; baseline-since must be earlier than current-since; both use the existingNd/Nh/ISO grammar.renderHumanextended with behavioral score, raw JSD, agent count, window boundaries, threshold guidance, and per-agent top-3 tool breakdown. - Tests: 18 new tests — 12 in
behavioral-drift.test.ts(windowing, JSD math, multi-agent averaging, top-tools reporting), 5 incompute.test.ts(weight exposure, weight contribution paths, edge cases), 1 in CLIdrift.test.ts(flag parsing). 843 passing total (was 826 on main).
- CI test-mock fix —
supabase.authinterface added tocommands-smokemock:mockSupabasenow includes amockAuthobject with stubbedsetSession,getSession, andrefreshSession(all returning a valid session shape). Without this, any test that callswriteAuthConfigand runs withoutTAGES_SERVICE_KEYset would crash withcannot read 'setSession' of undefined— becausecreateAuthenticatedClientreadsauth.jsonand callssupabase.auth.setSession(...)on the auth-path branch. The bug was latent until CI was widened frompnpm --filter @tages/server testtopnpm -r testin c9a27f1;resetMockSupabase()updated to clear the three new mock functions alongsidefrom/rpc.
2026-04-29 — PR #55 White second-review fix bundle (W2 limit-semantics, W2-AOT codex regex, Q1 Windows guard)
- W2 limit-semantics —
drift.ts--limitregression reverted:--limitnow controls display top-K only (original semantics, default 10). A newMAX_DB_ROWS = 10000constant applied to both Supabase queries provides defensive OOM protection without conflating "show top N keys" with "fetch N rows from the chronological window". - W2-AOT codex regex —
stripTagesBlockTOML array-of-tables support:targetHeaderandanyHeaderregexes now match[[mcp_servers.tages]]in addition to[mcp_servers.tages]. Hand-edited configs using double-bracket syntax are now cleaned correctly by--force. JSDoc updated to document the comment-swallowing limitation. - Q1 Windows guard —
pathToFileURLentrypoint fix (codex, cursor, gemini plugins): Replacedimport.meta.url === \file://${process.argv[1]}`withimport.meta.url === pathToFileURL(process.argv[1]).hrefin all three plugins. The original was broken on Windows (import.meta.urlusesfile:///C:/...;process.argv[1]usesC:...— never equal), silently no-oppingmain()undernpx`. - Regression test:
packages/codex-plugin/src/__tests__/index.test.tsadds one test covering[[mcp_servers.tages]]strip (10 tests total, was 9). 826 passing overall. - Deferred: W1 (comment swallowing before next non-tages header) — documented in JSDoc; S2 (friendly ENOENT for
computeOracleSha) — punt, raw error acceptable for eval harness.
- B1 —
drift.tscrash on bad--since:resolveSince()is now wrapped in try/catch; invalid input prints a clean error message and exits with code 1 instead of throwing uncaught. - B2 —
codex-pluginduplicate TOML block:--forceno longer appends a second[mcp_servers.tages]header. A new exportedstripTagesBlock()helper removes any existing tages tables in-place before the new block is written. USAGE text updated to reflect the replace-in-place behaviour. - W2 —
--limitapplied to queries:tages drift --limitnow passes.limit()to both Supabase queries (field_changesandtool_call_log) in addition to display truncation; the value is validated as a positive integer. - W3 —
agents-mdfederation header: whenagents-md-owners.jsonis configured butmemories.team_iddoesn't exist, the generated AGENTS.md opens with a machine-readable<!-- TAGES_FEDERATION_NOTE: ... -->HTML comment so agents and reviewers see the limitation immediately. - Q1 — dynamic oracle SHA:
eval/longmemeval/src/dataset.tsnow exportscomputeOracleSha()that hashes the on-disk oracle file at run time;run.tsreports the actual SHA instead of a hardcoded constant. - CI widening:
.github/workflows/ci.ymlandpublish.ymlexpanded from--filter @tages/serverto-r(all packages).publish.ymlalso adds@tages/codex-pluginand@tages/gemini-pluginto the npm publish matrix. - New tests (15 total): regression suite for
codex-plugin(9 tests, including round-trip strip+append guard), plus entry-point tests forcursor-plugin(3) andgemini-plugin(3). Pluginmain()calls guarded withimport.meta.urlcheck so packages are importable in tests.
- README hygiene: Stripped unreproducible benchmark claim from
## Benchmarkssection; corrected MCP tool, CLI command, test, and migration counts to match current codebase. - Bet A — Memory Governance foundation: New
/governancemarketing page (draft,noindex). Migration0057_provenance_fields.sqladdssession_id,source_context, andtool_namecolumns tomemorieswith a GIN index and aget_memory_provenanceRPC.MemoryTypeScript type extended withsessionId,toolName, andsourceContext. Formal spec atdocs/provenance-model.md. - Bet B — AGENTS.md native tooling: New
tages agents-md writeandtages agents-md auditCLI subcommands.writegenerates a canonical 6-section AGENTS.md from project memory.auditflags vagueness, missing sections, missing runnable commands, and absence of the three-tier Always/Ask/Never boundary pattern. - Bet D — Cross-tool distribution: New
@tages/cursor-pluginpackage. Runningnpx @tages/cursor-plugininstalls Tages in Cursor by writing.cursor/mcp.json. Setup guide atdocs/cursor-setup.md. - CI: New
.github/workflows/publish.ymltriggers onv*tag push to publish packages to npm (requiresNPM_TOKENrepo secret). - Strategy documents:
analysis/directory lands with competitive analysis, trend scan, positioning brief, deep research execution doc, Monte Carlo pricing model, and research notes.PLAN.mdandREMAINING.mdadded at repo root.
supabase/migrations/0057_provenance_fields.sql: pinnedsearch_path = public, extensionsand added anis_project_member(auth.uid(), m.project_id)guard inside theget_memory_provenanceSECURITY DEFINER function so it cannot leak provenance across projects. (B1, Q1).github/workflows/publish.yml: publish@tages/cursor-pluginalongside@tages/shared,@tages/server,@tages/clionv*tag push. (W1)packages/cli/src/commands/agents-md.ts: replaced the unsupported\Zanchor inextractSectionwith a JS-correct end-of-string lookahead so last-section audit rules (missing-commands, missing-tech-versions) fire correctly. Regression test added. (W2)apps/dashboard/src/components/marketing/governance-page.tsx: correctedsession_idfield type in the Provenance model table fromtexttouuid. (S1)- W3 (test count targets) was declined — counts reflect a verified test-run output, not a goal. S2 (control-flow warning) was deferred — no runtime impact.
- Pre-launch hygiene (Phase 0):
HOOK.mdand.semgrep-results/added to.gitignore. Closed migration 0042 git gap — file had been applied to prod on Apr 10 but never committed;supabase migration list --linkedconfirmed prod/local match. - Sprint A — Differentiation foundation (Phase 3.1 + 3.2): New
@tages/codex-pluginpackage (TOML writer targeting~/.codex/config.toml,--dry-run, block detection). New@tages/gemini-pluginpackage (JSON merge into~/.gemini/settings.jsonwith preserved top-level keys). Newtages agents-md diffandtages agents-md federateCLI subcommands extending the Bet B foundation. White review fixes: gemini env-var placeholders, codex regex false-positive on[mcp_servers.tages.env]alone, diff negation-word boundary. - Sprint B — LongMemEval harness scaffold (Phase 1.1): New
eval/longmemeval/directory with standalone TypeScript harness (not in pnpm workspace). RetainDB-pattern methodology documented with comparability caveat (Supermemory/RetainDB baselines on deprecated dataset). Pluggable memory backend:in-memorylexical floor +tages-clireal integration. Dry-run verified; real runs pendingOPENAI_API_KEY+ sandboxTAGES_EVAL_PROJECT. - Sprint C —
tages driftv1 (Phase 3.3): Newtages driftCLI command (experimental). Semantic drift uses a real instability metric (1 − 1/distinct_values over field_changes); 10 unit tests cover zero/two/three-value instability, session+agent reporting, whitespace normalization, topK. Coordination drift stubbed (not_implemented) — blocked onmemories.team_idcolumn. Behavioral drift stubbed (insufficient_data/not_implemented) — tool_call_log has raw data, v2 calibration pending design partners.--json,--since,--agent,--limitflags. - Chore: Plugin packages (cursor, codex, gemini) now use
--passWithNoTestssopnpm -r testdoes not fail at the root.
- Fixed GitHub OAuth login redirecting to the marketing homepage instead of
/app/projectsafter callback. Root cause:SameSite=Strictcookies are withheld by the browser on cross-site top-level navigations (i.e. GitHub's redirect back to/auth/callback?code=...), so the PKCE verifier and refreshed session cookies never reached the server. Reverted to Supabase's defaultSameSite=Lax, which is the correct setting for SSR auth cookies.HttpOnly + Secure + Laxstill blocks CSRF on state-changing requests. - Invite-flow overhaul (Team plan): Team invites now send a one-time Supabase magic-link email rather than inserting directly into
team_members. Pending invites expire after 30 days; expired rows are skipped byaccept_pending_invites. Owners and admins can revoke a pending invite before it is accepted (new DELETE RLS policy). The invite role dropdown enforces RBAC at both the UI and server layers — owners can invite admin or member, admins can only invite member. Dashboard sign-ins now callaccept_pending_invitesvia the OAuth callback, so web-only sign-ups resolve dangling invites automatically (previously only the MCP server did this on startup). Requires migrations0055_invite_expiry.sqland0056_invite_delete_policy.sqlapplied to your Supabase project.
- Split literal Stripe-style test fixtures in
safety.test.tsandobserve.test.tsvia string concatenation so GitHub secret scanning no longer flags them. The fixtures are intentional test inputs, not real credentials.
Tages — the Etruscan divine child who appeared from a furrow in the earth and dictated sacred knowledge to scribes before vanishing. The knowledge persisted long after the source was gone.