Skip to main content

Letta memory-mutation adapter for Phionyx runtime evidence — every memory write, clear, forget, or consolidation emits a signed, hash-chained envelope with before/after diff.

Project description

phionyx-letta

Memory-mutation audit chain for Letta agents — every memory write, append, clear, delete, forget, or consolidation emits a signed, hash-chained envelope with a structured before/after diff. AGPL-3.0 · Python 3.10+ · alpha (v0.7.0 W3)

Phionyx-letta is the v0.7.0 W3 (F15) implementation of the memory diff audit layer described in the Phionyx runtime-evidence design. It treats Letta core-memory blocks the same way the rest of the Phionyx stack treats agent turns: every state change is captured in a hash-chained, tamper-evident envelope that a third party can replay without operator-side insider knowledge.

What it gives you

For each memory mutation:

  • A structured diff summary — before/after content hashes, byte sizes, character-level added / removed / unchanged counts.
  • A typed mutation kind — one of write, append, clear, delete, forget, consolidate.
  • An optional forgetting reason — for clear, delete, forget mutations (e.g. explicit_user_request, retention_policy, consolidation_promotion).
  • An optional consolidation audit subblock — for consolidate mutations, cross-references canonical pipeline block #43 (memory_consolidation) with the participating memory ids and algorithm identifier.
  • An optional cross-runtime parent reference — when the mutation was caused by an upstream adapter envelope (langchain, openai_agents, RGE v0.2), this envelope can point back at it via subject.metadata.memory_audit.parent_envelope_ref.

All envelopes share Phionyx's canonical JSON + SHA-256 hash chain + opt-in Ed25519 signing surface (HMAC for demo). The verifier semantics match phionyx-mcp-server.audit_chain.verify_chain byte-for-byte.

Sixty-second usage

from phionyx_letta import (
    MemoryMutationContext,
    HmacSigner,
    FilesystemEnvelopeStore,
    build_memory_envelope,
    compute_memory_diff,
    GENESIS_HASH,
)

signer = HmacSigner(secret="REPLACE_IN_PRODUCTION_WITH_ED25519")
store = FilesystemEnvelopeStore(root="/var/lib/phionyx/letta_audit")

# Compute the diff between before and after content
diff = compute_memory_diff(
    before="User prefers concise answers.",
    after="User prefers concise answers. They speak Turkish.",
)

ctx = MemoryMutationContext(
    trace_id="letta-trace-alex-001",
    turn_index=42,
    producer="letta.agent_alex",
    block_id="block-9e3a-...",
    block_label="core_memory.persona",
    mutation_kind="append",
    diff=diff,
)

envelope = build_memory_envelope(
    ctx=ctx,
    previous_hash=store.head("letta-trace-alex-001"),
    package_version="0.1.0a1",
    signer=signer,
)
store.append("letta-trace-alex-001", envelope)

Schema

phionyx.memory_mutation_envelope.v1 — one envelope per memory mutation event. See examples/envelopes/v0_7_schema_portfolio.md in the parent repo for the cross-runtime composition surface (subject.metadata.memory_audit).

Top-level structure:

{
  "schema": "phionyx.memory_mutation_envelope.v1",
  "subject": {
    "runtime": "phionyx-letta",
    "version": "0.1.0a1",
    "producer": "<letta agent identifier>",
    "turn_index": <int>,
    "event_type": "memory_<kind>",
    "timestamp_utc": "<ISO-8601 UTC>",
    "metadata": {
      "memory_audit": {                              // W3.3 cross-runtime composition (optional)
        "parent_envelope_ref": "envelope://sha256:...",
        "schema": "phionyx.memory_mutation_envelope.v1",
        "kind": "<mutation kind>"
      },
      "<producer-supplied keys>": "..."
    }
  },
  "mutation": {
    "block_id": "<stable Letta block id>",
    "block_label": "<e.g. core_memory.persona>",
    "mutation_kind": "<write|append|clear|delete|forget|consolidate>",
    "diff": {
      "before_hash": "sha256:<hex>",
      "after_hash": "sha256:<hex>",
      "before_size_bytes": <int>,
      "after_size_bytes": <int>,
      "added_chars": <int>,
      "removed_chars": <int>,
      "unchanged_chars": <int>,
      "diff_text": null | "<unified diff>"
    },
    "forgetting_reason": null | "<reason>"
  },
  "memory_consolidation_audit": null | {           // W3.2 — only for `consolidate` mutations
    "block_ref": "pipeline_block_43:memory_consolidation",
    "from_episodic": ["<mem-id>", ...],
    "to_semantic": ["<sem-id>", ...],
    "consolidation_method": "<algorithm id>",
    "decay_applied": null | true | false
  },
  "integrity": {
    "previous": "sha256:<hex>",
    "current":  "sha256:<hex>",
    "signature": "<algo>:<hex>",
    "canonical_json": true
  }
}

