DEV Community

Cover image for How I Gave My AI Assistant a Persistent Identity
Edward Kubiak
Edward Kubiak

Posted on

How I Gave My AI Assistant a Persistent Identity

Every morning, I open a new session with my AI assistant. And every morning, it has no idea who I am.

It doesn't remember that I prefer terse responses. It doesn't know I corrected it three times last week about summarizing at the end of every message. It doesn't know we've been building together for 129 sessions. It starts from zero — a stranger with a system prompt.

I got tired of re-introducing myself. So I built Project Engram: persistent AI identity that travels with you across sessions and across models.

The Problem Isn't Memory — It's Identity

There are already tools that give AI assistants "memory." ChatGPT has a built-in memory feature. Claude has Projects. Open-source frameworks like Mem0, Zep, and Letta (MemGPT) offer sophisticated storage backends — vector databases, knowledge graphs, multi-tier recall systems.

They're all solving the wrong problem.

These tools store facts about you: "User prefers Python." "User works at Acme Corp." "User asked about deployment last Tuesday." Facts are useful. But facts aren't identity.

Identity is relational. It's how the AI calibrates its tone after you correct it. It's the trust that builds over 50 sessions of working together. It's knowing that "simpler" isn't a vague request — it's a pattern this specific user repeats when you over-engineer something. It's tracking open threads from three sessions ago that neither of you explicitly saved but both of you know are unresolved.

No existing tool models this. Here's the landscape:

System Stores facts Models identity Portable Local-first Decay scoring
ChatGPT Memory Yes No No No No
Claude Projects Yes No No Partial No
Mem0 Yes No Yes Optional Basic
Zep Yes No Yes Optional Temporal
Letta (MemGPT) Yes Partial Yes Yes Agent-driven
Engram Yes Yes Yes Yes Yes

The gap across all of them: relational context — how the dynamic between you and the AI evolves over time, not just what was said.

What Engram Actually Does

Engram runs a three-stage pipeline — extract, compress, inject — that converts raw conversation signals into a token-efficient identity payload.

1. Extract

At the end of every session, Engram scans your conversation for behavioral signals: corrections ("don't do that"), preferences ("I prefer markdown"), style observations, and relationship events (first time collaborating on a new domain, trust calibration moments).

These aren't keyword matches. The extractor classifies signals by type and confidence, preserving the original context.

2. Compress

Raw signals accumulate fast. After a hundred sessions, you might have thousands. Engram's compression pipeline handles this with two mechanisms:

Recency-weighted decay. Not all signals age equally. Engram assigns each signal a decay class:

Decay class What it holds Half-life
permanent Explicit corrections — "never do X" Never decays
slow Communication style, formatting preferences 90 days
fast Open threads, recent decisions 14 days
volatile Session-specific context 3 days

This models something no other tool does: forgetting. Human relationships naturally deprioritize old context. An AI that remembers everything with equal weight isn't being faithful to the relationship — it's hoarding.

Deduplication. The engine collapses near-duplicate signals (Jaccard similarity > 80%) and resolves contradictions. If you said "be verbose" in January and "be terse" in March, the newer signal wins. The older one is marked superseded, not deleted — the history is preserved, but it stops consuming token budget.

3. Inject

The scored, compressed profile is rendered into a structured payload and injected at the next session start. The entire identity fits within a 1,500–2,500 token budget. That's less than most system prompts — but it carries the weight of every session you've had together.

session end → [extract signals] → engram.db → [compress + score] → [render payload] → identity.md → next session start
Enter fullscreen mode Exit fullscreen mode

Portability: The Part That Changes Everything

Here's where Engram diverges most sharply from the market.

ChatGPT's memory is locked to OpenAI. Claude's memory is locked to Anthropic. If you switch providers, you start over. Your relationship — built over months — is gone.

Engram treats identity as data you own, not a platform feature. The identity payload is a published open spec (Apache 2.0) with four provider implementations:

Provider Backend Use case
ClaudeCodeProvider Claude Code + SQLite Default — full pipeline
OpenAIProvider ChatGPT API Inject via system message
OllamaProvider Local models Inject via /api/generate
GenericProvider Any system-prompt API Universal fallback

Migration is a two-command workflow:

# Export from Claude
engram migrate --to openai --output my-identity.json

# Import into OpenAI (three strategies: replace, merge, supplement)
engram migrate --from openai --input my-identity.json --strategy merge
Enter fullscreen mode Exit fullscreen mode

