# Merge mnemo-client + mnemo-mcp into unified mnemo-ai package

> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Merge `mnemo-client` and `mnemo-mcp` into a single `mnemo-ai` Python package with MCP as an optional extra (`pip install mnemo-ai[mcp]`).

**Architecture:** Restructure the flat `mnemo_client.py` file into a `src/mnemo/client.py` module under an implicit namespace package (no `mnemo/__init__.py`), matching the existing `mnemo.server` namespace used by `mnemo-server`. MCP server code moves to `src/mnemo/mcp/`. The `[mcp]` optional extra gates MCP-specific dependencies so the base install stays lightweight.

**Tech Stack:** Python 3.12+, hatchling build system, uv package manager, httpx (client), mcp SDK (optional MCP extra), pytest + pytest-asyncio (testing).

**Important namespace constraint:** `mnemo-server` occupies `mnemo.server` and `mnemo.simulation` under the `mnemo` namespace. Currently it has an empty `mnemo/__init__.py`, making it a regular package. For two separately-installed packages to share the `mnemo` top-level namespace, **both** must use implicit namespace packages (PEP 3147 / Python 3.3+) — meaning no `mnemo/__init__.py` in either repo. Task 5 removes the empty `mnemo/__init__.py` from mnemo-server. The client package MUST NOT create `src/mnemo/__init__.py` either.

---

## File Structure

### Final layout of mnemo-client repo (renamed conceptually to mnemo-ai):

```
mnemo-client/                        # repo directory (unchanged)
├── src/
│   └── mnemo/                       # NO __init__.py (implicit namespace package)
│       ├── client.py                # moved from mnemo_client.py (unchanged content)
│       └── mcp/
│           ├── __init__.py          # empty — marks mcp as a regular subpackage
│           ├── __main__.py          # entry point: python -m mnemo.mcp
│           └── server.py            # from mnemo-mcp/mnemo_mcp/server.py (imports updated)
├── tests/
│   ├── test_mcp/
│   │   ├── __init__.py
│   │   └── test_server.py           # from mnemo-mcp/tests/test_server.py (imports updated)
│   └── (future: test_client/)
├── pyproject.toml                   # updated: src layout, [mcp] extra, console script
├── README.md                        # updated: both usage modes
├── LICENSE                          # unchanged (Apache 2.0)
└── .env                             # unchanged
```

### Files deleted:
- `mnemo_client.py` (moved to `src/mnemo/client.py`)

### Files in mnemo-server to modify:
- `mnemo-server/mnemo/__init__.py` — DELETE (convert to implicit namespace package)
- `mnemo-server/pyproject.toml` — update dependency version constraint
- `mnemo-server/mnemo/simulation/harness.py:40` — update import `mnemo_client` → `mnemo.client`
- `mnemo-server/tests/test_client.py:11` — update import `mnemo_client` → `mnemo.client`

---

## Task 1: Restructure client into src layout

**Files:**
- Create: `src/mnemo/client.py` (copy of `mnemo_client.py`)
- Modify: `pyproject.toml`
- Delete: `mnemo_client.py`

- [ ] **Step 1: Create src directory structure**

```bash
mkdir -p src/mnemo
```

Do NOT create `src/mnemo/__init__.py`. This must be an implicit namespace package.

- [ ] **Step 2: Copy client module into src layout**

```bash
cp mnemo_client.py src/mnemo/client.py
```

The file contents stay exactly the same — no modifications to the client code.

- [ ] **Step 3: Update pyproject.toml for src layout**

Replace the current `pyproject.toml` with:

```toml
[project]
name = "mnemo-ai"
version = "0.2.0"
description = "Lightweight async Python client for the Mnemo API"
readme = "README.md"
license = "Apache-2.0"
requires-python = ">=3.12"
authors = [
    { name = "Inforge-ai" },
]
classifiers = [
    "Development Status :: 3 - Alpha",
    "Intended Audience :: Developers",
    "License :: OSI Approved :: Apache Software License",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.12",
    "Programming Language :: Python :: 3.13",
    "Typing :: Typed",
]
dependencies = [
    "httpx>=0.26.0",
]

[project.optional-dependencies]
mcp = [
    "mcp>=1.0.0",
]

[project.scripts]
mnemo-mcp = "mnemo.mcp.server:main"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = ["src/mnemo"]

[tool.pytest.ini_options]
asyncio_mode = "auto"

[dependency-groups]
dev = [
    "pytest>=9.0.0",
    "pytest-asyncio>=1.0.0",
]
```

Key changes from the original:
- Version bumped to `0.2.0`
- `packages = ["src/mnemo"]` replaces the old flat-file build config
- Added `[project.optional-dependencies] mcp`
- Added `[project.scripts] mnemo-mcp`
- Added pytest config and dev dependencies

