
Attestari
io.github.attestari由 GitHub 帳號 attestari 發布v0.0.8更新於 Oct 24, 2026
Auditable memory for AI agents: provable deletion, tamper-evident audit, time-travel recall.
發布方自己的服務:Attestari
概覽
為 AI 代理提供可稽核的長期記憶:儲存帶來源的事實,支援依歷史時點回溯、防竄改稽核與可證明的刪除。
- 可以做什麼
- 為某個主體新增記憶,自動擷取、去重並讓新事實取代舊事實
- 依主體檢索並回答問題,可指定過去某個日期作為查詢時點
- 把某條事實追溯回其來源訊息與字元區間
- 檢視主體的完整雙時態時間軸與已揭露的衝突
- 驗證雜湊鏈稽核紀錄,並在啟用時抹除主體資料並出具簽章的刪除憑證
- 適用情境
- 適合需要長期記住人物或實體資訊,且必須說明每條事實的來源、還原某個歷史時點的真實情況,或能證明使用者資料已被刪除的情境。較偏向受監管或自架部署,而非單純的筆記儲存。
- 執行需求
- 以 stdio 在本機執行,通常由 MCP 用戶端透過 uvx 從 PyPI 套件啟動,或使用已安裝的指令。預設不需任何設定,記憶存放在本機 SQLite 檔案中。選用環境變數:ATTESTARI_SQLITE_PATH 指定檔案位置,ATTESTARI_DATABASE_URL 改用搭配 pgvector 的 Postgres,ANTHROPIC_API_KEY 啟用 Claude 事實擷取,ATTESTARI_KEK 啟用靜態加密,ATTESTARI_MCP_ALLOW_FORGET 開放抹除工具。
安裝
在 SourceWeft 中
- 開啟 儀表板中的 Attestari,將其新增到工作區。
- 為需要使用其工具的對話啟用該服務。
Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。
其他 MCP 客戶端
參照 儲存庫 中的啟動說明。
README
Attestari
The auditable memory layer for AI agents. Give your agent long-term memory — like any memory layer — except every fact carries a receipt (where it came from, when), it runs on plain Postgres, the audit trail is tamper-evident, and any user's data can be provably deleted with a signed certificate.
[license] [python] [tests] [deps]
No database, no API key, no model download required to run that — the core engine has zero dependencies.
Contents
- Why it's different
- What you get
- Quickstart (30 seconds)
- The Python API
- Run it for real — Postgres · server + console · MCP · TypeScript
- REST API
- Configuration
- Provable deletion + tamper-evident audit, in one demo
- Already using Mem0 or Zep? Wrap it
- For auditors and DPOs
- How it works — and the Atlas, the engine on one illustrated page
- Project layout
- Docs & contributing
Why it's different
Hosted memory is a black box: you can't see where a "memory" came from, you can't cleanly delete one user's data, and you can't prove the history wasn't altered. For a bank, hospital, or insurer — and under GDPR / the EU AI Act — that's a dealbreaker. Attestari is the neutral, self-hostable layer that fixes exactly that.
The last two rows are the moat. Deletion you can prove: each user's data is
encrypted with their own key; forget() destroys the key, so the content is
unrecoverable — while an immutable log and a signed certificate remain as proof.
A history you can verify: every event is hash-linked, so verify_audit()
catches any edit, insert, or delete — and the proof survives deletion.
What you get
- Provenance on every fact — each memory traces back to the exact source message, with a character span, confidence, and timestamps.
- Bi-temporal time travel — query memory
as_ofany past instant; corrections supersede old facts without erasing them, so history is always reconstructable.as_offilters on valid time (when a fact was true). System time (when Attestari recorded it) is stored on every fact, but there's no query on it yet. - Provable deletion —
forget(subject_id)crypto-shreds a user's data and returns a signedDeletionCertificate; content backups and replicas are covered (key storage needs its own backup policy — see the threat model). - Tamper-evident audit — a hash-linked event chain;
verify_audit()detects any edit/insert/delete, and the proof survives crypto-shred. - Conflict resolution — single- vs multi-valued predicates; conflicts are
surfaced via
conflicts(), not silently dropped. - Entity resolution — merge "the same entity, many surface forms," reversibly.
Merges are recorded, but reads don't follow them yet:
search()andtimeline()still see each surface form separately. - Hybrid retrieval — semantic (pgvector) ⊕ keyword (full-text), with the bi-temporal filter built in.
- Runs anywhere — zero-dependency in-memory engine, or durable on one Postgres
- pgvector container. No graph database. Works across model vendors.
Quickstart (30 seconds)
You'll see facts change over time, a bi-temporal query answer differently "as of"
different dates, a provenance trace back to the source, and a forget() that
issues a certificate. No install, no API key, no database.
The Python API
One facade, Memory, covers the whole surface:
Run it for real
Three storage tiers, one engine — every guarantee (audit chain, crypto-shred, deep verification, time travel) holds on all three:
Durable with zero infrastructure (survives restarts; nothing to install or run):
Durable, on Postgres + pgvector (one container, no graph DB):
Already have a Postgres (managed or local)? The schema ships inside the pip package — no clone needed:
As a REST API + visual console:
As an MCP server (any agent — Claude, frameworks — can use it) — exposes
add_memory / search_memory / get_provenance over stdio, plus forget_subject
if you opt in (below).
Register it in your MCP client's config (e.g. Claude Desktop's
claude_desktop_config.json); the client launches the process for you:
Only command/args are required. Durable by default (memories go to the local
SQLite file, so they survive app restarts); the env block is where per-server
config lives — add ATTESTARI_DATABASE_URL to use Postgres instead of SQLite,
ANTHROPIC_API_KEY to upgrade extraction to Claude, ATTESTARI_KEK to enable
crypto-shred. To run it standalone (e.g. to debug): attestari-mcp (or
python -m attestari.mcp). Without a local install, MCP clients can spawn it
straight from PyPI: uvx --from "attestari[server]" attestari-mcp.
Erasure over MCP is opt-in. An agent can be steered by text it reads, and
erasure can't be undone, so forget_subject is only offered when the env
block sets "ATTESTARI_MCP_ALLOW_FORGET": "1". It is then flagged destructive
(clients that honour tool annotations ask before running it) and takes two
calls: the first previews what would be erased and returns a manifest_hash;
the second passes that hash back as confirm_manifest_hash, and erases only if
the subject's records still match the preview. Leave it off unless the agent is
meant to erase people; Memory.forget() and POST /v1/forget are unaffected.
From TypeScript — the TS client talks to the REST API, so start the server
first (see above; it defaults to http://localhost:8000). Then see
clients/ts (@attestari/client), a thin typed client mirroring the
Memory surface.
With LangChain: see clients/langchain (attestari-langchain)
— a AttestariRetriever (recall facts with provenance) and AttestariChatMessageHistory
(drop-in memory for RunnableWithMessageHistory) for any chain or agent.
With real Claude extraction (instead of the zero-dep deterministic extractor):
Enable crypto-shred deletion (turn forget() from a logical delete into
cryptographic erasure). Encryption is opt-in via a root key-encryption key
(KEK); with none set, forget() still works but only drops the data from reads.
Mint a KEK once and set it in the environment:
Now each subject's PII is encrypted at rest under a per-subject key, and
forget() destroys that key — the ciphertext is unrecoverable, while the audit
proof survives. With the KEK set, the DeletionCertificate is also signed
(HMAC-SHA256 under a KEK-derived key); anyone holding the KEK can verify it
offline — verify_certificate(cert, kek) — and a certificate with any altered
field fails. Without a KEK, forget() is a logical delete and the certificate
is issued unsigned. Keep the KEK out of the database and its backups (env
var or a KMS) — storing it next to the data defeats the shred. See the backup
boundary in docs/the-moat.md.
What forget() covers, and what it leaves: it erases the episodes recorded under
that subject_id and the facts extracted from them. A fact about the person that
was extracted from someone else's message lives in that other subject's scope and
survives. Encryption covers message text and fact values only; each event's
other fields stay readable after an erasure — subject_id, a fact's subject and
predicate (with Claude extraction the subject can be a person's name), scope ids,
timestamps, character spans (which reveal a value's length) and source_ref. So
use opaque, pseudonymous subject_ids and keep personal data out of source_ref.
An erased subject_id stays closed: add() for it raises ForgottenSubjectError
and stores nothing (POST /v1/add returns 409, and the MCP tool refuses), so
record someone who comes back under a new id.
Postgres keeps a register of certificates; Memory() and Memory.local() hand
the certificate back once from forget(), so store it yourself there.
Deploying for real. A production checklist:
- Storage: use
Memory.postgres()(concurrent access); apply the schema withpython -m attestari.initdb "$ATTESTARI_DATABASE_URL", and run it again after every upgrade (it's idempotent; until then, writes stop with that instruction and reads keep working).Memory.local()(SQLite) is single-process — great for one agent or an MCP server, not a shared service. - Server: run under a process manager, e.g.
uvicorn attestari.server:app --host 0.0.0.0 --port 8000 --workers 4behind a reverse proxy; put your own auth in front (the API ships without auth). - Writes for one subject: on 0.0.7 and earlier, serialise them in your app.
Two
add()calls for the same subject at the same moment can each supersede the same old value, leaving two live values for a single-valued predicate. Later releases decide supersession under the store's write lock, so concurrent writes are safe. - Writes after an erasure: on 0.0.7 and earlier, check
is_forgotten(subject_id)beforeadd(). With a KEK set, a write for a forgotten subject makes every later read of the log fail withInvalidTag, for every subject. To recover, delete that subject's row from thekeyringtable. Later releases refuse the write instead. - Extraction & embeddings: set
ANTHROPIC_API_KEY(extraction auto-upgrades to Claude) and install[embeddings]for real semantic vectors. - Keys: inject
ATTESTARI_KEKfrom a KMS/secrets manager as an env var — never bake it into an image or the DB. Back thekeyringtable up on a separate, short-retention policy (or rotate the KEK) so a restored data backup can't resurrect a shredded subject — see docs/the-moat.md. - Backups: exclude the derived projection tables (
edge,entity) as well — they hold plaintext fact text for retrieval and are fully rebuildable from the (ciphertext) event log, so backing them up only weakens the shred. After a restore without them, the first connection rebuilds them. - Secrets: nothing is read from a
.envfile automatically — export the vars (or use your orchestrator's secret injection) before starting the process.
REST API
uvicorn attestari.server:app serves:
Configuration
Environment variables (all optional — the engine runs with none of them):
Install extras (pip install -e ".[extra]"):
Provable deletion + tamper-evident audit, in one demo
Don't trust the bullet points — break the properties and watch them get caught.
This runs with no database, no API key, no model download, and is self-verifying
(every claim ends in an assert; it crashes if any property is false):
It adversarially proves all three differentiators: a silently rewritten fact is
caught at the exact seq by verify_audit(deep=True); a crypto-shredded
subject's ciphertext is provably unrecoverable while the audit proof survives;
and a corrected fact is queryable in the past without erasing history. (Runs on a
bare clone; pip install "attestari[crypto]" upgrades claim 2 from logical erasure to
cryptographic crypto-shred.) See
docs/the-moat.md for the threat model and honest boundaries.
For the full crypto-shred against a real encrypted Postgres row:
It shows: a fact traced to its source, a subject forgotten, the raw row confirmed to be unreadable ciphertext, recall returning nothing — and the audit chain still valid after the erasure.
Already using Mem0 or Zep? Wrap it
You don't have to replace your memory layer to get an audit trail. wrap() puts
Attestari in front of the client you already use:
Not on Python? Point your app at the Attestari server instead of at your memory service and get the same guarantees over REST:
A partial erasure returns 409, not 200 — a caller checking only the status
code must never read a half-completed deletion as success. The routes appear
only when an upstream is configured. See attestari.wrap_http for the small
JSON contract the upstream is expected to speak (stdlib-only, no new deps).
It doesn't take the delete call's word for it. After deleting, forget()
reads the subject back out of the wrapped store. A store that returns
{"deleted": true} and keeps the rows is caught right there —
downstream_verified is False, complete is False, and the discrepancy
goes into the audit chain. If the adapter has no read-back operation,
downstream_verified is None rather than True: "nobody checked" and
"checked and clean" are different claims, and only one of them is evidence.
Writes are recorded in the tamper-evident chain before being passed downstream;
reads pass through untouched (retrieval is why you kept your store); forget()
deletes downstream, crypto-shreds Attestari's copy, and records what the
downstream store actually did — including failure. Method names and the subject
keyword are configurable via Adapter, so this works against a bare vector
store too.
What wrapping does and doesn't prove. Attestari can't cryptographically shred data inside someone else's service — it doesn't hold their keys. A wrapped deployment proves the deletion was requested, that the downstream delete was called and what it returned, that Attestari's own copy is unrecoverable, and that none of that was altered afterwards. That's an auditable deletion record across both systems, not crypto-shred everywhere: a wrapped store is only as erasable as its own delete endpoint is honest, and wrapping turns that endpoint's behaviour into evidence instead of a promise. For full cryptographic erasure, the data has to live in Attestari itself.
For auditors and DPOs
The people who have to answer for an AI system's memory get their own docs in auditor/ — a plain-language one-pager (what's guaranteed, what isn't, how to check it yourself), an EU AI Act Art. 12 mapping, and a GDPR Art. 17 note on cryptographic erasure and the deployment policies it depends on.
Any deployment can produce a dated snapshot of its own verifiable state:
The bundle carries the audit-chain result and head hash, an erasure register with every request re-checked against the current ledger, and the retained deletion certificates. Every claim is re-derived from the live ledger when the bundle is generated — it's evidence because you can regenerate it, with read access and no cooperation from whoever runs the system.
How it works
The source of truth is an append-only event log; everything you query (the knowledge graph, the vector index, the keyword index) is a projection you can rebuild from it. That's why audit, time-travel, provenance, and provable deletion fall out of the design instead of being bolted on.
- The Attestari Atlas — the whole engine on one illustrated page: every write, read and erase, the audit chain you can tamper with in the browser, where it fits, and its sharp edges. Written for 0.0.7.
- ARCHITECTURE.md — the design, end to end.
- LEARN.md — the same ideas explained from scratch, for newcomers.
Project layout
Docs & contributing
- ARCHITECTURE.md — the design
- auditor/ — for DPOs, compliance, and internal audit
- LEARN.md — how Attestari works, from scratch
- CONTRIBUTING.md — dev setup, good first issues
- SECURITY.md — reporting vulnerabilities
Status
The engine and its differentiators — verifiable deletion, tamper-evident audit, bi-temporal provenance, Postgres-native retrieval — are built and tested (122 tests; Postgres p95 ≈ 1 ms).
License
Apache-2.0. The core stays permissively licensed; the hosted cloud and enterprise/governance features are the commercial layer.
來源:README.md,提交 4bb79df
工具
0版本歷史
3- v0.0.8最新Oct 9, 2026
- v0.0.7Oct 9, 2026
- v0.0.6Sep 16, 2026
評分
已滿足適用檢查項的 50%
該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。
- 近 30 天內可連通25 分
請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。
- 已宣告認證方式10 分
請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。
- 已列出工具15 分
請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。
- 描述必需15 分
- 圖示10 分
- 文件15 分
- 授權條款10 分