The spec defines transferability tiers so you know exactly what survives the move:

  • Tier 1 (near-lossless): Communication style, behavioral rules, personas, open threads
  • Tier 2 (lossy but useful): Trust level, relationship depth, style descriptors — full recalibration takes 2-5 sessions
  • Tier 3 (structural only): Session counts, event logs — metadata, no behavioral weight

The practical result: the skeleton transfers, the muscle regrows in 2-5 sessions. That's dramatically better than starting from scratch.

Personas: Context-Switching Without Losing Yourself

Sometimes you need a different version of the same relationship. Engram supports named personas with a merge engine:

# Create personas with different calibrations
engram persona create work --name "Work Claude" --formality 0.9 --default
engram persona create creative --name "Creative Claude" --formality 0.2

# Auto-activate by directory
echo "work" > ~/Projects/work/.engram/persona
Enter fullscreen mode Exit fullscreen mode

Personas use a REPLACE / APPEND / SUPPRESS override system on top of the base identity. Your corrections and relationship history carry through — only the surface-level style shifts. This is fundamentally different from having separate memory stores per context, which is what most tools do.

Local-First: Your Identity Never Leaves Your Machine

Engram stores everything in a local SQLite database. No cloud sync, no telemetry, no API calls. The identity payload is a markdown file on your filesystem.

This is an architectural constraint, not a preference. Identity data is intimate — it's a model of how you think, communicate, and collaborate. It should live where your SSH keys live: on your machine, under your control.

The export and redaction system gives you control over what leaves:

Redaction level What's removed Use case
none Nothing Trusted environments
excerpts Raw conversation text from signals Sharing without exposing private conversations
full All human-readable text Structural portability only

Why I Published an Open Spec

The identity-payload-v1.md spec isn't documentation for Engram — it's a standalone format definition. Any LLM framework can implement it. The fields are typed, tiered for transferability, and versioned with forward-compatibility guarantees (unknown fields must be preserved on round-trip).

I published it because identity portability only works if it's a shared standard, not a proprietary format. If Mem0 or Letta or anyone else wants to read and write Engram payloads, the spec is Apache 2.0 and the door is open.

The Numbers

  • 713 tests (517 pytest + 75 BATS + 121 Vitest) across all modules
  • 4 provider implementations with a shared 8-method interface
  • 12-view local dashboard (React + Express) for managing identity, signals, and consent
  • Consent management built in — you can revoke identity tracking at any time, and the pipeline respects it

Getting Started

# Install via Homebrew
brew tap ek33450505/engram
brew install engram
engram init

# Or clone and install manually
git clone https://github.com/ek33450505/project-engram
cd project-engram
bash install.sh

# See your current identity state
engram inspect

# Rebuild and inject the payload
engram inject
Enter fullscreen mode Exit fullscreen mode

Engram currently integrates with CAST (Claude Agent Specialist Team) for signal extraction, but the provider architecture means it can work with any source of conversation data.

What's Next

The extraction pipeline currently relies on structured journal entries. I'm exploring whether embedding-based signal detection could work for unstructured conversation history — but that's an open thread, not a roadmap promise.

If you're building AI tools and the identity portability problem resonates, check out the spec. If you're a developer who's tired of re-introducing yourself to your AI assistant every morning, give Engram a try.


Project Engram is open source under Apache 2.0. Stars, issues, and provider contributions are welcome.

GitHub logo ek33450505 / project-engram

Persistent AI identity that travels with you across models and sessions.

Project Engram — Persistent AI Identity

Project Engram

Persistent AI identity that travels with you across models and sessions.

Version Tests License Python


Engram Architecture


What Engram Does

  • Extracts identity signals from your conversations — communication style, behavioral corrections, preferences, and relationship arc
  • Compresses and deduplicates signals into a token-efficient payload using recency-weighted decay scoring
  • Injects your identity context at session start — across models, across providers — via plain system prompt text

Install via Homebrew

brew tap ek33450505/engram
brew install engram
Enter fullscreen mode Exit fullscreen mode

After installation:

engram init
bash $(brew --prefix)/opt/engram/libexec/scripts/cast-install.sh
Enter fullscreen mode Exit fullscreen mode

Quick Start

git clone https://github.com/ek33450505/project-engram
cd project-engram
bash install.sh    # auto-grants consent; use --no-consent to opt out

# Inspect current identity state
engram inspect

# Rebuild and inject the identity payload
engram inject

# Export identity as portable JSON
engram export --output identity.json

# Migrate to a different model provider
engram migrate --to openai --output my-identity.json
engram migrate --from openai --input my-identity.json --strategy merge
Enter fullscreen mode Exit fullscreen mode

