Metadata-Version: 2.4
Name: aleth-client
Version: 1.6.2
Summary: Thin, standalone Python client for the Aleth memory engine over its local wire. Depends only on pydantic.
Author: Aleth Authors
License: Apache-2.0
Project-URL: Homepage, https://alethmemory.com
Project-URL: Repository, https://github.com/aleth-ai/aleth
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pydantic<3,>=2
Dynamic: license-file

# aleth-client

A thin, standalone Python client for **Aleth's persistent memory** over the
engine's local wire. It imports **no engine package** and
depends only on **pydantic** -- any Python project or agent can `pip install` it
and get durable memory without pulling in the engine.

**License:** Apache-2.0. The client is open-source; the Aleth engine (the
daemon this client talks to) is distributed separately.

Documentation and results: https://alethmemory.com. Repository:
https://github.com/aleth-ai/aleth.

## Install

```bash
pip install aleth-client
```

From a source checkout, `pip install .` in this directory installs that
version instead.

## 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
pip install aleth-memory
aleth start        # runs in the background and writes .aleth_daemon.json
```

## 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])

# Retire a belief behind its replacement, without deleting it
old = mem.remember("Priya owns the pricing model.")
new = mem.remember("Marco owns the pricing model.")
mem.supersede(old.node_id, new.node_id)

# Really delete a memory, when you want it gone
mem.forget(fact.node_id)
```

### Method surface

The eleven verbs the Aleth engine serves: `remember, remember_batch, recall,
show, search, retract, forget, supersede, connect_nodes, status, nodes`, with
`recall_deep`, `recall_fused` and `recall_reranked` as ways to recall.

The client also carries methods the Aleth engine does not serve (goals,
reasoning chains, hypotheses and policy checks). Calling one against the engine
returns a clear error naming the eleven-verb surface; it never fails silently.

### Errors

`DaemonUnavailable` (no daemon answered), `BackendError` (daemon-side failure,
incl. an `[UNCERTAIN]` write whose confirmation never arrived -- verify before
retrying), `NodeNotFound`, `BIOSDenied` (refused by a policy of the server),
`ProtocolMismatch` (the daemon advertises a different contract MAJOR, or is too old
to honour a parameter whose absence would change what the answer means, such as a
search `projection` or `read_cold`).

## Versioning & compatibility

The wire contract is frozen at `MEMSDK_PROTOCOL_VERSION = "2.4"` and governed by
semver (MAJOR = breaking, MINOR = additive, PATCH = fix). v2.4 adds an optional
`projection` to `search`: `"full"` (the default, unchanged), `"ids"` (node ids only,
for patterns whose matches are too large to ship whole) or `"count"` (the full match
count, no rows), the last two returned as `ProjectedSearchResult`. A server older
than 2.4 cannot honour a projection, so the client raises `ProtocolMismatch` rather
than return full rows under the projected name. Also in v2.4, a search says how
much it could read: some memories can be cold (encrypted at rest, not yet loaded),
and a plain scan cannot read them. The results carry optional coverage fields --
`examined`, `unreadable`, `cold_read`, `coverage_complete`, and `coverage_warning`
when anything went unread (plus `unreadable_ids`, up to 100, naming what a
`read_cold` search still could not read) -- so a miss in an incomplete search is never mistaken for
absence; each is `None` when the server did not send it (a complete default `"full"`
search keeps the plain shape). `search(..., read_cold=True)` reads cold memories
too; it is slower, so the server may stop at its time budget and answer with
`complete=False` and a `resume_at` cursor: call again with `start_at=resume_at`
until `complete` is True. Neither parameter is sent at its default, and a server
that cannot honour `read_cold` makes the client raise `ProtocolMismatch` rather than
answer from the readable part alone. v2.3 adds VALID TIME: the optional `observed_at` / `valid_from` / `valid_to` kwargs on
`remember` and `as_of` on `recall`, plus `valid_at` and the three dates on each
returned row, `as_of` / `order` on the result, and the three dates on `show`. A
superseded belief becomes reachable BY DATE instead of only by being the newest.
v2.2 adds `match_strength` per row and the `coverage` verdict. v2.1 adds the
optional `classification` / `confidence` declaration kwargs on `remember` --
forwarded only when given, so older servers never see them. v1.1 added
`recall_ranked`, a higher-precision, model-ranked recall (now
`recall_reranked`; `recall_fast` likewise became `recall_fused`, the default --
the old names remain as aliases) 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.

## Trust model (read this)

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. This client offers no authenticated per-consumer identity, real tenancy,
or off-box endpoint.

## Which surface do I want?

- **This client (`aleth-client`)** -- you are writing **Python code** in a
  project that needs durable memory over the wire.
- **`aleth-mcp`** -- you are an **AI assistant** (Claude Code, VS Code, or any
  MCP-speaking host) and want the same memory as MCP tools.