- [ ] **Step 4: Delete old flat module file**

```bash
rm mnemo_client.py
```

- [ ] **Step 5: Verify the client installs and imports correctly**

```bash
cd /home/mnemo/mnemo-client
uv pip install -e .
python -c "from mnemo.client import MnemoClient, MnemoClientSync, MnemoAuthError, MnemoNotFoundError, MnemoServerError; print('OK')"
```

Expected: `OK`

- [ ] **Step 6: Verify old import path no longer works (expected)**

```bash
python -c "from mnemo_client import MnemoClient" 2>&1 || echo "EXPECTED FAILURE"
```

Expected: `ModuleNotFoundError` — this is correct, the old import path is gone.

- [ ] **Step 7: Add .gitignore**

Create or update `.gitignore` to cover the new layout:

```
__pycache__/
*.pyc
.venv/
dist/
*.egg-info/
.pytest_cache/
.env
```

- [ ] **Step 8: Commit**

```bash
git add src/mnemo/client.py pyproject.toml .gitignore
git rm mnemo_client.py
git commit -m "refactor: restructure mnemo_client.py into src/mnemo/client.py

Move from flat single-file module to src layout with implicit namespace
package. This prepares for merging mnemo-mcp into the same package.

Import path changes: mnemo_client → mnemo.client"
```

---

## Task 2: Move MCP server code into the repo

**Files:**
- Create: `src/mnemo/mcp/__init__.py`
- Create: `src/mnemo/mcp/__main__.py`
- Create: `src/mnemo/mcp/server.py`

**Source:** `/home/mnemo/mnemo-mcp/mnemo_mcp/`

- [ ] **Step 1: Create MCP package directory**

```bash
mkdir -p src/mnemo/mcp
```

- [ ] **Step 2: Create empty `__init__.py`**

Create `src/mnemo/mcp/__init__.py` as an empty file. This marks `mcp` as a regular subpackage under the `mnemo` namespace.

- [ ] **Step 3: Copy server.py and update imports**

Copy `/home/mnemo/mnemo-mcp/mnemo_mcp/server.py` to `src/mnemo/mcp/server.py`.

Then update the import line. Change:

```python
from mnemo_client import MnemoClient, MnemoAuthError, MnemoNotFoundError
```

to:

```python
from mnemo.client import MnemoClient, MnemoAuthError, MnemoNotFoundError
```

This is the only import change needed in server.py. All other imports (mcp, logging, os, etc.) stay the same.

- [ ] **Step 4: Create `__main__.py`**

Create `src/mnemo/mcp/__main__.py` — this enables `python -m mnemo.mcp`:

```python
from mnemo.mcp.server import main

main()
```

Intentionally unconditional (matching the original). The console script (`mnemo-mcp`) points directly at `mnemo.mcp.server:main` in pyproject.toml, so `__main__.py` is only used by `python -m`.

- [ ] **Step 5: Verify MCP module imports (with mcp extra installed)**

```bash
cd /home/mnemo/mnemo-client
uv pip install -e ".[mcp]"
python -c "from mnemo.mcp.server import mcp_server; print('OK')"
```

Expected: `OK`

- [ ] **Step 6: Verify `python -m mnemo.mcp` starts (then Ctrl+C)**

```bash
timeout 3 python -m mnemo.mcp 2>&1 || true
```

Expected: either starts the server (then times out) or fails with a config error about missing `MNEMO_API_KEY`/`MNEMO_BASE_URL` — both are fine. The point is the module loads.

- [ ] **Step 7: Commit**

```bash
git add src/mnemo/mcp/
git commit -m "feat: merge mnemo-mcp server into mnemo-ai package

MCP server is now at mnemo.mcp (was mnemo_mcp in separate repo).
Install with: pip install mnemo-ai[mcp]
Run with: mnemo-mcp or python -m mnemo.mcp"
```

---

## Task 3: Move MCP tests

**Files:**
- Create: `tests/test_mcp/__init__.py`
- Create: `tests/test_mcp/test_server.py`

**Source:** `/home/mnemo/mnemo-mcp/tests/test_server.py`

- [ ] **Step 1: Create test directory**

```bash
mkdir -p tests/test_mcp
touch tests/test_mcp/__init__.py
```

- [ ] **Step 2: Copy test file and update imports**

Copy `/home/mnemo/mnemo-mcp/tests/test_server.py` to `tests/test_mcp/test_server.py`.

Update all imports and references in the test file. There are four categories:

1. **Module alias** (line 10) — change:
   ```python
   import mnemo_mcp.server as srv
   ```
   to:
   ```python
   import mnemo.mcp.server as srv
   ```
   This alias is used by all `patch.object(srv, ...)` calls throughout the tests.