Cross-runtime composition (W3.3)

When a Letta memory mutation is triggered by another adapter (a LangGraph node, an OpenAI Agents tool call, an RGE v0.2 turn), the upstream envelope's id can be passed as memory_audit_parent_ref:

envelope = build_memory_envelope(
    ctx=ctx,
    previous_hash=store.head(trace_id),
    package_version="0.1.0a1",
    signer=signer,
    memory_audit_parent_ref="envelope://sha256:<upstream RGE envelope current>",
)

The resulting envelope carries subject.metadata.memory_audit so a reviewer can walk from any upstream envelope to the memory mutation it caused without needing matching schema ids. The reference is one-way (memory envelope → upstream envelope) because the upstream envelope is sealed at sign time and cannot be amended retroactively.

The reverse direction is recommended on upstream emitters that know they cause memory mutations: emit your envelope first, then build the memory mutation envelope with memory_audit_parent_ref set to your own integrity.current. The two envelopes form a verifiable pair.

What this package does NOT do

  • It does not instrument Letta automatically. You compute the diff yourself (with compute_memory_diff or your own logic) and call build_memory_envelope at the right point in your code. A future release MAY ship a Letta runtime hook that intercepts memory writes; v0.1.0a1 ships the audit primitives only.
  • It does not store memory contents by default. diff.diff_text is None unless the caller explicitly requests it (include_diff_text=True). Size deltas + content hashes are always recorded; raw text is opt-in.
  • It does not interpret mutation semantics. A forget envelope with forgetting_reason="retention_policy" is just two strings to this package — the operator decides what they mean.
  • It does not certify compliance. Like the rest of the Phionyx stack, this is evidence-grade audit, not a regulatory attestation.

Status (v0.7.0 W3)

  • W3.1 — per-mutation envelope. Shipped. 20/20 tests pass.
  • W3.2 — forgetting + consolidation audit subblock. Shipped.
  • W3.3 — cross-runtime composition. Shipped via subject.metadata.memory_audit.

v0.7.0 W4 (HearthOS reference deployment + release) follows.

License

AGPL-3.0-or-later. See LICENSE in the parent repo.

Citing

If you use phionyx-letta in academic or policy work, cite the parent project: Abak, A. T. (2026). Phionyx Research — Runtime Evidence Layer for Agentic AI. ORCID 0009-0002-3718-4010.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

phionyx_letta-0.1.0a1.tar.gz (27.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

phionyx_letta-0.1.0a1-py3-none-any.whl (23.1 kB view details)

Uploaded Python 3

File details

Details for the file phionyx_letta-0.1.0a1.tar.gz.

File metadata

  • Download URL: phionyx_letta-0.1.0a1.tar.gz
  • Upload date:
  • Size: 27.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for phionyx_letta-0.1.0a1.tar.gz
Algorithm Hash digest
SHA256 415bf109e71a7552134cb5a1b09207217489c2dd1dd8f20cb47666f0b7aada10
MD5 98375bf220c4c476098914ce705e4db4
BLAKE2b-256 4fee771d5c9e72c47cf81942a0223a2cf7cbdd6f3956bffaa5f3b2e06dfddab6

See more details on using hashes here.

Provenance

The following attestation bundles were made for phionyx_letta-0.1.0a1.tar.gz:

Publisher: release.yml on halvrenofviryel/phionyx-letta

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file phionyx_letta-0.1.0a1-py3-none-any.whl.

File metadata

  • Download URL: phionyx_letta-0.1.0a1-py3-none-any.whl
  • Upload date:
  • Size: 23.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for phionyx_letta-0.1.0a1-py3-none-any.whl
Algorithm Hash digest
SHA256 caf18f702d40d71645a843293bb15924d77feb59a0555a53ff0a3777849ff1d8
MD5 9accd3bb25e964dbd6fa3e3ddf15facc
BLAKE2b-256 4faf2aecb684a68425016d5ddd3429d0208485220386cb94be2ea30602e2fb5d

See more details on using hashes here.

Provenance

The following attestation bundles were made for phionyx_letta-0.1.0a1-py3-none-any.whl:

Publisher: release.yml on halvrenofviryel/phionyx-letta

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page