Metadata-Version: 2.4
Name: mnemo-agent
Version: 0.3.0
Summary: Local-first agent memory CLI — dump, diff, migrate & query across Mem0, Letta, and more
Author: Joshua Ndala
License-Expression: MIT
Project-URL: Homepage, https://github.com/joshndala/mnemo-agent
Project-URL: Repository, https://github.com/joshndala/mnemo-agent
Project-URL: Bug Tracker, https://github.com/joshndala/mnemo-agent/issues
Project-URL: Changelog, https://github.com/joshndala/mnemo-agent/CHANGELOG.md
Keywords: agent,memory,cli,mem0,letta,mcp
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Utilities
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: click>=8.1
Requires-Dist: pydantic>=2.6
Requires-Dist: rich>=13.7
Requires-Dist: fastapi>=0.110
Requires-Dist: uvicorn[standard]>=0.29
Requires-Dist: pyyaml>=6.0
Requires-Dist: python-dateutil>=2.9
Provides-Extra: mem0
Requires-Dist: mem0ai>=0.0.20; extra == "mem0"
Provides-Extra: letta
Requires-Dist: letta-client>=0.1; extra == "letta"
Provides-Extra: parquet
Requires-Dist: pyarrow>=16.0; extra == "parquet"
Requires-Dist: pandas>=2.2; extra == "parquet"
Provides-Extra: graph
Requires-Dist: networkx>=3.3; extra == "graph"
Requires-Dist: matplotlib>=3.9; extra == "graph"
Provides-Extra: s3
Requires-Dist: boto3>=1.34; extra == "s3"
Provides-Extra: all
Requires-Dist: mnemo-agent[graph,letta,mem0,parquet,s3]; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest>=8.2; extra == "dev"
Requires-Dist: pytest-click>=1.1; extra == "dev"
Requires-Dist: httpx>=0.27; extra == "dev"
Dynamic: license-file

# 🧠 mnemo

