Concepts
How mem/ctl stores, syncs, and shares memory across agents and teams
Concepts
Data model
mem/ctl organizes data in a hierarchy:
Organization
└── Project
├── Memories (key-value pairs)
├── Context entries (typed, structured)
├── Branch plans (per git branch)
├── Sessions (agent activity logs)
└── Snapshots (point-in-time backups)Organizations group projects and team members. Projects scope all data - two agents on the same org and project share the same memory pool.
Memories
The core unit. Each memory has:
| Field | Description |
|---|---|
key | Unique identifier (e.g. agent/context/architecture/auth) |
content | Free-form text content |
priority | 0-100, higher surfaces first in bootstraps and searches |
tags | Array of labels for filtering |
scope | project (default) or shared (org-wide) |
ttl | Expiry policy: session, pr, sprint, or permanent |
metadata | Arbitrary JSON for tool-specific data |
Context entries
Context entries are memories with structured types. They use the key pattern agent/context/{type}/{id} and have 9 built-in types:
| Type | What to store |
|---|---|
coding_style | Naming, formatting, linting, review standards |
architecture | System design, modules, data flow, tech stack |
testing | Framework, naming, locations, coverage rules |
constraints | Hard limits, non-goals, security, performance budgets |
lessons_learned | Past mistakes, gotchas, workarounds |
workflow | Branch strategy, PR process, CI/CD, deploy pipeline |
folder_structure | Repository layout and domain boundaries |
file_map | Key files per feature area |
branch_plan | Implementation plan for the current branch |
You can also create custom context types per organization using the context_config tool.
Branch plans
Branch plans are context entries scoped to a git branch. They include:
- Implementation description
- Status (
planning,in_progress,review,merged) - Checklist with items and completion state
- Automatically associated with the current branch name
Sessions
Sessions track agent activity within a conversation:
- Start/end timestamps
- Which memories were read and written
- Which tools were used
- Summary of what was accomplished
- Git context (branch, commits, diffs)
Sessions enable handoff between conversations. The next agent session can see what the previous one did and pick up where it left off.
Where data is stored
All memory is stored server-side in the mem/ctl cloud API (or your self-hosted instance). There is no local-only mode - the API is the source of truth.
The CLI maintains a local cache for performance and offline resilience, but it is never the primary store.
Agent (IDE)
└── MCP Server (memctl CLI)
├── In-memory cache (30s TTL)
├── Local SQLite cache (~/.memctl/cache.db)
└── Cloud API (source of truth)
└── Database (Turso/SQLite)Why cloud-first matters for teams
Because all data lives server-side, any team member with access to the same org and project sees the same memories. There is no merge conflict or sync delay beyond the cache TTL. When one agent stores a coding convention, every other team member's agent picks it up on the next bootstrap.
Caching and sync
The CLI uses a three-tier cache to minimize API calls while keeping data fresh.
Tier 1: In-memory cache
- TTL: 30 seconds
- Stale window: 120 seconds (serves stale data while revalidating in the background)
- ETag support: Skips data transfer if the API returns 304 Not Modified
- Request deduplication: Multiple concurrent reads for the same key share a single API call
This means within a single agent session, repeated reads of the same memory hit the API at most once every 30 seconds.
Tier 2: Local SQLite cache
- Location:
~/.memctl/cache.db - Scope: Separated by
{org}:{project} - Sync: Incremental delta sync on startup (fetches only changes since last sync)
- Fallback: If SQLite is unavailable, falls back to an in-memory Map
On MCP server startup, the CLI:
- Pings the API to check connectivity
- If online and first run: fetches up to 100 memories to populate the cache
- If online and not first run: runs an incremental delta sync (only changes since last sync timestamp)
- If offline: operates from the local cache
Tier 3: Pending writes queue
- Location:
~/.memctl/pending-writes.json - Purpose: Queues failed writes when the API is unreachable
- Replay: Can be replayed when connectivity is restored
Freshness indicators
Every API response includes a freshness indicator:
| State | Meaning |
|---|---|
fresh | Directly from the API |
cached | From in-memory cache, within TTL |
stale | From in-memory cache, past TTL but revalidating |
offline | From local SQLite cache, API unreachable |
Team collaboration
How teams share context
All team members working on the same project share the same memory pool. When anyone stores or updates a memory, it is immediately available to others (within cache TTL).
Typical team workflow:
- Tech lead sets up org defaults (coding style, architecture, constraints)
- Developers join the org and project
- Org defaults are applied to the project via
org.defaults_apply - Each developer's agent bootstraps on session start and receives the shared context
- As developers add lessons learned, update architecture docs, or modify conventions, changes propagate to the whole team
Organization features
| Feature | Description |
|---|---|
| Org defaults | Centrally managed memory entries applied to all projects |
| Templates | Reusable memory bundles for new project setup |
| Context diff | Compare context between two projects in the same org |
| Cross-project search | Search memories across all projects in the org |
Concurrent access
mem/ctl handles concurrent access from multiple agents:
- Optimistic concurrency: Uses ETag-based
If-Matchheaders to detect conflicts on writes - Session claims: Agents can claim resources (files, memory keys) to signal exclusive access
- Watch: Monitor specific keys for changes made by other sessions
Offline mode
When the API is unreachable:
- Reads fall back to the local SQLite cache
- Writes are queued in
~/.memctl/pending-writes.json - The CLI retries connectivity periodically
- When the API becomes available again, pending writes can be replayed
Offline mode is automatic - no configuration needed. The agent continues working with cached data and queues mutations for later sync.
Rate limiting
CLI session write limits
Write operations (memory.store, memory.delete, memory.update, batch_mutate) are rate-limited per session:
- Default: 500 writes per session
- Configurable: Set
MEMCTL_RATE_LIMITenvironment variable - Warning: At 80% usage, the CLI warns the agent
- Blocked: At 100%, writes are rejected until the session resets
Read operations are not rate-limited.
API rate limits
HTTP API requests are rate-limited per user per minute using a sliding window. Limits vary by plan:
| Plan | Requests/min |
|---|---|
| Free | 60 |
| Lite | 100 |
| Pro | 150 |
| Business | 150 |
| Scale | 150 |
| Enterprise | 150 |
These API rate limits are separate from the CLI session write limits above. The session limit caps total writes within a single agent session. The API rate limit caps HTTP requests per minute across all sessions for a user.
Memory lifecycle
Memories can be managed with lifecycle policies:
- TTL expiry: Memories with
ttlset tosession,pr, orsprintexpire automatically - Archive: Soft-delete that keeps data but hides from search
- Cleanup: Remove expired or stale memories
- Pin: Prevent a memory from being cleaned up
- Sunset: Mark a memory for gradual removal with a deadline
- Lock/unlock: Prevent edits to critical memories