← Back to App

Changelog

Changelog

What's new in the PDM SDK — always up to date.

Date: 2026-10-07 Theme: Memory learns where its facts came from, who they belong to, and how that changes over time

Version 0.2.5 is the largest release since 0.2.0. Memory stays recognisable, but around it the SDK gains an append-only evidence layer (EventLog), field memberships and relationships, cloud-side field state and projections, a GeoPass client, shape-aware decay, and an OpenClaw plugin that puts the integrity gate in front of an agent's tools.

Two changes need your attention before upgrading: user is now mandatory, and decay() now soft-deletes. See Breaking changes.


⚠️ Breaking changes

  • user is required. Memory(...) takes user as a keyword-only argument, and every pdm-cli command that opens a store needs --user. Against a cloud store it must be the username the token belongs to: the server takes the owner from the token and refuses a payload naming anyone else. The CLI exits with an error rather than guessing.
  • decay() soft-deletes. Memories whose live P_effective is below the threshold are marked deleted instead of erased. They disappear from recall, list and get, but the rows stay in the store. The returned counts are unchanged.
  • Default source is manual, not chat. azus_chat is reserved for real Companion chat provenance; unknown legacy labels map to manual.
  • Default cloud URL is production (https://api.azus.ai), no longer localhost. Pass cloud_url=... to point elsewhere.

🗂️ Evidence Layer — EventLog

Memories can now be traced to the events that produced them, and that trail is append-only.

python
1from pdm_memory import Memory
2from pdm_memory.event_log import EventLog
3from pdm_memory.storage.eventful_sqlite import EventfulSQLiteDriver
4
5mem = Memory(storage=EventfulSQLiteDriver(db_path="./app.db"), user="alice")
6log = EventLog(mem)
7
8ids = log.ingest(
9    event=log.event("chat_message", raw_reference="chat:123:msg:456"),
10    payload="Moved the Orion release review to Friday. Alex is on it.",
11    facts=[
12        {"text": "Orion release moved to Friday", "tags": ["orion", "release", "date"]},
13        {"text": "Alex owns the Orion release", "tags": ["orion", "alex", "owner"], "about": "Alex"},
14    ],
15    field_id="work",
16)

One call records one event, its signatures, a mention for each name, and the identity that name resolves to.

  • Idempotent ingest. Re-ingesting the same payload reuses the event (deduplicated on its content hash) and re-records nothing.
  • Mentions are evidence, identities are decisions. mention, confirm, pending, entities, entity, about and a reversible merge cover the path from "a name was written" to "this is that person".
  • extract_signatures(event_id, text) turns an event's own text into a signature. The text is checked against the event's content hash first, so a signature cannot be attributed to an event it was not part of. Pass llm_client to compress it; without one the text is stored verbatim. Idempotent unless force=True. Also available on CloudDriver.
  • check_integrity() reports references that lead nowhere. It reads only and repairs nothing.
  • SQLite and PostgreSQL share one implementation, differing only where the dialects differ. PostgreSQL is now exercised against a real server in CI.
  • EventSync carries the evidence layer between two stores in dependency order (events, then entities, then mentions) and translates ids on the way, since each side keeps its own keys. sync also carries signature provenance across.
  • ISO-8601 timestamps are parsed by the SDK itself, so the accepted grammar no longer changes with the Python runtime.

🧩 Fields & Relationships

Who belongs where, and when.

  • Memberships and filings: add_field_membership, end_membership, file_fact, unfile_fact, fact_fields, fields_of, members_of. Settling time is recorded for memberships, links and filings.
  • Relationships: link(source, target, relationship_type, directionality=...) (directed or symmetric), end_link, and related.
  • Evidence on links: EventLog.reinforce and EventLog.apply_contrary_evidence dispatch to a relationship's channel when given a relationship record, and to the memory methods otherwise. Resubmitting the same evidence is refused with CloudConflictError.
  • Recall respects fields. Facts filed in a field are scoped by that field rather than by their subject.
  • Memberships, filings and the full evidence layer (mention, confirm, entities, about, merge, check_integrity, members_of) run on the evidence-layer SQLite and PostgreSQL drivers.
  • A cloud store supports ingest, extract_signatures, link, end_link, related and file_fact. It has no roster route (members_of), keeps no event table (the listing and identity methods raise a RuntimeError that says so), and answers fields_of and memberships only for your own subject key.

🌐 Field State & Relationship State (cloud)

  • current_state(field_id) / state_at(field_id, moment): the reconciled state of a bounded field: memberships with the intervals they held, relationships, and the entities this observer may reveal, one keyset page at a time. Nested fields match by prefix (westfield covers westfield/dqs).
  • Every item declares its provenance as measured or projected; an untagged item is rejected rather than guessed at. Results are filtered to what the observer may reveal, and there is no unfiltered mode.
  • relationship_state(source, target, at_time=None, domain=None): which links were live, which channel measurements applied, and, only within the channel's own recency window, the current resolution vector.
  • current_resolution(observer, target, domain): the multidomain channel vector. There is deliberately no single flat score.
  • trajectory(subject_id, start, end): the ordered transitions of a field or entity over [start, end). It works on a local evidence-layer store too; only a cloud store can return grant_changed, projection_recorded and outcome_recorded steps.
  • current_state, state_at, relationship_state, current_resolution and projections are cloud only and raise in privacy mode instead of inventing a second data model.

🔮 Projections (cloud)

  • project(horizon_days=None, record=False): a forward fan of branches per domain (holds, drifted, unobservable), each with a confidence band, a timing range and the conditions that would invalidate it, all tagged projected. record=True persists the fan.
  • projection(projection_id) reads one recorded branch with its outcome.
  • record_outcome(projection_id, observed_at, connection_geometry, meaning_propagation, model_update="") settles a recorded projection, with each judgement correct, partial or incorrect. The server derives timing itself. A projection settles once (a second outcome raises CloudConflictError); one observed before it was made raises CloudStorageError with status 422; someone else's projection reads as not found.

🪪 GeoPass Client

from pdm_memory.geopass import GeoPass wraps the Companion GeoPass facade for a cloud Memory: belongs, can, view, grant, revoke, audit and transition. belongs(field_id, at=..., known_at=...) can answer from what was recorded by a given time, so an end backdated past at but recorded later does not apply. GeoPass answers whether an observer belongs to a field and may act in it; it is distinct from GAA's verify(), which scores a proposed action against rules.

⏳ Shape-Aware Decay & Contrary Evidence

  • Memory shapes: shape="ephemeral" | "behavioral" | "structural" at save time sets the half-life to 2 hours, 90 days, or no decay. A shape overrides the domain half-life.
  • decay_at(id): a read-only live snapshot of one memory's decay metrics, using the same law as recall and explain.
  • apply_contrary_evidence(target, evidence): lowers pressure and validation on a conflicting fact at once, without rewriting its fact or creation time, and by default stores the evidence linked to the target (evidence_tags, evidence_shape and persist_evidence control that). It stores the evidence first: if the store refuses it, for example a cloud store given fewer than 3 tags, the target is left untouched instead of being penalised and then failing.
  • Ephemeral decay and contrary evidence no longer cause live P_effective to rebound.

🛡️ OpenClaw Plugin

plugins/openclaw runs verify() at OpenClaw's before_tool_call hook, scoring every proposed action against plain-English rules before it executes. Rules live in ~/.openclaw/pdm-guard-rules.json, nothing needs a PDM store, and every gate decision writes a short JSON receipt to the gateway log. The plugin calls Python directly rather than going through an HTTP sidecar. Intent extraction and receipts were hardened in this release. Tested against OpenClaw 2026.7.1-2.

☁️ Cloud Notes

  • A cloud store requires at least 3 tags per memory and raises ValueError before any request is sent. A local store accepts fewer.
  • mem.delete(id) soft-deletes; cloud list and get hide those rows.
  • EventLog.ingest is idempotent on a cloud store: repeating an ingest reuses the event and no longer refiles a fact that is already in the field.
  • extract_signatures waits up to 60 seconds, since the server builds the signature while the request is open.
  • GeoPass: grant needs a signature you own as its target, and view answers on none < conclusion < full for signatures; a level the target does not have resolves to none.

📦 Installation

bash
1# Core package
2pip install pdm-memory==0.2.5
3
4# With full UI and all adapters
5pip install "pdm-memory[all]==0.2.5"

Upgrading from 0.2.4: add user=... to every Memory(...) call and --user to CLI commands.


🛠️ Developer Support & Feedback

We operate on a Closed Loop principle. Your feedback directly shapes the next "tick" of the Westfield OS evolution.

🆘 Getting Help

Visit our primary support hub: 👉 azus.ai/support

🐛 Reporting Bugs & Torsion

Since our core repository is currently private to protect our IP, please report bugs, logical inconsistencies (Torsion), or security leaks through the following channels:

1. Support Portal: Log a ticket at azus.ai/support.

2. Direct Signal: For high-stakes architectural flaws, reach out to the team on X (@ExodusBecause) or via our developer Discord.

3. Audit Logs: When reporting a bug, please include report.render(), pdm-cli verify --json, or mem.explain(id) to help us localize the "leak."

💡 Feature Requests

Have an idea for a new adapter, a Middleware Hook, or a gate that should fire earlier? We prioritize features based on community "Pressure." Submit your proposals on the support page or flag them in your daily operation logs if you are an enterprise partner.


📜 Version History & Changelog

We maintain a rolling log of the last 10 versions to ensure transparency in our "Window Advance."

VersionStatusKey Highlight
v0.2.5LatestEvidence layer, fields and relationships, field state, projections, GeoPass, shape-aware decay, mandatory user.
v0.2.4StableStandalone verify(), hard constraints, cloud batch, torsion auto-discovery.
v0.2.3StableHook system, temporal anchoring, and diversity bias.
v0.2.0StableIndustrial hardening, PostgreSQL support, and idempotency.
v0.1.9LegacyInteractive Explorer console and torsion resolution.

Built by Westfield Innovations LLC · azus.ai