2. **Client imports** (line 11) — change:
   ```python
   from mnemo_client import MnemoAuthError, MnemoNotFoundError
   ```
   to:
   ```python
   from mnemo.client import MnemoAuthError, MnemoNotFoundError
   ```

3. **Server imports** (line 12) — change:
   ```python
   from mnemo_mcp.server import (
   ```
   to:
   ```python
   from mnemo.mcp.server import (
   ```

4. **Docstring** (line 1) — change:
   ```python
   """Tests for mnemo_mcp.server startup validation and tools."""
   ```
   to:
   ```python
   """Tests for mnemo.mcp.server startup validation and tools."""
   ```

To find and verify all occurrences:

```bash
grep -n "mnemo_mcp" tests/test_mcp/test_server.py
grep -n "mnemo_client" tests/test_mcp/test_server.py
```

Replace every `mnemo_mcp` with `mnemo.mcp` and every `mnemo_client` with `mnemo.client` throughout the file.

- [ ] **Step 3: Run the tests**

```bash
cd /home/mnemo/mnemo-client
uv run pytest tests/test_mcp/test_server.py -v
```

Expected: all tests pass (there are ~40 tests across 7 test classes).

- [ ] **Step 4: Commit**

```bash
git add tests/
git commit -m "test: add MCP server tests from mnemo-mcp repo

All test imports updated for new package structure."
```

---

## Task 4: Guard MCP imports at package boundary

**Files:**
- Verify: `src/mnemo/mcp/__init__.py` (should be empty)
- Verify: no top-level imports of MCP deps

This task is about verifying — the architecture already guards this naturally since:
- `src/mnemo/` has no `__init__.py` (implicit namespace, imports nothing)
- `src/mnemo/mcp/__init__.py` is empty
- MCP dependencies (`mcp` library) are only imported inside `src/mnemo/mcp/server.py`

- [ ] **Step 1: Verify base install doesn't pull in MCP deps**

```bash
cd /home/mnemo/mnemo-client
uv venv --seed /tmp/test-no-mcp
/tmp/test-no-mcp/bin/pip install -e .
/tmp/test-no-mcp/bin/python -c "from mnemo.client import MnemoClient; print('client OK')"
/tmp/test-no-mcp/bin/python -c "import mcp" 2>&1 | grep -q "ModuleNotFoundError" && echo "mcp NOT installed (correct)"
rm -rf /tmp/test-no-mcp
```

Expected: client imports fine, `mcp` is not installed.

- [ ] **Step 2: Verify importing mnemo doesn't crash without mcp extra**

```bash
cd /home/mnemo/mnemo-client
uv venv --seed /tmp/test-no-mcp2
/tmp/test-no-mcp2/bin/pip install -e .
/tmp/test-no-mcp2/bin/python -c "
from mnemo.client import MnemoClient
print('client import OK')
try:
    from mnemo.mcp.server import mcp_server
    print('ERROR: should have failed')
except ImportError:
    print('mcp import correctly fails without extra')
"
rm -rf /tmp/test-no-mcp2
```

Expected: client OK, MCP import fails with ImportError.

- [ ] **Step 3: No commit needed** (verification only)

---

## Task 5: Update mnemo-server for namespace compatibility

**Files:**
- Delete: `/home/mnemo/mnemo-server/mnemo/__init__.py` — convert to implicit namespace package
- Modify: `/home/mnemo/mnemo-server/pyproject.toml:18` — add version constraint
- Modify: `/home/mnemo/mnemo-server/mnemo/simulation/harness.py:40` — update import
- Modify: `/home/mnemo/mnemo-server/tests/test_client.py:11` — update import

- [ ] **Step 1: Remove mnemo/__init__.py to enable namespace package**

Delete the empty `mnemo/__init__.py` from mnemo-server so both packages can share the `mnemo` namespace:

```bash
cd /home/mnemo/mnemo-server
git rm mnemo/__init__.py
```

This file is empty (0 bytes) — removing it converts `mnemo` from a regular package to an implicit namespace package. All existing imports (`from mnemo.server.xxx import ...`) continue to work identically.

- [ ] **Step 2: Verify mnemo-server still works without `__init__.py`**

```bash
cd /home/mnemo/mnemo-server
python -c "from mnemo.server.config import settings; print('OK')"
```

Expected: `OK`

- [ ] **Step 3: Update pyproject.toml dependency version**

In `/home/mnemo/mnemo-server/pyproject.toml`, change:

```toml
    "mnemo-ai",
```

to:

```toml
    "mnemo-ai>=0.2.0",
```

Keep the `[tool.uv.sources]` path entry unchanged — the repo directory is still `mnemo-client`, so `mnemo-ai = { path = "../mnemo-client" }` is correct for local dev.

