Metadata-Version: 2.4
Name: aleth-client
Version: 1.3.0
Summary: Thin, standalone Python client for the Aleth memory engine over the frozen local wire (MEM-SDK, ROADMAP ch.161). Depends only on pydantic.
Author: Aleth Authors
License: Apache-2.0
Project-URL: Homepage, https://aleth.ai
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pydantic>=2
Dynamic: license-file

# aleth-client

A thin, standalone Python client for **Aleth's persistent memory + thesis
tracking** over the warm-daemon wire. Part of MEM-SDK (ROADMAP ch.161,
Option A). It imports **no engine package** and depends only on **pydantic** --
a sibling project (a Hand, another venture's agent) can `pip install` it and get
durable memory without pulling in the Brain.

**License (S1421):** MIT. The client and the MPB-2 host plugins
(`clients/aleth-hermes`, `clients/aleth-openclaw`) are
open-source; the Aleth engine (the daemon this client talks to) stays closed.

## Install

```bash
pip install ./clients/aleth-client
```

(In-repo install only -- no PyPI publish, by design. Copy the directory into a
sibling project and `pip install ./aleth-client` there.)

## Prerequisite: a running engine

The client talks to a **running engine** discovered via its
`.aleth_daemon.json` discovery file (under `data/runtime/` by default, or pass
`discovery_dir=` / set `ALETH_DISCOVERY_DIR`). The daemon holds the warm graph;
the client stays thin and never loads a local copy.

```bash
# the host that serves this wire in-repo (it writes .aleth_daemon.json):
python -m enki.runtime --pool-id baseline-pool --is-master --data-dir data --detach
```

## Usage

```python
from aleth_client import MemoryClient

mem = MemoryClient().connect()          # verifies reachability + protocol MAJOR

node = mem.remember("The sky is blue", origin="user")
print(node.node_id, node.classification)   # a computed judgment, not a constant

# Declare what you know about your own memory; your word outranks analysis.
fact = mem.remember("My locker code is 4312", classification="fact")

hits = mem.recall("sky", limit=5)
for n in hits.nodes:
    print(n.node_id, round(n.score, 3), n.content[:60])

# Thesis tracking
mem.store_reasoning_chain(
    chain_id="my_decision", title="My decision",
    steps=["weighed A [0.8]", "B cheaper [0.9]"], session_number=1,
)
h = mem.create_hypothesis(
    prediction="X holds", rationale="...", falsification_condition="...",
    confidence=0.6, hypothesis_type="completion", testability=0.8,
    testable_criteria="...", source_node_ids=[],
)
mem.add_hypothesis_evidence(
    hypothesis_id=h.node_id, outcome="confirmed",
    evidence_node_ids=[], confidence_change=0.1, experiment_id="exp1",
)
```

### Method surface

Memory: `remember, recall, recall_deep, recall_ranked, show, search, retract,
connect_nodes, status, nodes`. Thesis: `store_intuition, store_reasoning_chain,
session_checkpoint, recall_chains, recall_intuitions, create_hypothesis,
add_hypothesis_evidence, retract_hypothesis`. Goals: `goal_create, goals_list,
goal_detail, goal_progress, goal_achieve, goal_abandon`. Governance:
`bios_check, bios_status`. (No `forget` -- the memory surface is retract-based,
matching the wire.)

### Errors

`DaemonUnavailable` (no daemon answered), `BackendError` (daemon-side failure,
incl. an `[UNCERTAIN]` write whose confirmation never arrived -- verify before
retrying), `NodeNotFound`, `BIOSDenied` (blocked by a BIOS axiom),
`ProtocolMismatch` (the daemon advertises a different contract MAJOR).

## Versioning & compatibility

The wire contract is frozen at `MEMSDK_PROTOCOL_VERSION = "2.1"` and governed by
semver (MAJOR = breaking, MINOR = additive, PATCH = fix). v2.1 (EPI-1, S1565)
adds the optional `classification` / `confidence` declaration kwargs on
`remember` -- forwarded only when given, so older servers never see them. v1.1 (MPB-2, S1421)
adds `recall_ranked` -- daemon-side cross-encoder-ranked recall
(bge-reranker-v2-m3 on CUDA hosts / ms-marco-MiniLM-L-12-v2 on CPU) whose
nodes carry `created_at` for the dated presentation helper
(`aleth_client.presentation.dated_block`). The daemon advertises
its version via `sdk_status`; `connect()` checks the MAJOR matches and raises
`ProtocolMismatch` otherwise. The full spec is
[`docs/architecture/deployment/mem-sdk-contract.md`](../../docs/architecture/deployment/mem-sdk-contract.md);
drift between this copy and the engine is caught by the conformance guard
(`tests/test_contract_conformance.py`, MSDK-3).

## Trust model (read this -- MSDK-5)

This client authenticates to the daemon with a **local discovery-file token**
and inherits the **same-box trust boundary**: everything on the box is the
operator. It does **NOT** provide per-consumer identity, tenancy isolation, or
off-box transport, and a plain `recall` sees the **GLOBAL** memory graph (the
`source_project` tag is a filter, not a partition). **Do not** expose this
client across a trust boundary or treat it as an externally-safe, multi-tenant
API. Anyone needing authenticated per-consumer identity, real tenancy, or an
off-box endpoint wants the (un-built, rejected-for-now) Option B in
`docs/ROADMAP_ALT.md`.

## Which surface do I want?

- **This client (`aleth-client`)** -- you are writing **Python code** in a
  sibling project that needs durable memory over the wire.
- **The foreign-MCP-window path** -- you are an **assistant window** (Claude
  Code / VS Code) working inside another venture's repo and want the memory
  graph as MCP tools with project provenance. See
  [`docs/reference/using-enki-from-other-projects.md`](../../docs/reference/using-enki-from-other-projects.md).
