Metadata-Version: 2.4
Name: memnode
Version: 0.1.0
Summary: Python client for Memnode, persistent memory for AI agents
Author: memnode
License: MIT
Project-URL: Homepage, https://memnode.dev/docs
Project-URL: Documentation, https://memnode.dev/docs
Project-URL: Repository, https://github.com/memnode/memnode
Project-URL: Issues, https://github.com/memnode/memnode/issues
Keywords: ai,agents,memory,mcp,python,sdk,memnode
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Description-Content-Type: text/markdown

# memnode (Python)

Python client for **Memnode**, persistent memory for AI agents.

- Stdlib-only — no runtime dependencies (uses `urllib`, `json`).
- Wraps the v1 endpoints exposed by the Rust data plane.
- Typed response dataclasses.

## Quickstart and proof

If you land on this package page first, use this order:

1. Install + proof loop: <https://memnode.dev/mcp>
2. Public demo article: <https://memnode.dev/articles/claude-code-memory-demo>
3. Downloadable 14-second proof loop: <https://memnode.dev/article-images/mcp-demo-loop.mp4>
4. Hosted docs: <https://memnode.dev/docs>

The shortest believable Memnode loop is still MCP-first:

- teach Claude Code one repo convention
- start a fresh task or later session
- recall it and inspect lineage

## Install

Published package:

```bash
pip install memnode
```

Local development:

```bash
cd clients/python
pip install -e .
```

## Usage

```python
from memnode import MemnodeClient

client = MemnodeClient("https://api.memnode.dev", "mn_live_...")

result = client.recall("Where is the user moving?")
print(result.answer, result.confidence)
for hit in result.supporting_memories:
    print(hit.node_id, hit.props.get("summary"), hit.score)

query = client.query(
    "Observation",
    filter={
        "_memory_status": {"$in": ["supported", "canonical"]},
        "_support_count": {"$gte": 3},
    },
    limit=10,
)
print(query.nodes[0].props.get("summary"))

client.feedback(memory_id=result.supporting_memories[0].node_id, helpful=True)

health = client.healthz()
print(health.ok)
```

Compatibility import still works:

```python
from memnode_client import MemnodeClient
```

For the shortest proof loop, start with the local MCP path first and keep this package for hosted or app-backend use.

## Endpoints

| Method                  | HTTP                      | Notes                                             |
|-------------------------|---------------------------|---------------------------------------------------|
| `recall`                | `POST /v1/recall`         | Returns typed `RecallResponse`                    |
| `feedback`              | `POST /v1/feedback`       | Mark a supporting memory helpful / not helpful    |
| `explain`               | `POST /v1/explain`        | Raw JSON with per-edge scoring                    |
| `query`                 | `POST /v1/query`          | Structured query for memory inspection            |
| `record_procedure`      | `POST /v1/procedures`     | Persist a trigger → action-sequence procedure     |
| `recall_procedures`     | `GET /v1/procedures`      | Retrieve procedures, optionally by trigger        |
| `memory_lineage`        | `GET /v1/lineage/{id}`    | CORRECTS / SUPERSEDES / DERIVED_FROM chain        |
| `healthz`               | `GET /healthz`            | Liveness probe                                    |
| `status`                | `GET /v1/status`          | Control-plane lease + data-plane counters         |

Recording raw observations over HTTP is not yet supported server-side. Until
`POST /v1/record` ships, use the MCP transport to record memories.

## Errors

All errors inherit from `MemnodeError`:

- `MemnodeAuthError` — 401/403
- `MemnodeRateLimitError` — 429, carries `retry_after` seconds when the server
  returns a `Retry-After` header
- `MemnodeUnavailableError` — 503 (control-plane lease gone, data plane shutting
  down, etc.)
- `MemnodeHTTPError` — other non-2xx responses, carries `status` and `body`

## Tests

```bash
PYTHONPATH=clients/python python -m unittest discover clients/python/tests
```

Tests spin up an in-process `http.server` on a random port and drive the client
end-to-end — no mocks, no fixtures.