Requires CAST installed at ~/.claude/.

Top comments (1)

Collapse
 
shawnsammartano profile image
Shawn Sammartano • Edited

Good framing on the identity vs. memory distinction — that's a real gap most tools ignore.
I've been building something that sits a layer below this that identity tools like Engram could run on top of. Added Nexus to your table with a few columns your comparison. Nexus isn't a memory store, it's a gateway that sits in front of one. The problem it solves is different: Claude Desktop, ChatGPT, Perplexity, Cursor, and eight other AI clients all writing to the same memory backend simultaneously, with none of them knowing about the others, and zero data loss if the process dies mid-write.

A few specifics:

Every write goes through a Write-Ahead Log with fsync before the 200 OK returns. kill -9 mid-write and nothing is lost. Tested.
v0.1.3 added Ed25519 signed writes and a hash-chained audit log. bubblefish verify proof.json runs with no daemon — proves a specific memory hasn't been tampered with since it was written.
11 clients verified simultaneously: Claude Desktop, Claude Web, Claude Code, ChatGPT Web, ChatGPT Desktop, Perplexity Comet, LM Studio, Open WebUI, Cursor, Windsurf, OpenClaw. Same WAL, same SQLite, no conflicts. While I say 11 AI Apps here, that not the ceiling. I just haven't pre-made the configs for others yet.

Based on the architecture — Nexus can connect to anything that can speak one of four transports:

MCP stdio
Any app that supports MCP stdio transport by spawning a child process. The app runs bubblefish mcp as a subprocess and talks JSON-RPC 2.0 over stdin/stdout.
Verified: Claude Desktop, Claude Code, Cursor, Windsurf
Any app that can: configure a command + args in an MCP config file

MCP HTTP / SSE
Any app that can send an HTTP POST to localhost:7474/mcp or a Cloudflare Tunnel URL. JSON-RPC 2.0 over HTTP. SSE variant for streaming clients.
Verified: LM Studio, Windsurf, Claude Web, Perplexity Comet, ChatGPT (via OAuth 2.1)
Any app that can: make authenticated HTTP requests to an MCP endpoint

HTTP Inbound (POST /inbound/{source})
Any app or middleware that can make an HTTP POST with a JSON body and a bearer token. This is the most generic path — no MCP required.
Verified: Open WebUI (via Pipelines), OpenClaw (via TypeScript plugin)
Any app that can: make HTTP POST requests — which is everything

OpenAI-compatible write (POST /v1/memories)
Same as HTTP inbound but OpenAI payload shape. Apps that already speak OpenAI API format can write memories with minimal config change.
Any app that: uses the OpenAI API format

The right-hand columns in this table don't exist anywhere else in this space:

`

System Stores memories Models identity Portable across LLMs Local-first Decay scoring Multi-client shared memory Survives kill -9 Ed25519 signed writes Hash-chained audit log MCP native Verified AI clients Zero deps single binary Remote access (phone → home memory)
ChatGPT Memory 1 ☁️ Cloud only
Claude Projects ⚠️ Partial 1 ☁️ Cloud only
Mem0 ⚠️ Optional ⚠️ Basic ⚠️ Partial 1 ⚠️ Cloud mode only
Zep / Graphiti ⚠️ Optional ⚠️ Temporal ⚠️ Partial 1 ⚠️ Cloud mode only
Letta (MemGPT) ⚠️ Partial ⚠️ Agent-driven ⚠️ Partial 1 ❌ Local only
Engram ⚠️ Claude-focused 1 ❌ Local only
MemPalace ✅ verbatim ⚠️ Partial ✅ 19 tools ⚠️ Claude Code ❌ Local only
BubbleFish Nexus v0.1.3 ✅ Temporal + decay ✅ shared WAL ✅ WAL + fsync ✅ Ed25519 ✅ hash-chained ✅ stdio+HTTP+SSE+OAuth 11 verified ✅ no Docker ✅ Cloudflare Tunnel — phone, tablet, any device

Your memory store runs on your machine, your data never leaves, and you can still reach it from your phone anywhere in the world via Cloudflare Tunnel — zero cloud vendor required.

`

The identity modeling column is yours — Nexus doesn't track relational context across sessions. Different problem. Where these could complement each other: Engram handles behavioral signal extraction and identity compression, Nexus handles the durable multi-client transport layer underneath it.

github.com/bubblefish-tech/nexus — Go, AGPL-3.0, single binary.
(Drafted with AI assistance.)