**Note:** The spec says to cut over to a PyPI version constraint (`"mnemo-ai>=0.2.0"` without the path source). The path source is kept here for local development. Tom should remove the `[tool.uv.sources]` override when deploying against the published PyPI package.

- [ ] **Step 4: Update import in harness.py**

In `/home/mnemo/mnemo-server/mnemo/simulation/harness.py`, line 40, change:

```python
            from mnemo_client import MnemoClient
```

to:

```python
            from mnemo.client import MnemoClient
```

- [ ] **Step 5: Update imports in test_client.py**

In `/home/mnemo/mnemo-server/tests/test_client.py`, line 11, change:

```python
from mnemo_client import (
    MnemoClient,
    MnemoClientSync,
    MnemoAuthError,
    MnemoNotFoundError,
    MnemoServerError,
    RememberResult,
    RecallResult,
)
```

to:

```python
from mnemo.client import (
    MnemoClient,
    MnemoClientSync,
    MnemoAuthError,
    MnemoNotFoundError,
    MnemoServerError,
    RememberResult,
    RecallResult,
)
```

- [ ] **Step 6: Verify mnemo-server still resolves its dependencies**

```bash
cd /home/mnemo/mnemo-server
uv sync
python -c "from mnemo.client import MnemoClient; print('OK')"
```

Expected: `OK`

- [ ] **Step 7: Commit (in mnemo-server repo)**

```bash
cd /home/mnemo/mnemo-server
git add pyproject.toml mnemo/simulation/harness.py tests/test_client.py
git commit -m "refactor: namespace package + updated mnemo-ai imports

- Remove empty mnemo/__init__.py to enable implicit namespace package
  (allows mnemo-ai and mnemo-server to coexist under the mnemo namespace)
- Update imports: mnemo_client → mnemo.client (mnemo-ai v0.2.0)"
```

---

## Task 6: Update README

**Files:**
- Modify: `README.md`

- [ ] **Step 1: Rewrite README for unified package**

Replace the README with updated content covering:

1. Overview — persistent memory for AI agents (client library + MCP server)
2. Installation:
   - Client only: `pip install mnemo-ai` or `uv add mnemo-ai`
   - With MCP server: `pip install mnemo-ai[mcp]` or `uv add "mnemo-ai[mcp]"`
3. Quick Start — async and sync client examples (same as current, but update import from `mnemo_client` to `mnemo.client`)
4. MCP Server for Claude Desktop:
   ```json
   {
     "mcpServers": {
       "mnemo": {
         "command": "uvx",
         "args": ["mnemo-ai[mcp]"]
       }
     }
   }
   ```
   Environment variables: `MNEMO_API_KEY`, `MNEMO_BASE_URL`, `MNEMO_DEFAULT_AGENT_ID`
5. API Reference (same as current, with updated import paths)
6. License — Apache 2.0

Keep the existing API reference tables and response type docs, just update the import paths.

- [ ] **Step 2: Commit**

```bash
cd /home/mnemo/mnemo-client
git add README.md
git commit -m "docs: update README for unified mnemo-ai package

Cover both client library and MCP server installation/usage."
```

---

## Task 7: Final verification

- [ ] **Step 1: Clean install test (client only)**

```bash
cd /home/mnemo/mnemo-client
uv venv --seed /tmp/test-final
/tmp/test-final/bin/pip install .
/tmp/test-final/bin/python -c "from mnemo.client import MnemoClient, MnemoClientSync; print('client OK')"
rm -rf /tmp/test-final
```

- [ ] **Step 2: Clean install test (with MCP)**

```bash
cd /home/mnemo/mnemo-client
uv venv --seed /tmp/test-final-mcp
/tmp/test-final-mcp/bin/pip install ".[mcp]"
/tmp/test-final-mcp/bin/python -c "from mnemo.client import MnemoClient; from mnemo.mcp.server import mcp_server; print('all OK')"
rm -rf /tmp/test-final-mcp
```

- [ ] **Step 3: Run all MCP tests**

```bash
cd /home/mnemo/mnemo-client
uv run pytest tests/test_mcp/ -v
```

Expected: all tests pass.

- [ ] **Step 4: Verify console script entry point**

```bash
cd /home/mnemo/mnemo-client
uv pip install -e ".[mcp]"
which mnemo-mcp && echo "entry point installed"
timeout 3 mnemo-mcp 2>&1 || true
```

Expected: entry point exists, starts (or fails on config, which is fine).

- [ ] **Step 5: Verify `python -m mnemo.mcp` works**

```bash
timeout 3 python -m mnemo.mcp 2>&1 || true
```

- [ ] **Step 6: Do NOT publish to PyPI** — Tom handles this manually.
