Metadata-Version: 2.4
Name: contextstore-sdk
Version: 0.2.0
Summary: Client SDK for the ContextStore company brain — compiled memory and agent team, accessed via a typed Python API.
Author: ContextStore
License: MIT
Project-URL: Homepage, https://contextstore.oritm.tech
Keywords: memory,mcp,second-brain,agents,knowledge-base
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Provides-Extra: langchain
Requires-Dist: langchain-core>=0.2; extra == "langchain"
Provides-Extra: langgraph
Requires-Dist: langgraph>=0.2; extra == "langgraph"
Provides-Extra: all
Requires-Dist: langchain-core>=0.2; extra == "all"
Requires-Dist: langgraph>=0.2; extra == "all"

# ContextStore Python SDK

Talk to your ContextStore **company brain** — compiled memory + agent team — from
Python. The SDK is a typed client over your backend's MCP JSON-RPC layer.

## Install

```bash
pip install contextstore-sdk
```

## Quickstart

```python
import os
from contextstore import ContextStore

client = ContextStore(api_key=os.environ["CONTEXTSTORE_KEY"])

# Remember something
client.memory.add(
    content="Board approved usage-based pricing on Sep 12",
    metadata={"project": "pricing", "owner": "maya"},
)

# Ask the company brain — with sources
res = client.memory.query("What did we decide about pricing?")
print(res.answer)
print(res.sources)
```

## Local / self-hosted

Point at your own backend (default is the hosted one):

```python
client = ContextStore(
    api_key=os.environ["CONTEXTSTORE_KEY"],
    base_url="https://contextstore.onrender.com",
)
```

For local development you can pass a JWT instead of an api_key:

```python
client = ContextStore(token="<jwt>")
```

## Namespaces / methods

| Python | Backend MCP tool |
|---|---|
| `client.memory.add(...)` | `memory_store` |
| `client.memory.query(...)` | `memory_recall` |
| `client.memory.log_turn(...)` | `log_conversation_turn` |
| `client.context.snapshot()` | `get_context_snapshot` |
| `client.context.checkin(...)` | `smart_checkin` |
| `client.company.learn(...)` | `company_learn` |
| `client.company.map()` / `.set_map(...)` | `company_map` |
| `client.company.review(run=True)` | `company_review` |
| `client.company.approve(...)` / `.reject(...)` | `review_propagation` |
| `client.company.pending(...)` | `list_propagation_queue` |
| `client.permissions.grant/revoke/list(...)` | permission admin tools |
| `client.permissions.check_authority(...)` | `check_action_authority` |

## Scopes & API keys

Each API key carries a set of scopes that limit which tools it may call. Pick the smallest set your app needs:

| Scope | Allows |
|---|---|
| `memory:rw` | Store, query, and manage memories and sessions |
| `context:read` | Read snapshots, session context, and local/Notion context |
| `company:read` | Read the company map, learnings, org info, and the review queue |
| `company:write` | Learn corrections, publish map/playbooks, approve propagation |
| `admin` | Everything above, plus permission management and revocation |

Required scope per namespace:

| Namespace | Methods | Scope |
|---|---|---|
| `client.memory.*` | `add`, `query`, `log_turn`, `supersede` | `memory:rw` |
| `client.context.*` | `snapshot`, `checkin` | `context:read` |
| `client.company.map()` | read map / playbooks | `company:read` |
| `client.company.map(set_map=...)` | publish map | `company:write` |
| `client.company.learn` / `approve` / `reject` | | `company:write` |
| `client.company.review` / `pending` | | `company:read` |
| `client.permissions.*` | `grant`, `revoke`, `list`, `check_authority` | `admin` |

A key with `admin` scope satisfies every tool. Requests authenticated with a user JWT (instead of an API key) are not scope-limited.

## Errors

- `AuthenticationError` — bad/expired/scoped-out API key
- `ApiError` — the MCP tool returned an error
- `ContextStoreError` — network / transport issues

No external dependencies — uses only the Python standard library.

## Framework adapters (optional)

Wire ContextStore memory into LangChain / LangGraph agents so they read and write
the company brain through the same scoped, review-gated layer.

```bash
pip install "contextstore-sdk[all]"   # langchain-core + langgraph
```

```python
from contextstore import ContextStore
from contextstore.langchain import ContextStoreStore, memory_tools

client = ContextStore(api_key=os.environ["CONTEXTSTORE_KEY"])

# 1) LangGraph long-term semantic memory (BaseStore)
store = ContextStoreStore(client)
await store.aput(("memories", "pricing"), "price-decision",
                 {"content": "Board approved usage-based pricing on Sep 12"})
await store.asearch(("memories", "pricing"), "what did we decide about pricing?")

# 2) A ready-made agent tool list (includes the action-authority gate)
tools = memory_tools(client)
```

Exact short-term thread state should stay in LangGraph's built-in
`MemorySaver`; `ContextStoreStore` is the governed long-term memory layer.
`ContextStoreStore.delete` is intentionally unavailable to agents — memory
removal goes through the human review/consent ritual.

For conversation history (`BaseChatMessageHistory`):

```python
from contextstore.langchain import ContextStoreChatMessageHistory
history = ContextStoreChatMessageHistory(client, thread_id="tx-42", thread_label="pricing")
history.add_user_message("What's our pricing position?")
history.add_ai_message("Usage-based pricing, approved Sep 12.")
print(history.messages)
```

### LongMemEval benchmark provider

Run ContextStore through the official LongMemEval harness
(`pip install longmemeval`):

```bash
export CONTEXTSTORE_KEY="ctsk_..."
python -m longmemeval.provider contextstore --config_file your_config.json
```

The provider maps `add` → `memory_store`, `get` → `memory_recall`,
`update` → `memory_store` (update source), and needs no imports from the
harness package (`contextstore.longmemeval.ContextStoreMemProvider`).
