PersonaTrace
A memory layer for what is still true, what is due, and why it was stored.
PersonaTrace is not a chatbot or an agent harness. It is a small memory kernel that a host can call. The host owns the model, the prompt, the UI, the tone, and any proactive behavior.
The unit of memory is not a fact. It is a fact that holds for a while: it has a validity window, a retention curve, evidence, and optionally a due date. A separate intention store handles one-off commitments whose lifetime is measured in hours or days, not in months.
What it remembers
| Type | Examples | Lifetime |
|---|---|---|
| Belief | preferences, identity, constraints, projects, goals, habits | retention curve per category; archived, not deleted |
| Intention | "class the day after tomorrow", "submit the report Friday" | due + grace; done / cancelled / expired |
| Evidence | the sentence a belief came from | kept with the belief; read only after a hit |
| Mention | "someone said he is preparing for an exam" | separate from first-hand beliefs; decays faster |
The merged path uses 17 belief categories across two tracks:
work: explicit_facts expertise projects goals likes dislikes constraints
persona: identity traits interests style_notes behavior_patterns
decision_style interpersonal boundaries habit state
How retrieval works
query
├─ pinned: boundaries / constraints / identity
├─ semantic: lexical IDF + vector cosine (candidate-set normalized)
├─ time facet: due/range rows, only for time-intent questions
├─ cross-category: items from categories not already selected
└─ evidence on demand: reasoning + original sentence for the first hits
score = (0.15 + 0.85 * similarity) * (0.35 + 0.65 * retention)
A time question is not answered by a better embedding. It is answered by putting the date into a typed field and querying that field. The facet is a conditional bypass, not a second retriever.
Install
pip install personatrace
# optional embedding / LLM / API layers
pip install "personatrace[llm,vector]"
Until 1.5.0 is available on PyPI, install the merged API from source:
pip install "git+https://github.com/Stellfract-Frost/PersonaTrace.git"
Python 3.10+. The core belief kernel uses the standard library. The merged
facade uses Pydantic; the default local store is SQLite. Redis is optional.
## Quick start: structured memory
The host extracts beliefs/intentions; PersonaTrace stores, ranks and expires
them. This path does not call an LLM.
```python
from personatrace import MergedMemory
memory = MergedMemory(
user_id="alice",
sqlite_path="./personatrace.db", # beliefs + intentions in one file
)
memory.write(
beliefs=[{
"category": "identity",
"label": "名字叫小陌",
"confidence": 0.9,
"reasoning": "user introduced themselves",
}],
intentions=[{
"action": "上课",
"due": "后天",
"importance": 0.9,
"confidence": 0.8,
}],
source="direct",
)
context = memory.build_context("我那个 deadline 是几号")
print(context.agenda_lines)
print(memory.inject("我那个 deadline 是几号"))
build_context()returns structured data and has no side effects.inject()is an optional prompt adapter; the host can render the pack itself.sourcemust be one ofdirect / bridge / console; proactive turns must not write user facts.
MCP
The server exposes eight tools. The merged tools use SQLite by default, so no Redis or server setup is required.
{
"mcpServers": {
"personatrace": { "command": "personatrace-mcp" }
}
}
| Tool | Purpose |
|---|---|
memory_state |
current or historical beliefs |
memory_recall |
pinned + ranked beliefs, with hidden count |
memory_observe |
write one evidence-backed belief |
memory_correct |
invalidate a belief without deleting history |
memory_predict |
next action from the behavior sequence |
memory_remember |
write already-extracted beliefs / intentions |
memory_context |
structured pinned/dated/related/cross/agenda pack |
memory_agenda |
read-only short-term agenda |
Every call has an 8s timeout and returns an error result instead of raising. A failing memory must never take the host's conversation down.
See MCP.md.
Evaluation
A 12-belief, 10-query fixture is included. It is a directional gate, not a benchmark.
method recall@3 MRR
v2 native (no pinned) 35.0% 0.333
v2 native (pinned) 23.3% 0.283
v1 string 53.3% 0.583
v1 + bge 76.7% 0.833
outer + bge 76.7% 0.833
outer + bge + time facet 90.0% 0.933
The useful comparison is outer + bge → + time facet: the gain comes from
typed time, not from a stronger embedding.
python scripts/eval_recall.py
python scripts/eval_recall.py --no-embed
Design notes
The full failure analysis, measurements, tradeoffs and pitfalls are in DESIGN_NOTES.md. The temporal kernel is described in MEMORY_V2.md.
What is shipped
| Area | Status |
|---|---|
| v2 kernel: retention, bi-temporal state, evidence, CAS guard | shipped |
| SQLite persistence by default | shipped |
| 17-category belief contract + Chinese typed time | shipped |
| outer retrieval + time facet + cross-category | shipped |
| short-term intentions with importance / TTL / anti-nag | shipped |
MergedMemory facade + MCP tools |
shipped (M2) |
| v1 → v2 migration script | shipped; dry-run by default |
| graph memory | experimental, not wired into default retrieval |
PersonaManager default path switched to merged |
not yet (M3) |
Known limits:
- single user; no multi-tenant or auth;
- no UI, persona, or proactive messaging;
- label-keyed beliefs still create a second record for a paraphrase;
- the evaluation set is small;
PersonaManagerremains the legacy v1 pipeline; useMergedMemoryor MCP for the merged path.
License
MIT
Metadata
Release files for personatrace 1.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| personatrace-1.5.0.tar.gz | 94.5 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| personatrace-1.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 197.2 kB
Release files / personatrace-1.5.0.tar.gz
| Download URL | personatrace-1.5.0.tar.gz |
|---|---|
| Size | 94.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
72aa7e1927e7087ce8d3b0f2393f5c938aa13c56400e70dfd325f717128c6bae
|
|
BLAKE2b-256 checksum How to use checksums |
6ae89cb9cb11625bdb424ebfe45f2473bc400c371eb29f1a03d1b69053b37c4a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.9
|
Release files / personatrace-1.5.0-py3-none-any.whl
| Download URL | personatrace-1.5.0-py3-none-any.whl |
|---|---|
| Size | 102.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9753ce75814549accc30801b2e50fbc704dd83ef9ef71c0fe9ee75ace77effd6
|
|
BLAKE2b-256 checksum How to use checksums |
d37eb4895aefa30bd83c32620e9fae2dda8e0a08c13059aff99d3172aa6153fd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.9
|
Security for personatrace 1.5.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.