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
useris required.Memory(...)takesuseras a keyword-only argument, and everypdm-clicommand 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 liveP_effectiveis below the threshold are marked deleted instead of erased. They disappear fromrecall,listandget, but the rows stay in the store. The returned counts are unchanged.- Default
sourceismanual, notchat.azus_chatis reserved for real Companion chat provenance; unknown legacy labels map tomanual. - Default cloud URL is production (
https://api.azus.ai), no longer localhost. Passcloud_url=...to point elsewhere.
🗂️ Evidence Layer — EventLog
Memories can now be traced to the events that produced them, and that trail is append-only.
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,aboutand a reversiblemergecover 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. Passllm_clientto compress it; without one the text is stored verbatim. Idempotent unlessforce=True. Also available onCloudDriver.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.
EventSynccarries 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.syncalso 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=...)(directedorsymmetric),end_link, andrelated. - Evidence on links:
EventLog.reinforceandEventLog.apply_contrary_evidencedispatch to a relationship's channel when given a relationship record, and to the memory methods otherwise. Resubmitting the same evidence is refused withCloudConflictError. - 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,relatedandfile_fact. It has no roster route (members_of), keeps no event table (the listing and identity methods raise aRuntimeErrorthat says so), and answersfields_ofand 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 (westfieldcoverswestfield/dqs).- Every item declares its provenance as
measuredorprojected; 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 returngrant_changed,projection_recordedandoutcome_recordedsteps.current_state,state_at,relationship_state,current_resolutionand 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 taggedprojected.record=Truepersists 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 judgementcorrect,partialorincorrect. The server derives timing itself. A projection settles once (a second outcome raisesCloudConflictError); one observed before it was made raisesCloudStorageErrorwith 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 asrecallandexplain.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_shapeandpersist_evidencecontrol 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_effectiveto 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
tagsper memory and raisesValueErrorbefore any request is sent. A local store accepts fewer. mem.delete(id)soft-deletes; cloud list and get hide those rows.EventLog.ingestis idempotent on a cloud store: repeating an ingest reuses the event and no longer refiles a fact that is already in the field.extract_signatureswaits up to 60 seconds, since the server builds the signature while the request is open.- GeoPass:
grantneeds a signature you own as itstarget, andviewanswers onnone<conclusion<fullfor signatures; a level the target does not have resolves tonone.
📦 Installation
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."
Built by Westfield Innovations LLC · azus.ai