stele-sdk 0.2.2
STELE Python SDK and local bootstrap helpers (HTTP client + optional local steled launcher).
Requires Python: >=3.9

# stele (Python)

Dependency-free Python SDK for STELE (stdlib `urllib`, Python 3.9+).

This package contains:
- `stele_sdk`: the HTTP client (in-repo module)
- `stele`: thin wrapper module + optional local bootstrap helpers (installed from `pip install stele-sdk`)

If you want a deeper dive, see the repo docs at `docs/sdk/python.md`.

## Install

```bash
pip install stele-sdk
```

```python
from stele import SteleClient, APIError
```

Package note:
- PyPI distribution name: `stele-sdk`
- Import module for published package usage: `stele`

## Client Configuration

```python
client = SteleClient(
    base_url="http://127.0.0.1:8080",
    api_version="v1",
    agent_id="agent-1",
    session_id="session-1",
    client_id="my-app",
    embedder_override="",     # optional
    ops_auth_token="",        # optional; also read from STELE_OPS_AUTH_TOKEN / STELE_MCP_AUTH_TOKEN
    timeout=15,
)
```

Environment defaults (when not passed explicitly):
- `STELE_BASE_URL`
- `STELE_API_VERSION`
- `STELE_AGENT_ID`
- `STELE_SESSION_ID`
- `STELE_CLIENT_ID`
- `STELE_EMBEDDER_OVERRIDE`
- `STELE_OPS_AUTH_TOKEN` (ops endpoints)
- `STELE_MCP_AUTH_TOKEN` (ops endpoints; convenience fallback)

## Minimal Example: Write + Query

```python
import time
from stele import SteleClient

client = SteleClient(
    base_url="http://127.0.0.1:8080",
    agent_id="agent-1",
    session_id="session-1",
)

write = client.write(
    {
        "memory": {
            "content": "We should attach provenance.source_refs to all writes.",
            "type": "MEMORY_TYPE_PROCEDURAL",
            "scope": "SCOPE_AGENT",
            "provenance": {
                "source_refs": ["run:sdk/python/README.md#minimal-example"],
                "citations": [],
                "origin_turn_id": "",
            },
            "timestamp_ms": int(time.time() * 1000),
        }
    }
)
print("wrote:", (write.get("memory") or {}).get("id"))

query = client.query(
    {
        "query_text": "What provenance should we attach?",
        "budget_tokens": 250,
        "scope_order": ["SCOPE_AGENT", "SCOPE_TEAM", "SCOPE_PROJECT", "SCOPE_GLOBAL"],
    }
)
print("recall:", len(query.get("memories") or []))
```

## Optional: Local Bootstrap (No Go Toolchain)

If you have GitHub Release assets published for this repo, you can bootstrap a local `steled` before creating the client:

```python
from stele.local import ensure_running
from stele import SteleClient

ensure_running()
client = SteleClient(agent_id="agent-1", session_id="session-1")
print(client.query({"query_text": "sanity check"}))
```

## Error Handling

Non-2xx responses raise `APIError`:

```python
from stele import APIError

try:
    client.reindex({})
except APIError as exc:
    print("status:", exc.status_code, "code:", exc.code, "request:", exc.request_id, "msg:", exc.message)
```

## Graph Example: Add Edge + List

```python
import time

client.edge_add(
    {
        "edge": {
            "from_id": "mem-aaa",
            "to_id": "mem-bbb",
            "type": "EDGE_TYPE_RELATES_TO",
            "weight": 1,
            "created_at_ms": int(time.time() * 1000),
        }
    }
)

edges = client.edge_list({"node_id": "mem-aaa"})
print(edges.get("edges"))
```

## Proactive Surfacing Helper

Use the built-in trigger orchestrator when you want SDK-side proactive suggest parity:

```python
suggestor = client.create_proactive_suggestor()
suggestor.trigger("bootstrap", {"active_files": ["README.md"]})
suggestor.trigger(
    "context_shift",
    {"active_files": ["src/auth/handler.go"], "recent_commands": ["plan:implement"]},
)
suggestor.trigger("pre_edit", {"active_symbols": ["AuthHandler"]})
```

`ProactiveSuggestor` enforces debounce, context-hash dedupe, rate limits, and payload caps before calling `suggest`.

## Ops Endpoints (Bearer Token)

Ops endpoints require `ops_auth_token` (or env `STELE_OPS_AUTH_TOKEN` / `STELE_MCP_AUTH_TOKEN`):
- `bulk_forget`
- `export_ndjson` / `export_to_file`
- `import_memories`
- `maintenance`
- `reindex`
- `decay`

### Export to File (Convenience)

```python
import os
from stele import SteleClient

ops = SteleClient(
    base_url="http://127.0.0.1:8080",
    agent_id="agent-1",
    session_id="session-1",
    ops_auth_token=os.environ.get("STELE_OPS_AUTH_TOKEN", ""),
)
ops.export_to_file("stele-export.jsonl")
```

### Import

```python
from stele import SteleClient

with open("stele-export.jsonl", "r", encoding="utf-8") as f:
    ndjson = f.read()

ops.import_memories({"data": ndjson, "strict": False})
```

## API Coverage (Method Map)

Methods map closely to `steled` routes:
- Core: `write`, `query`, `feedback`, `protect`, `supersede`, `forget`
- Retrieval utils: `list_memories`, `get_memory`, `search_memories`, `update_memory`, `verify`, `extract`
- Bulk: `bulk_write`, `bulk_forget` (ops)
- Ops: `export_ndjson`/`export_to_file`, `import_memories`, `schema`, `metrics`, `maintenance`, `reindex`, `decay`
- Graph: `edge_add`, `edge_delete`, `edge_list`, `edge_traverse`, `edge_suggest`
- Proactive/stream: `suggest`, `watch`
- Sharing: `learn_share` (mistake-only)
- Agent/system: `agent_get`, `agent_upsert`, `access_mark_used`, `events`, `membership_add/remove/list`, `health`, `stats`