> **Local-first agent memory CLI** — dump, diff, migrate, and query memories across [Mem0](https://mem0.ai), [Letta](https://letta.com), and your local filesystem.

Agents are finally getting good long‑term memory, but every framework (Mem0, Letta, Supermemory, custom Postgres) stores it differently. mnemo is a git‑like CLI for agent memory: you can dump, diff, migrate, and query what your agents know, all from your terminal, using a simple normalized schema and local‑first files. It’s designed for developers who want to own their agent’s “brain” instead of locking it into a single vendor.

Inspired by Mnemosyne (Greek goddess of memory), **mnemo** is a portable CLI for managing agent memory: capture facts, version-control dumps, compare snapshots, and sync to cloud memory providers — all from your terminal.

---

## Features

- **15 CLI commands** with rich `--help` and tab-completion
- **Normalized schema** — facts with `{entity, attribute, value, source, timestamp, confidence, metadata.tags}`
- **Multi-provider** — local JSON, Mem0, Letta (stubs → real APIs with optional deps)
- **TF-IDF search** — `mnemo recall "query"` with zero external ML deps, filterable by `--tag`
- **Rich tables** — confidence color-coded (🟢 ≥0.8, 🟡 ≥0.5, 🔴 <0.5)
- **HTML + graph diffs** — visual diff between dump snapshots
- **MCP server** — FastAPI `/mcp/list_tools` + `/mcp/call_tool` for Ollama/Claude Code agents
- **Push/pull sync** — S3, Cloudflare R2, or local filesystem remote; timestamp-based merge
- **Safe writes** — `--dry-run` on load, pull, and migrate

---

## Quick Start

```bash
# Install
pip install mnemo-agent              # core (local only)
pip install "mnemo-agent[s3]"       # + S3/R2 push-pull sync
pip install "mnemo-agent[all]"      # everything (mem0 + letta + parquet + graph + s3)

# Initialize Joshua's job-prep agent
mnemo init --agent job-prep

# Add facts manually (entity defaults to agent name, --tag is repeatable)
mnemo add --fact "Joshua uses React, Node, Supabase, Vercel" --agent job-prep
mnemo add --fact "Joshua is based in Toronto" --agent job-prep --confidence 1.0
mnemo add --fact "Chose Supabase over Firebase for auth" --agent job-prep --attribute decision --tag decision --tag auth

# View stored memories — plain format shows IDs for retract/edit
mnemo show --agent job-prep
mnemo show --agent job-prep --format plain

# Recall using natural language, optionally filtered by tag
mnemo recall "tech stack" --agent job-prep
mnemo recall "auth" --agent job-prep --tag decision
mnemo search "Supabase database" --agent job-prep --limit 5

# Edit or remove facts by ID (use 'show --format plain' to find IDs)
mnemo retract a1b2c3d4 --agent job-prep
mnemo edit a1b2c3d4 --value "Updated wording" --agent job-prep

# List all agents
mnemo ls --pretty

# Dump to a timestamped file
mnemo dump --agent job-prep

# Load a sample dump
mnemo load --file tests/fixtures/job_prep_sample.json --agent job-prep

# Compare two agents (or two dump files)
mnemo diff --agent-a job-prep --agent-b job-prep-v2
mnemo diff dump1.json dump2.json --html diff_report.html

# Start the MCP server (for Ollama / Claude Code agents)
mnemo serve --agent job-prep --port 8080

# Sync to S3 (prompts for credentials on first add)
mnemo remote add origin s3://my-bucket/mnemo --agent job-prep
mnemo push --agent job-prep
mnemo pull --agent job-prep   # merges remote facts into local
```

---

## 📋 All Commands

| Command | Description |
|---|---|
| `mnemo init --agent <name>` | Initialize agent directory + config |
| `mnemo add --fact "text" --agent <name>` | Add a memory fact (`--entity`, `--attribute`, `--tag` supported) |
| `mnemo dump --agent <name> [--source mem0\|letta]` | Dump memories to JSON |
| `mnemo load --file dump.json --agent <name>` | Load dump into local/Mem0/Letta |
| `mnemo ls [--agent all]` | List agents and fact counts |
| `mnemo show --agent <name>` | Display agent's latest memories (`--format pretty\|json\|plain`) |
| `mnemo diff --agent-a <a> --agent-b <b>` | Diff two agents (or `diff a.json b.json`) |
| `mnemo recall "query" [--tag <tag>]` | TF-IDF search across all agents, optional tag filter |
| `mnemo search "query" [--limit 10] [--tag <tag>]` | Alias for recall with higher default limit |
| `mnemo retract <fact-id> --agent <name>` | Remove a fact by ID or 8-char prefix |
| `mnemo edit <fact-id> --agent <name>` | Edit value/attribute/confidence of an existing fact |
| `mnemo migrate --dump f.json --target mem0 --agent name` | Migrate between providers |
| `mnemo serve --agent <name> [--port 8080] [--read-only]` | MCP FastAPI server |
| `mnemo remote add <name> <url> --agent <name>` | Add a named remote (s3://, r2://, file://) |
| `mnemo remote list --agent <name>` | List configured remotes |
| `mnemo remote remove <name> --agent <name>` | Remove a remote |
| `mnemo push [--remote origin] --agent <name>` | Push local memory to remote |
| `mnemo pull [--remote origin] --agent <name>` | Pull and merge remote memory into local |

---

## Project Structure

```
mnemo-agent/
├── src/mnemo/
│   ├── __init__.py          # version
│   ├── cli.py               # Click CLI (all commands)
│   ├── models.py            # Pydantic: Fact, AgentDump, MnemoConfig
│   ├── storage.py           # Local file I/O (JSON, YAML, credentials)
│   ├── search.py            # TF-IDF search + diff engine
│   ├── remotes.py           # Push/pull backends: FileBackend, S3Backend
│   ├── server.py            # FastAPI MCP server
│   └── adapters/
│       ├── mem0_adapter.py  # Mem0 API → normalized facts
│       └── letta_adapter.py # Letta API → normalized facts
├── tests/
│   ├── test_cli.py          # CLI command tests
│   ├── test_remote.py       # Remote backends, merge, push/pull tests
│   └── fixtures/
│       └── job_prep_sample.json
├── config.yaml              # Sample agent config
├── pyproject.toml
└── requirements.txt
```

---

## Memory Schema

```json
{
  "agent": "job-prep",
  "dump_ts": "2026-03-21T23:00Z",
  "source": "manual",
  "version": "1",
  "facts": [
    {
      "id": "uuid",
      "entity": "Joshua",
      "attribute": "tech_stack",
      "value": "React, Node, Supabase, Vercel",
      "source": "chat|tool|manual|mem0|letta|import",
      "timestamp": "2026-03-21T20:00Z",
      "confidence": 0.95,
      "metadata": {}
    }
  ]
}
```

### Example: Project Memory for `advisor-prep`

```json
{
  "agent": "advisor-prep",
  "facts": [
    {
      "id": "uuid-1",
      "entity": "advisor-prep-agent",
      "attribute": "project_summary",
      "value": "CLI + agent that helps students prep for advisor meetings using UBC context.",
      "source": "manual",
      "timestamp": "2026-03-22T01:00Z",
      "confidence": 0.9,
      "metadata": { "tags": ["summary", "high-level"] }
    },
    {
      "id": "uuid-2",
      "entity": "advisor-prep-agent",
      "attribute": "decision",
      "value": "Chose Supabase over Firebase for auth due to better Postgres integration.",
      "source": "manual",
      "timestamp": "2026-03-22T01:05Z",
      "confidence": 0.95,
      "metadata": { "tags": ["decision", "auth"], "ticket": "ADR-001" }
    },
    {
      "id": "uuid-3",
      "entity": "advisor-prep-agent",
      "attribute": "stack",
      "value": "Next.js, React, Node, Supabase, Vercel.",
      "source": "manual",
      "timestamp": "2026-03-22T01:10Z",
      "confidence": 1.0,
      "metadata": { "tags": ["stack"] }
    }
  ]
}
```

---

## 🔌 MCP Server (for Ollama / Claude Code)

```bash
mnemo serve --agent job-prep --port 8080
```

| Endpoint | Description |
|---|---|
| `GET /mcp/list_tools` | List available tools (MCP schema) |
| `POST /mcp/call_tool` | Call a tool by name with arguments |
| `GET /facts` | REST: list all facts |
| `GET /search?q=query` | REST: search memories |
| `GET /docs` | Swagger UI |

### Available MCP tools

```json
{ "name": "search_memory",  "description": "TF-IDF search over agent memory" }
{ "name": "list_facts",     "description": "Return all facts, optionally filtered" }
{ "name": "upsert_fact",    "description": "Add a fact to agent memory" }
{ "name": "get_agent_info", "description": "Agent metadata and fact count" }
```

---

## ⚙️ Configuration

Each agent has `~/.mnemo/<agent>/config.yaml`:

```yaml
agent: job-prep
default_source: local
default_target: local
mem0_api_key: null          # https://app.mem0.ai
mem0_user_id: joshua
letta_base_url: http://localhost:8283
letta_agent_id: null        # from your Letta agent
tags: [job-prep, interview]
notes: Memory store for interview prep agent
remotes:
  origin: s3://my-bucket/mnemo
```

Remote credentials (S3/R2 access keys) are stored separately in `~/.mnemo/credentials` with `chmod 600`. They are populated automatically when you run `mnemo remote add` — you will be prompted for them interactively. Pass `--no-creds` to skip prompting and rely on the standard boto3 credential chain (`AWS_ACCESS_KEY_ID` env var, `~/.aws/credentials`, IAM role).

---

## Environment Variables

| Variable | Description |
|---|---|
| `MNEMO_AGENT` | Default agent name (skips `--agent` flag) |
| `MNEMO_DIR` | Override base directory (default: `~/.mnemo`) |
| `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` | S3 credentials (alternative to prompting) |
| `R2_ACCOUNT_ID` | Cloudflare R2 account ID (alternative to prompting) |

---

## Tests

```bash
pip install "mnemo-agent[dev]"
pytest tests/ -v
```

---

## Roadmap

- [x] Push/pull sync to S3, R2, and local filesystem remotes
- [ ] Vector embeddings for semantic search (v2)
- [ ] Parquet export for analytics
- [ ] `mnemo audit` — fact provenance trace
- [ ] Web UI dashboard
- [ ] Native Ollama MCP client registration

---

## Example Use Case: `job-prep` Agent

```bash
# Bootstrap your interview prep memory
mnemo init --agent job-prep
mnemo load --file tests/fixtures/job_prep_sample.json --agent job-prep

# Ask your agent questions via MCP (Ollama / Claude Code reads from :8080)
mnemo serve --agent job-prep --port 8080

# After a practice interview, add what you learned
mnemo add --fact "Lead with Supabase migration story at FAANG interviews" \
  --agent job-prep --attribute interview_tip --confidence 0.9 --tag tip

# Before next session, recall relevant context
mnemo recall "React Supabase full-stack" --agent job-prep
```

---

## License

MIT © Joshua Ndala
