Metadata-Version: 2.4
Name: harness-memory
Version: 0.1.1
Summary: Pluggable memory system with hierarchical recall, FTS search, and multiple backend support.
Project-URL: Homepage, https://github.com/orcakit/harness-memory
Project-URL: Repository, https://github.com/orcakit/harness-memory
Project-URL: Issues, https://github.com/orcakit/harness-memory/issues
Author: orcakit
License-Expression: MIT
License-File: LICENSE
Keywords: agent,fts,llm,memory,recall,sqlite
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.11
Provides-Extra: dev
Requires-Dist: mypy>=1.13; extra == 'dev'
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.8; extra == 'dev'
Provides-Extra: postgres
Requires-Dist: psycopg[binary]>=3.1; extra == 'postgres'
Provides-Extra: qdrant
Requires-Dist: qdrant-client>=1.7; extra == 'qdrant'
Description-Content-Type: text/markdown

# orcakit-harness-memory

[![CI](https://github.com/orcakit/harness-memory/actions/workflows/ci.yml/badge.svg)](https://github.com/orcakit/harness-memory/actions/workflows/ci.yml)
[![PyPI version](https://img.shields.io/pypi/v/orcakit-harness-memory.svg)](https://pypi.org/project/orcakit-harness-memory/)
[![Python versions](https://img.shields.io/pypi/pyversions/orcakit-harness-memory.svg)](https://pypi.org/project/orcakit-harness-memory/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

Pluggable memory system for LLM agents — hierarchical memory tree with full-text search and multiple backend support.

## Features

- **Memory Tree** — Hierarchical summaries (root → branch → leaf) for long-term recall
- **Full-Text Search** — FTS5/BM25 powered search across conversations and memories
- **Conversation Records** — Standardized chat history storage and retrieval
- **Pluggable Backends** — SQLite (default, zero-dep), PostgreSQL, Qdrant
- **Zero Dependencies** — Core package uses only Python stdlib + sqlite3
- **Namespace Isolation** — Multiple agents share one database safely

## Installation

```bash
pip install orcakit-harness-memory
```

Optional backends:

```bash
pip install "orcakit-harness-memory[postgres]"   # PostgreSQL backend
pip install "orcakit-harness-memory[qdrant]"     # Qdrant vector backend
```

## Quickstart

```python
from harness_memory import Memory

# Create with default SQLite backend
memory = Memory(namespace="my-agent")

# Store a memory
memory.store("User prefers Python over Java", topic="preferences")

# Recall relevant memories
results = memory.recall("programming language")
for node in results:
    print(f"[{node.topic}] {node.content}")

# Add a conversation record
from harness_memory import ConversationRecord, Message
from datetime import datetime, timezone

record = ConversationRecord(
    id="conv-001",
    thread_id="thread-1",
    user="alice",
    started_at=datetime.now(timezone.utc),
    ended_at=datetime.now(timezone.utc),
    messages=[
        Message(role="user", content="How do I use memory?", timestamp=datetime.now(timezone.utc)),
        Message(role="assistant", content="Just call memory.store()!", timestamp=datetime.now(timezone.utc)),
    ],
    summary=None,
    metadata={},
)
memory.add_conversation(record)

# Search conversations
hits = memory.search("memory")
for hit in hits:
    print(f"[{hit.role}] {hit.message_content}")
```

## Backend Configuration

```python
# SQLite (default) — zero dependencies
memory = Memory(namespace="agent", backend="sqlite")
memory = Memory(namespace="agent", backend_config={"db_path": "/data/memory.db"})

# PostgreSQL — requires [postgres] extra
memory = Memory(namespace="agent", backend="postgres", backend_config={
    "dsn": "postgresql://user:pass@localhost/memdb"
})

# Qdrant — requires [qdrant] extra
memory = Memory(namespace="agent", backend="qdrant", backend_config={
    "url": "http://localhost:6333"
})

# Custom backend — pass any MemoryBackend instance
memory = Memory(namespace="agent", backend=my_custom_backend)
```

## API Reference

### Memory

| Method | Description |
|--------|-------------|
| `store(content, topic=None)` | Store a memory as a leaf node |
| `recall(query, limit=5)` | Recall relevant memories via FTS |
| `add_conversation(record)` | Persist a conversation record |
| `search(query, limit=10)` | Full-text search across messages |
| `list_conversations(**filters)` | List conversations with filters |
| `get_conversation(id)` | Get full conversation by ID |
| `get_tree()` | Get the complete memory tree |

### Data Types

- `MemoryNode` — A node in the memory tree (root/branch/leaf)
- `ConversationRecord` — Complete conversation with messages
- `Message` — Single message (user/assistant/tool)
- `SearchResult` — FTS search hit with score
- `ConversationSummary` — Lightweight conversation listing

## Development

```bash
make dev          # Install dev dependencies
make lint         # Ruff check + format check
make typecheck    # mypy strict
make test         # pytest
make all          # lint + typecheck + test
```

## License

[MIT](LICENSE)
