PMB
Memory server
First committed by oleksiijko
Published in oleksiijko/pmb. Publisher page
285 GitHub stars
What it is
Local-first persistent memory for AI coding agents (Claude Code, Cursor, Codex) over MCP. Decisions, lessons and facts live in one SQLite file on your disk. Offline, multilingual.
AutoGineer overview, from the brain’s own files
PMB provides persistent memory for MCP-aware AI coding agents like Claude Code, Cursor, and Codex. By using a local SQLite database as the source of truth, it captures decisions, lessons, and project facts, allowing agents to retain context across sessions without relying on cloud storage or external API keys. The system uses a hybrid approach combining lexical search, vector embeddings, and entity graphs to surface relevant information to the agent. It includes tools for indexing project structures, tracking commit intent, and managing memory through a dashboard, ensuring that agents can access historical context automatically.
How it works
Memory model: Hybrid
AutoGineer overview, from the brain’s own files
PMB operates as an MCP server that connects to your AI agent. It uses a hybrid memory model where durable events are stored in a local SQLite database, while search indexes are maintained in LanceDB. When an agent interacts with the system, PMB uses a combination of BM25 lexical search, vector embeddings, and entity graph analysis to retrieve relevant information. The system includes hooks that automatically observe agent activity and inject context into the agent's workflow, while also allowing for manual indexing of files, PDFs, and project data.
| Folder | Role | Files |
|---|---|---|
| .claude | agent-config | 1 |
| .github | agent-config | 10 |
| docs | docs | 41 |
| scripts | scripts | 47 |
| src | source-code | 173 |
| tests | tests | 199 |
| docker | folder | 4 |
| mintlify | folder | 34 |
| npm | folder | 5 |
Requirements
Runtimes: Python >=3.11
Databases: LanceDB, SQLite
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Google Antigravity, Kiro, OpenCode, Amp, Roo Code, Cline, JetBrains Junie, Devin (ex-Windsurf)
Set it up
This brain runs code automatically: 1 script. Review Makefile before opening the folder in Claude Code. No step below turns a hook on for you.
Makefile:pip install -e .
- Not scanned by AutoGineerThe author’s README also describes installing it from a clone of its repository. Read its install section: AutoGineer did not scan that path. https://github.com/oleksiijko/pmb/blob/d0e2f2e287acb10e7c7fb794941a76533ade52d6/README.md#install
- Not scanned by AutoGineerAutoGineer could not scan everything it runs. https://pypi.org/project/pmb-ai/
First committed by oleksiijko. Published in oleksiijko/pmb. Licence: Apache License 2.0.
Usage
AutoGineer overview, from the brain’s own files
- Install the PMB package via pip or npm.
- Run the setup command to configure your agent and wire the MCP connection.
- Use the CLI to index project files, track changes, or import existing data.
- Interact with your AI agent as usual, allowing PMB to automatically inject relevant memory and record new events.
- “pmb recall "auth decision"”
- The system searches the local SQLite memory and returns stored information regarding past authentication decisions.
- “pmb index project .”
- The system scans the current directory to index the project structure and symbols into the memory store.
Documentation by oleksiijko
<!-- mcp-name: io.github.oleksiijko/pmb-ai -->
<div align="center">
<img src="https://raw.githubusercontent.com/oleksiijko/pmb/main/docs/assets/logo.png" width="100" alt="PMB logo">
PMB
Local-first memory for your AI coding agent.
SQLite is the source of truth. No cloud, no API keys, no re-explaining.
Image: Website Image: PyPI Image: CI Image: Docs Image: Python Image: License Image: MCP Image: GitHub MCP Registry
<img src="https://raw.githubusercontent.com/oleksiijko/pmb/main/docs/assets/dashboard-map.png" width="760" alt="PMB dashboard - your project's memory as a live entity graph">
Local-first memory, visualized. 3,800+ entities and 41,000+ connections, captured automatically as you work.
Website · Docs · Quickstart · Demo · Why PMB · How it works · FAQ
Your AI agent forgets everything between sessions. So you re-explain the same decisions, lessons and constraints over and over. PMB remembers them in one local workspace and feeds them back through MCP - no cloud, no API keys, no LLM call on the read path. And it tells you when memory is actually helping, instead of claiming "+X%".
⭐ Star the repo if PMB saves you a re-explanation.
</div>
PMB gives Claude Code, Cursor, Codex and the other MCP-aware agents a real memory: decisions you made last week, lessons you taught them, personal facts, project structure, PDFs. They survive every restart, every model upgrade, every agent switch - because they live in a local workspace you own, with SQLite as the durable source of truth and rebuildable search indexes beside it.
No API keys. No subscription. No LLM call on the read path. Just local files.
Quickstart
pip install pmb-ai # 1. install
pmb setup # 2. detect your agent + wire the MCP entry
pmb warmup # 3. preload the model (first recall is instant)
# 4. restart your agent, then just talk to it - memory is automatic
pmb stats # 5. see what's stored
pmb recall "auth decision" # 6. search memory from the terminal
pmb doctor # 7. confirm everything is wiredThat's it - your agent now remembers. No account, no keys, nothing leaves your machine.
Command name: the CLI is
pmb. Viapipyou also get the aliaspmb-ai; vianpm(npx pmb-ai setup) the command ispmb-aiand it installs the Python package first, then runs setup. Same tool - use whichever your install gave you.
Links: pmbai.dev (site) · docs.pmbai.dev (docs) · Getting started · Deleting memories.
Demo
What it feels like - same prompt, with and without memory:
<div align="center">
<a href="https://github.com/oleksiijko/pmb/raw/main/docs/assets/pmb-setup.mp4"><img src="https://raw.githubusercontent.com/oleksiijko/pmb/main/docs/assets/pmb-setup-poster.png" width="820" alt="Watch the 2-minute PMB setup"></a>
<sub>▶ Click to play the 2-minute setup</sub>
<img src="https://raw.githubusercontent.com/oleksiijko/pmb/main/docs/assets/before-after.svg" width="880" alt="Same prompt, with and without memory: without PMB the agent asks which file and what the bug was; with PMB it recalls verdict-policy.ts:142 in 6 ms.">
</div>
You: fix that LoadGuard pricing bug we hit last Tuesday
Agent: prepare(message="fix LoadGuard pricing bug")
↓ (6 ms)
→ project_context: 12 events about LoadGuard,
4 lessons (incl. "never lower NEGOTIATE/SKIP under 25%"),
3 decisions, 2 open goals
→ active_arcs: "LoadGuard verdict-policy refactor (started Tue)"
→ lessons: 1 directly matches "pricing"
→ recent_activity: 8 commits this week
Looking at src/engine/verdict-policy.ts (you opened it Tuesday
14:32, last changed Wednesday). The pricing bug is on line 142
where the bundle fallback tightened below the rate-floor. Per the
lesson you saved, we never drop the threshold under 25% - restoring
the guard there.The agent didn't ask. It didn't guess. It read its memory in 6 ms and showed up already informed.
Why PMB
Local-first, zero-config. SQLite holds the durable memory; rebuildable search indexes stay local. No account, API keys, telemetry, or cloud to trust.
It actually gets used. On Claude Code / Codex, hooks inject the right memory before the model thinks - you never have to remember to call a tool.
Multilingual, no setup. The embedder covers 50+ languages; a Russian query finds an English fact. No per-language config.
MCP-native. One
pmb connectwires Claude Code, Cursor, Codex, Windsurf, Zed, VS Code, and more.Fast read path. Recall in ~35 ms warm; writes return in under a millisecond - no LLM call to remember.
Honest impact. The dashboard shows which lessons actually changed outcomes, instead of claiming "+X%".
Your data, in the open.
pmb exportdumps everything to Markdown/JSON. Apache 2.0.
See your memory
pmb dashboard opens a local, liquid-glass web UI on http://127.0.0.1:8765
over everything PMB captured - written automatically, just by working. It binds
to 127.0.0.1 only, so nothing leaves your machine.
<div align="center">
<img src="https://raw.githubusercontent.com/oleksiijko/pmb/main/docs/assets/dashboard-map.png" width="820" alt="PMB dashboard - Map (entity graph)">
Map - every entity and connection in your project, as a live graph.
<img src="https://raw.githubusercontent.com/oleksiijko/pmb/main/docs/assets/dashboard-timeline.png" width="820" alt="PMB dashboard - Timeline (journal)">
Timeline - your memory as a journal, newest first.
</div>
Nine tabs: Map (entity graph, live), Timeline (git-graph by project), Overview, Entities, Arcs (narrative threads), Lessons (per-rule follow-rate, dead-lesson detection), Duplicates (inline merge), Performance (per-tool latency), Recall (debug ranker).
Verified local backups
pmb snapshot create --note "before maintenance"
pmb snapshot list
pmb snapshot verify <snapshot-id>
# Stop PMB servers, agent connections, and dashboards before restoring.
pmb snapshot restore <snapshot-id>Snapshots use SQLite online backup to include committed WAL data and record
file checksums. Restore checks the snapshot before changing memory and saves
a verified copy of the previous state. Use pmb snapshot list --json in scripts.
See backup and recovery for scope and limitations.
What you can store
# Personal facts that change (time-travel: old values archived, never lost)
record_keyed_fact("user", "city", "Warsaw")
# Project structure - symbols, imports, .gitignore-aware
pmb index project .
# Why each file exists + the intent behind every commit (Haiku-summarised, local)
pmb track modules # one-line purpose per indexed file
pmb track changes # new commits: what changed and WHY
# PDFs (research papers, manuals, contracts)
pmb index pdf paper.pdf
pmb index pdf ~/docs --recurse
# Whatever your agent logs as it works: decisions, lessons, completed tasks, goalsPMB is content-agnostic. If it's text the agent will care about later, PMB remembers and retrieves it.
What the agent gets back
A single MCP call - prepare(message) - returns the right things at the right
level of detail, in 4-16 ms:
| Field | What it is |
|---|---|
project_context | Full project overview if the message mentions a project: key facts, lessons (RULES to follow), decisions, open goals, related entities, the project's narrative arc |
lessons | Procedural rules matching the query, each with a surface_id so the agent can confirm it followed the rule later |
recent_activity | Last 24 h of decisions / edits / completions for session continuity |
open_goals | In-progress goals so the agent knows what you're pursuing |
active_arcs | Narrative arcs the project is currently living in |
For everything else there's recall(query) (hybrid search, 35 ms warm) and 27
other tools in docs/reference/COMMANDS.md.
How it works
flowchart LR
A[Your agent] -->|MCP stdio| B[PMB MCP server]
B --> C[Engine]
C -->|read 35 ms| R[Hybrid recall<br/>BM25 + vector + graph + rerank]
C -->|write under 1 ms| W[Async embed queue<br/>SQLite first, vectors later]
R --> D[(SQLite)]
R --> E[(LanceDB)]
W --> D
W --> E
style A fill:#dbeafe,color:#1e3a8a
style B fill:#ede9fe,color:#5b21b6
style C fill:#dcfce7,color:#14532dStorage - every durable event lives in SQLite, the source of truth. Rebuildable vector indexes live in LanceDB beside it. The whole workspace stays on your disk and can be copied or exported anytime.
Recall - BM25 (lexical) + dense vector (semantic) + entity graph + optional cross-encoder rerank, fused via Reciprocal-Rank-Fusion.
Writes - async. The MCP tool returns in under a millisecond; the embed + LanceDB insert happen on a background thread.
Dedup - four layers: exact text match -> cosine >= 0.92 auto-merge -> cosine 0.80-0.92 borderline (LLM verify later) -> manual review in the dashboard. Old values are archived, never deleted; full history via
keyed_fact_as_of(t).Multilingual - no language packs. The default embedder (
paraphrase-multilingual-MiniLM-L12-v2) covers 50+ languages, so где я живу finds a keyed-fact stored as user.city = Warsaw. Intent detection rides English semantic anchors that transfer cross-lingually, and the cold lexical path self-compiles from your own traffic. Recall stays strong across ~11 languages (top-3 ~= 0.9 on a 101-query eval; top-1 = 1.00 for en/fr/pt/ru). See docs/contributing/adding-a-language.md.
Install
The Quickstart above is all most people need. Other ways:
# From source
git clone https://github.com/oleksiijko/pmb.git && cd pmb
python -m venv .venv && source .venv/bin/activate
pip install -e .
pmb warmup # prime the ~450 MB embedder onceWire one or more agents (all stdio - the server runs as a child of your agent; no network, no port, no token):
pmb connect claude-code # also: codex · cursor · windsurf · gemini · vscode · zed · opencode · continuePoint several agents at one memory:
pmb connect claude-code --workspace personal
pmb connect cursor --workspace personal # both read/write the same workspaceSharing one memory across machines or a team? That's an optional HTTP mode with bearer-token auth - see docs/guide/TEAM.md. Not needed for local use.
Running the tests? Use the venv's Python:
.venv/bin/python -m pytest(or.venv\Scripts\python.exe -m pyteston Windows). Barepytestoutside the venv just reports missingnumpy/fastmcp/typer.
CLI cheat sheet
# Memory
pmb stats show counts and storage info
pmb recall "query" search with full debug
pmb dashboard web UI on port 8765 (graph, settings, errors)
# Ingest
pmb index pdf paper.pdf extract + chunk + embed
pmb index pdf ~/docs --recurse entire directory
pmb index project . scan codebase
pmb track changes summarise commit intent (why)
pmb track modules one-line purpose per module
pmb import chatgpt ~/Downloads/export.json bring existing history
# Continuity & efficiency (opt-in)
pmb resume save write .pmb/resume.md (commit it)
pmb resume install refresh resume.md at every turn end
pmb health lessons-impact which lessons actually help outcomes
pmb memory ledger Memory Delta handles this session
# Maintenance
pmb regraph rebuild entity graph
pmb consolidate run sleep pass (optional)
pmb compact archive old events
pmb dedupe resolve borderline duplicates
# Hooks (force-feed PMB at the protocol level - no model cooperation)
pmb hooks install claude-code wire all lifecycle hooks
pmb hooks list show what's installed
pmb hooks capabilities ambient mechanism each agent supports
pmb hooks uninstall claude-code remove them
pmb auto-context "fix bug in PMB" preview per-turn injection
pmb session-restore -m 180 preview post-compaction restore
pmb lesson-followcheck --dry-run preview follow-through scoring
# Ambient memory (the write side - memory journals the agent's work)
pmb autowrite --dry-run preview ambient auto-write for this turn
pmb ambient-watch . ambient auto-write for MCP-only hosts (git observer)
pmb forget-auto drop memory the ambient layer wrote itself
# Config
pmb config list default tier (25 keys you care about)
pmb config list --pro every key, including 80 advanced knobs
pmb config set recall.ppr_enabled true toggle a feature
pmb connect --rules-only refresh CLAUDE.md onlyStep-by-step per agent: docs/guide/usage.md. Full reference: docs/reference/COMMANDS.md.
Hooks - memory that doesn't wait to be asked
The hard part of agent memory isn't storing - it's getting the agent to use
what's stored. Soft instructions in a rules file get skipped. So PMB wires hooks
at the protocol level (pmb hooks install claude-code), each removing a
dependency on the model remembering to act:
UserPromptSubmit -> auto-recall. Every message is classified (regex, multilingual, sub-ms) and the matching memory - lessons, past decisions, recall hits, project overview - is injected before the model thinks. Trivial messages inject nothing.
PostToolUse -> ambient observe. Every tool the agent runs is appended to a lightweight action journal (a single SQLite INSERT, no model). Reads and
lsare filtered out; edits, tests and commits are kept.SessionStart -> session-restore. After a context compaction the agent rebuilds "where you left off" from what the session recorded, instead of re-asking you.
Stop -> follow-through + ambient auto-write. (a) It checks which surfaced lessons actually showed up in what the agent did and marks them followed, deterministically. (b) If the agent did NOT call a
record_*tool, it synthesizes one activity entry from the observed actions - so real work is captured even when the agent stays silent.
Preview any without an agent: pmb auto-context "...", pmb session-restore -m 180, pmb lesson-followcheck --dry-run, pmb autowrite --dry-run.
Ambient memory - the write side
Auto-recall fixed the read side; ambient memory does the same for the write
side - the memory journals the agent's work even when it forgets record_batch:
Coordinated. If the agent already called a
record_*tool this turn, ambient stays silent; it only fills the gap.Outcome-scored, not churn. A turn is journaled only if results clear a quality bar (tests passed, a failure fixed, a deploy ran), not by file count alone.
Honest + reversible. Every ambient entry is tagged
source=autowrite, shown as auto in the dashboard, and removable withpmb forget-auto. On by default; disable withpmb config set autowrite.enabled false.Works on every host. Claude Code (hooks), Codex (
pmb codex-notify), MCP-only hosts like Cursor/Zed/VS Code (git observer,pmb ambient-watch .). Check yours withpmb hooks capabilities.
Synthesis is template-based by default (instant, no model). Opt into a local/API/CLI
model summary with pmb config set autowrite.synthesizer llm:ollama or llm:openai
(it has a timeout and falls back to the template).
Self-improvement loop
Every surfaced lesson carries a surface_id. Follow-through is recorded both
ways: the agent confirms via mark_lesson_followed(surface_id, True), and the
Stop hook infers it from recorded activity. The Lessons tab then shows,
per rule: how often it was shown, how often it was followed, ★ USEFUL
(followed >= 2x), ? UNVERIFIED (surfaced but unconfirmed), and 💀 DEAD only
when a rule is repeatedly ignored (>= 2). You see which rules help and prune
the ones that don't.
Settings - 25 you care about, 80 you don't
PMB has 105 tunables. The 25 that affect day-to-day quality are default-tier
(pmb config list). The rest are internal weights and experimental flags,
hidden behind --pro so the surface stays scannable. Every pro key still reads
with pmb config get and writes with pmb config set - hidden from list, not
gated.
| Key | Default | What it does |
|---|---|---|
recall.top_k | 5 | How many results recall returns |
recall.bm25_weight | 0.7 | BM25 vs vector mix (1.0 = pure BM25) |
recall.ppr_enabled | true | Multi-hop graph diffusion, gated by intent |
recall.keyed_fact_boost | 0.35 | How hard personal-attr facts win on personal queries |
recall.rerank | false | Always-on cross-encoder (regresses LoCoMo, keep off) |
embedding.model | paraphrase-multilingual-MiniLM-L12-v2 | The vector model |
graph.extractor | regex | regex / spacy / llm:claude / llm:openai / llm:ollama / llm:codex |
mcp.record_batch_async | true | Fire-and-forget writes (sub-ms return) |
agent.apply_lessons | true | Agent surfaces lessons before acting |
dedup.enable | true | All four dedup layers |
decay.factor_per_day | 0.985 | Importance half-life |
chat.model | haiku | Default model for pmb-chat |
Numbers
| Recall p50 / p95 warm | 35 ms / 110 ms |
prepare(message) warm | 4-16 ms |
record_batch_async | < 1 ms |
| MCP cold boot | 3.7 s |
| LoCoMo recall@10 (n=10) | 94.5 % |
| Multilingual mega-stress top-10 (900 q) | 99.2 % |
# Reproduce locally
python scripts/benchmarks/benchmark_locomo.py --n-conversations 10
python scripts/benchmarks/mega_stress_test.py<a name="privacy"></a>Privacy
100 % offline by default. No network calls from the engine, zero telemetry - there is no PMB server to call home to.
Workspace = a directory under
~/.pmb/<name>/. Copy it to Dropbox, push it to git, share it on a USB drive. Your call.Secrets are auto-redacted at write time (OpenAI / Anthropic / AWS / Stripe / GitHub keys; configurable).
Apache 2.0 licensed. Forks welcome.
FAQ
Does PMB call an LLM? On read: never. On write: never by default. Optional:
pmb consolidate can run a local Ollama, Claude CLI, Anthropic, or OpenAI pass to write short
reflections - opt-in.
What about cost? $0. There is no PMB service.
Does the agent need to know about PMB? After pmb connect, the rules are
appended to CLAUDE.md / AGENTS.md automatically. The default profile exposes
10 core MCP tools (including the prepare() read-first pattern); wider profiles
exist for ingestion and admin.
Will it slow my agent down? Tools return in single-digit milliseconds for
everything except recall (35-110 ms warm), which is below human perception.
Can two agents share one memory? Yes - point them at the same workspace. SQLite WAL + a 10 s busy-timeout handle concurrent writes.
Wipe a fact? pmb forget <ulid> archives it (excluded from recall, restorable).
Hard-delete: pmb delete <ulid> --hard.
Windows? Yes - tested on Windows 11, macOS 14, Ubuntu 22.04. Cyrillic paths and console encoding are handled.
PDFs / code / Markdown? pmb index pdf paper.pdf, pmb index project .,
pmb import markdown ~/notes/, pmb import chatgpt path.json.
Cold start is slow. First recall loads the embedding model (~3 s). Run
pmb warmup once, or let the prewarm thread handle it in the background.
Roadmap? See docs/ROADMAP.md: litestream backup, optional cloud-sync (BYO bucket), tree-sitter project indexing, image OCR.
Contributing
Issues and PRs welcome. There's one full-time maintainer; please open a discussion before a large change so we can align on direction.
git clone https://github.com/oleksiijko/pmb.git && cd pmb
python -m venv .venv && source .venv/bin/activate
pip install -c requirements-dev.lock -e ".[dev,crypto]"
python scripts/prewarm_models.py
pytest # full suite, ~4 minutes
pytest -k recall # fast subset, ~12 sDev commands
bash scripts/test.sh # whole suite (CI-equivalent)
bash scripts/test.sh tests/recall # a subset (any pytest args pass through)
bash scripts/codeql_local.sh # run CI's CodeQL security-extended locally
bash scripts/install-dev-hooks.sh # pre-commit hook: ruff + CodeQL before each commitscripts/codeql_local.sh auto-installs the CodeQL bundle on first run and runs
the exact suite CI uses, so security findings are caught locally instead of on a
push. The pre-commit hook bypasses with git commit --no-verify (or skip just
the scan with SKIP_CODEQL=1).
License: Apache 2.0.
CHANGELOG.md
Changelog
All notable changes to PMB are documented here.
[1.3.0] - Unreleased — Reliable local memory
Added
Verified workspace snapshots: SQLite online backup, SHA-256 file manifests,
pmb snapshot verify, and machine-readablepmb snapshot list --json.Restore validates before changing memory, keeps a verified safety snapshot, removes stale files, and rolls back file moves on an I/O failure.
Fixed
Cold prepare-context hooks accept prompts beginning with a dash and keep the agent turn open if the fallback CLI fails (#92).
Hook requests name their workspace before asking a shared daemon for context.
Daemon restarts reuse the current address, and reconnecting an HTTP MCP client uses the running daemon's port (#89).
Arc clustering ranks active threads by similarity before selecting the options sent to the model (#83).
Update FastMCP and development dependency pins to include upstream security fixes.
On Windows, an MCP tool call no longer hangs until the client times out when it is the first to load a native extension or start
gitin the server process. The stdio transport kept a synchronous read pending on stdin, and Windows makes a seek on that pipe, or a child process that inherits it, wait for the client's next message. A waiting client sends only its cancellation (after 180 s in Copilot CLI). The server now reads from a private duplicate and points fd 0 at the null device.Correction capture only reads the user's own words: text inside
<pasted_content>(a pasted log, a reply from another assistant) and Claude Code side-agent notes no longer produce a false "CORRECTION DETECTED" or a draft lesson. A draft made from a real correction quotes the user's own words, not the paste.Ollama maintenance respects the model and endpoint saved in configuration. Explicit arguments and environment variables still override saved values; auto detection probes the same endpoint used for generation. HTTP model errors are distinguished from an unreachable server (issue #81).
Consolidation honors the saved backend when no override is supplied, waits for durable embedding completion, and labels dry-run results as previews.
Failed model calls return a nonzero consolidation exit status and keep source events. Malformed decisions cannot authorize archiving.
Serialize inference through the shared embedding model to prevent native crashes when recall overlaps the background embedding worker on macOS.
Tests no longer rewrite the developer's global Git identity. Dry-run write isolation uses deterministic vectors instead of a platform-sensitive score.
Cold-write tests isolate model-load traps to their own engines, avoiding interference from background work and running on every supported platform.
Local test scripts include the property and MCP integration suites; CI and local development use the same pinned dependency constraints. Quarantine failures remain visible, and skipped required jobs cannot turn CI green.
Package, npm, MCP registry, and citation versions agree on 1.3.0.
Claude Code subagent hand-backs (
<agent-message ...>prompts) are skipped like<task-notification>blocks, so they no longer get auto-context or trigger a false "CORRECTION DETECTED" and a draft lesson (issue #84).
Previously merged fixes included in this release
Fixed
pmb decayno longer dies withKeyError: 'decay_factor'on every run. Decay became per-tier (signals/decay.py TIER_DECAY_FACTORS) andapply_decayreturnsdecayed_by_tier; it has never returned a singledecay_factor. The CLI summary line still formattedresult['decay_factor'], so the command raised on every invocation — after the importance updates had been written, so the decay itself succeeded and only the report died. That is the worst shape for a maintenance job: scheduled decay looks broken (or, piped to a log, looks like a hard failure) while the data change silently went through. The summary now reports the per-tier breakdown it actually receives, and tolerates a payload without one.MCP call telemetry is no longer lost when a server shuts down.
record_callbuffers rows and writes them once_PERF_FLUSH_EVERY(25) have accumulated, but nothing flushed the remainder on the way out - so a server that handled fewer than 25 calls recorded nothing, and every server dropped its final partial batch. Since most sessions never reach 25 tool calls,mcp_callscould stay empty indefinitely, leaving the dashboard Performance tab andpmb mcp perfwith no data to show. The stdio server now installs anatexithook plus SIGTERM/SIGINT handlers (install_shutdown_flush), which matters because an MCP stdio server is a child process its host terminates with a signal, and Python does not runatexithandlers on SIGTERM. The signal path restores the previous disposition and re-delivers, so Ctrl-C andSIGTERMstill behave exactly as before.The warm daemon drains its buffered perf rows when it stops serving.
run_daemonhands the process touvicorn.run, and uvicorn captures SIGTERM/SIGINT itself: it shuts down, restores the previous handlers, then re-raises the signal from insideServer.capture_signals, so the process dies withoutuvicorn.runever returning. Neitherinstall_shutdown_flush's signal path, noratexit, nor afinallyarounduvicorn.runcan run on the path that actually stops a daemon. That left/internal/shutdownand the idle watcher as the only drains — and the watcher does nothing at all whendaemon.idle_exit_minis0(never idle-exit), so a daemon serving fewer than_PERF_FLUSH_EVERYcalls recorded no telemetry. The drain now hangs off the ASGI lifespan shutdown, which does run before uvicorn re-raises; all exit paths share one_drain_before_exithelper. Verified end to end: 6 real MCP calls through a daemon, thenSIGTERM—mcp_callsdid not even exist before, and holds all 6 after.
Added
OpenAI API backend support across consolidation/reasoning,
pmb-chat, graph extraction, autowrite summaries, config, doctor, and LLM command help. Uses stdlib HTTP; no OpenAI SDK dependency.
[1.2.3] - 2026-08-16 - Version-consistency fix
Fixed
pmb.__version__now matches the release. The 1.2.3 release bumpedpyproject.tomlbut left the__version__constant (and the npm package version) at 1.2.2, sopmb daemon status/pmb doctorreportedv1.2.2even after upgrading — which read as "the restart didn't work" and sent users chasing a non-existent stale-process bug.__version__, the npm package, and the CHANGELOG all agree on 1.2.3 now.
[1.2.2] - 2026-06-29 - Dashboard port fallback and ambient watcher UX
Fixed
pmb dashboardno longer crashes with a raw socket traceback when the default port is unavailable. If127.0.0.1:8765is already held by the warm daemon / MCP server, the dashboard auto-skips to the next free port; explicit--portchoices now get a short actionable diagnostic instead of a Python stack trace.MCP recall lesson E2E now checks the supported contract. Procedural rules returned by MCP
recall()live in the top-levellessonsfield, so the old quarantined assertion against onlyresultswas removed.
Added
pmb ambient-watchcan manage several MCP-only project observers in one process. Runpmb ambient-watch app api docs --saveonce, then restart all saved targets withpmb ambient-watch --all.
[1.2.1] - 2026-06-27 - Security and CI-stability pass
Security
Dashboard static serving is path-traversal-proof.
/static/<name>is served by exact-name lookup againstSTATIC_DIR's own listing, so user input never reaches a filesystem path - closing CodeQLpy/path-injectionand the related response-splitting on the derivedContent-Type.Encrypted-bundle import is tar-slip-safe.
import_workspacerejects symlink / hardlink / device members and never calls an unfilteredextractall(older runtimes extract validated members by hand) - CodeQLpy/tarslip.File-path regex made linear (ReDoS). The entity-graph file-path pattern no longer backtracks catastrophically on long slashless input.
Dashboard log injection closed - the request route is stripped of CR/LF before logging.
Git post-commit hook installed
0o700(owner-only) instead of0o755.
Added - developer tooling
scripts/codeql_local.shruns CI's CodeQLsecurity-extendedsuite locally (auto-installs the bundle on first run), so security findings surface before a push.scripts/test.shruns the whole suite or any subset;scripts/install-dev-hooks.shwires a pre-commit hook (ruff + CodeQL).
Fixed - CI stability
Matrix-reddening flaky tests fixed at the source: the smart-recall confidence check tolerates time-based float jitter; the dashboard and delete-API HTTP harnesses wait for readiness and retry transient timeouts (shared
tests/_http.py); an embedder-float-variance ranking test is markedplatform_sensitive(gates on the Linux reference runner).
Fixed - stability and recall-correctness pass (live-session QA)
forget/pin/restoreinvalidate the recall cache, so a forgotten memory stops surfacing immediately instead of lingering in the warm daemon's cache until the TTL.PMB's own LLM sub-calls no longer trip PMB's hooks.
pmb track changes/track modules/ consolidate spawnclaude -p; those sub-calls now setPMB_INTERNAL_LLM=1andpmb-hookno-ops on it, so the summarizer's own instruction ("Capture the INTENT, not the diff") is no longer captured as a "user correction" draft lesson.pmb track modulesnever stores a refusal as a module purpose. The prompt states the indexed structure is the only input, and refusal / clarifying-question / "unknown" responses are dropped instead of stored.pmb history/pmb correlatefind commits tracked bypmb track changes(read both thefilesandfiles_changedmetadata keys and thegit-changefact source, not only the legacy git-signal schema).pmb doctorchecks the configured embedding model (the default multilingual MiniLM-L12) instead of a hardcoded all-MiniLM-L6-v2, ending a false "model not cached" warning.pmb recall(CLI) routes through the warm daemon for full hybrid (BM25 + vector) results when one serves this workspace, instead of cold BM25-only; falls back to the local cold engine otherwise.index projectcaptures module-level constants (UPPER_CASE assignments) as symbols, not just defs / classes / methods.The entity graph no longer ingests code-index scaffolding (
file,symbols,imports, month names) as nodes.Out-of-band writes are visible without a restart. A long-running engine (the warm daemon) reloads its index when another process changed it; a cold write (a one-shot CLI with no model loaded) indexes into BM25 synchronously; and the recall cache is invalidated on an external change. A CLI
pmb fact/indexis now recallable immediately.Auto-recall surfaces the specific fact for project-named questions ("what is
<project>'s X?") instead of only the project overview.Project-scoped recall (
recall(project=X)) also matches decisions that name the project in their content. Found in a live agent-to-agent test: one session records a decision (record_batch stores it as anactivity, dropping the project tag), and a laterrecall(project=X)filtered it out - breaking cross-session memory. The scope filter now falls back to a content mention, so the decision is found.Hooks are emitted UNQUOTED so they parse in PowerShell. Headless
claude -pon Windows runs hooks through PowerShell, which ParserErrors on a quoted command ("pmb-hook" ...) with no&call operator - so SessionStart / Stop / auto-recall silently failed in headless agents and injected memory never reached them. The hook command is nowpmb-hook ...(unquoted bare name on PATH, or a space-free absolute path), which parses in PowerShell, cmd and bash.The cold auto-context no longer mangles Cyrillic / emoji. The cold hook path decoded the full
pmbCLI's UTF-8 stdout with the Windows locale (cp1251), double-encoding non-ASCII - the agent saw "Карта проекта" arrive as "Карта проекта". The decode (and the child's output codec) are now pinned to UTF-8, matching the daemon path.Captured corrections are scoped to the project they're about. A correction-capture draft was stored as the raw user message with no project context, so it surfaced contextless and could leak across the other projects sharing a memory store. The draft now records which project the complaint is about - both as structured
project_namemetadata (sofind_lessons(project=...)keys off it) and inline as a[project: X]tag - resolved via the same lenient detector the overview path uses (so dev-ish names likepmbare caught). A path-like workspace name is reduced to its basename, so the tag never becomes a full filesystem path.Hooks survive Windows Smart App Control. Hooks are now invoked through the signed Python interpreter (
<python> -m pmb.hookclient ...) instead of the pip-generated, UNSIGNEDpmb-hook.exelauncher. SAC blocks unsigned executables, which silently killed every hook (the user saw "part of this app was blocked" pointing at the hook path, typically right after a reinstall recreated the shims). The interpreter path is the space-free first token, so the command still parses unquoted in PowerShell / cmd / bash.pmb hooks installis strip-then-add, so reinstall leaves no stale or duplicate hook lines. It removes every PMB-marked hook first, then writes the current set - previously an unrecognised marker or an oldpmb-hookline could survive a reinstall as a duplicate (capture-explorationwas missing from the marker set and is now included).
Changed
The warm daemon serves the effective
leantool profile by default (forget / recall_smart / index_project / project_structure + the core memory loop), andpmb daemon start/restartnow readsdaemon.tool_profileinto the spawned daemon, so a manual restart keeps it instead of falling back to the tight 10-toolminimalsurface.pmb workspace currentwording: sourceexplicitnow reads "explicit workspace id (--workspace flag or caller-provided)".
[1.2.0] - 2026-06-27 - Dashboard redesign and self-tending memory
A full dashboard redesign, settings moved out of the TUI into the dashboard, and engine work that lets memory tend itself.
Added
Dashboard redesign: violet PMB design system (Inter, glass surfaces), a live Settings tab that edits config in the browser, global search, a collapsible icon sidebar, a boot loader, a custom confirm dialog, Map polish, an Overview activity chart, an Errors tab, and running maintenance commands from the UI.
Memory tends itself: the daemon maintenance tick now runs the forgetting-curve decay before archive_cold (gated by
daemon.maintenance_decay), so importance decays on its own instead of needing a manualpmb decay.Recall quality: saturated the graph boost
w/(1+w)and tuned thegraph_boostdefault.New docs page: "Does PMB actually help — and how we measure it honestly" (
concepts/measuring-impact.md). Lays out the two-method evaluation stance - retrieval benchmarks (LoCoMo / multilingual) for recall quality, and Earned Memory's three honest layers (associational lift → Wilson-CI verdicts → within-lesson followed-vs-ignored causal read) for whether memory changes outcomes - with the limitations stated plainly and how to run it on your own workspace.
Changed
Silent best-effort swallows in the write path are now observable. Audited the ~340 bare
except Exception: passblocks. The hot write/recall paths use them heavily, but for BEST-EFFORT secondary work (graph edges, temporal / identity enrichment, dedup queueing) layered AFTER the primary event is already persisted - non-blocking by design, not data loss. The real gap was visibility: a systemic enrichment failure degraded recall silently. The recall-affecting swallows in the hot path -write.py(graph / temporal / identity / dedup enrichment),embed.py(queue drain - a systemic failure can no longer silently leave events unembedded and unfindable) andrecall.py(scoring boosts + recall-time drain) - now route through the existingerrlog.log_errorseam (the idiombatch.pyalready used), so a repeated failure surfaces inpmb doctor/ the status panel instead of vanishing. Warmup probes, config reads and intentional fall-throughs are left silent by design. The happy path is unchanged - zero cost unless something throws.Default MCP tool surface trimmed 34 → 10 (
minimalis now the built-in default profile). A freshly connected agent now sees a tight core-10 -prepare,recall,project_overview,find_lessons,mark_lesson_followed,session_brief,record_batch,record_keyed_fact,list_goals,update_goal- instead of 30+ tools, cutting choice-confusion and per-turn token cost. Nothing is removed: the fuller surface stays one flag away (PMB_TOOL_PROFILE=default= 34 tools,full= ~65), and the publicdefaultsurface is byte-for-byte unchanged (still pinned by the API-contract test).pmb connect claude-codenow pinsminimal(waslean).Earned Memory is now statistically honest.
lesson_impact/pmb health lessons-impactpreviously reported per-lessonliftas a bare point estimate, so an n=1 fluke could read as a real "useful"/"harmful" effect. Each lesson now carries a 95% Wilson confidence interval and a conservativeverdict-useful/harmfulonly when the CI clears the no-lesson baseline AND n ≥min_n(default 5), otherwiseunverified/insufficient. The report addssignal_sufficiency, atrustworthyflag,n_confident, and an explicit confounding-by-indicationcaveat; the CLI shows the CI, the verdict, and a "not yet trustworthy" banner. The measurement-only stance is unchanged - it now states WHEN it can't be trusted instead of emitting a misleading number.Earned Memory gains a within-lesson causal read. Beyond the associational
lift(vs the no-lesson baseline), each lesson now reports acausal_verdict(helps/hurts/inconclusive/insufficient) from a followed-vs-ignored comparison of the SAME lesson's turns - holding the surfacing trigger fixed, which controls for the confounding the baseline lift cannot. It fires only when both arms clearmin_nand their Wilson CIs separate. New per-lesson fieldsn_followed,n_ignored,followed_success_rate,ignored_success_rate,followed_lift; a top-leveln_causal; and a CLI section that prints the conclusive reads (or says the causal read is pending more data). Residual confound noted incaveat: the agent's choice to follow may itself track task type.
[1.1.0] - 2026-06-24 - Semantic tracking, memory feedback, and token-saving guards
A semantic layer on top of pmb index project. The structural index says which
symbols exist; this says WHY a file exists and WHY it changed. All local, Haiku
by default (or fully offline via Ollama), and idempotent.
Added
pmb track changes- reads new git commits, asks a small LLM (Haiku) to summarise each commit's INTENT (the "why", which a raw diff does not carry), and stores it as agit-changememory record linked to the files it touched. Idempotent via a per-repo cursor kept next to the workspace DB (not in the event store, so it never pollutes memory). Flags:--since,--max-commits,--backend(auto/claude/anthropic/ollama).pmb track modules- a one-line "what this file does" summary per indexed file. Runpmb index projectfirst; files already summarised are skipped (--forceto redo),--limitcaps LLM calls per run.pmb track install- a gitpost-commithook sotrack changesruns automatically after each commit (background, non-blocking, never clobbers an existing hook).project_structure(name)MCP tool - the agent pulls a project's file/module map straight from memory (languages, files grouped by directory with their purpose + symbol count, key modules, recent change intents) with no filesystem scan. Assembles whatindex_project+track modules+track changesalready stored.recall_exploration/record_explorationMCP tools (incremental cognition) - memoize the conclusion an agent reaches after exploring the codebase, keyed to the content hash of each source file. A future session callsrecall_explorationand gets the conclusion back with a freshness check:freshwhen every source is byte-identical (reuse it, skip the re-reading), otherwisestale_fileslists what changed so only those are re-checked. Caches the agent's research OUTPUT (an incremental build for reasoning), targeting repeated exploration - the real token/turn cost - rather than context size.Auto-capture of exploration memos (
pmb capture-exploration, Stop hook). Off by default (memo.autocapture_enabled); when on, a turn that read >= N files and ended with an answer is memoized from the transcript automatically.recall_explorationalso reportsrepo_changed_since(the repo moved beyond the listed sources, so verify even if the listed ones are fresh), closing the false-fresh gap.Memory Delta Protocol (
memory_delta.enabled, default off). A per-session ledger of items PMB has already shown the agent. When auto-context re-injects the same lesson, the renderer collapses it to a one-line handle reference (! [M07] still active) instead of restating the full text. New items get a fresh[Mxx]tag, updated items are flagged, and items that left the active set surface asExpired since last turn: M03. SessionStart fires a Context Rebase that clears the ledger so the next render restates full text - critical after/compactbecause the model loses the handle->text mapping. Measured -72% block size on repeat injections of 3 typical lessons; default off until measured on your own workflow. CLI:pmb memory ledger,pmb memory rehydrate.Resume note (
pmb resume save / show / install). Writes.pmb/resume.md- a structured, committable markdown snapshot of "where we are now": open goals, recent decisions, lessons, recent activity, files touched, latest exploration conclusions, and project structure. Sourced from PMB's typed memory (not extractive), so the sections have real structure. Content below thePMB-RESUME-MARKERline in an existing file is preserved across regenerations - hand-edited additions survive.pmb resume installflipsresume.auto_save_enabledso the Stop hook refreshes the file at every turn end; commit it to share session continuity with your team.Earned Memory (
pmb health lessons-impact,lesson_impactMCP tool). Joins each surfaced lesson to the OUTCOME of the turn it was active in (tests pass/fail, red->green, build, deploy - no LLM) and reports per-lesson success-rate, lift vs the no-lesson baseline, and churn - so PMB can show which rules pull weight vs which are dead-weight or harmful. Measurement only; ranking/decay feedback is deferred until the outcome signal is dense enough to trust.Capture-on-correction. When a user message reads as pushback / frustration / a repeat complaint (RU/UK/EN profanity, ALL-CAPS, "те же грабли", repeat-word + a negated action), PMB records a DRAFT lesson on the FIRST occurrence and nudges the agent to refine it - so the rule exists in memory when it is needed, not after the seventh complaint. Tagged
source=correction-capture, deduped within a 90-min window. Knobs:auto_recall.correction_capture,correction_record_draft,correction_importance.Repeat guard (message-time). When a new message strongly overlaps an existing rule, it is promoted to a LOUD banner at the top of the auto-context block ("YOU'VE HIT THIS BEFORE") instead of one line in a wall. Knob:
auto_recall.repeat_guard.Repeat guard (action-time). The PreToolUse guard now also fires the "do NOT repeat this" corpus - failures + correction drafts - at the MOMENT the agent is about to act ("⛔ STOP - you were corrected on this before"), so the warning reaches inside autonomous tool loops that have no user message. New
find_negative_memories(); extends the existing R11 lesson guard. Replay on a real transcript: the recurring failure became catchable at the 2nd occurrence vs the 8th in reality.
Changed
Lesson/decision decay floor. Lessons and decisions no longer decay below importance 0.6, so a critical-but-rarely-recalled rule cannot silently fade out of
find_lessonsranking. Pinned (>=0.99) and ordinary qa/activity events are unaffected. Retire a rule witharchive/forget, not by waiting.Surface-ids reach the agent after
/compact.session_restorenow logs lesson surfaces BEFORE rendering and embeds[id:N]in the text, plus a "pending confirmations" block - somark_lesson_followedworks on the post-compact path (previously the id never reached the agent).
Fixed
track changeson merge and root commits. File list + diff now usegit diff-tree --first-parent --root/git show --first-parent, so merge commits report their first-parent changes and the initial commit still lists its files (previously empty, which made the LLM guess the intent).Faster offline LLM calls. The Claude-CLI backend passes
--strict-mcp-config, so headless one-shot calls (track summaries, consolidation) no longer load the user's full MCP server set on every call.
Reuses the existing LLM client (Claude CLI / Anthropic / OpenAI / Ollama) and runs the model with no tools, so feeding it untrusted diffs is safe.
[0.9.3] - 2026-06-14 - Injection precision, cross-lingual recall, model picker
Sharper auto-context: the hook injects the right memory and stays quiet on small
talk, recall finds cross-language answers, and you pick the embedding model in
setup (or swap it later in one command). All additive + config-gated - default
behaviour is safe.
Injection precision (read path)
Absolute-evidence gate on by default.
auto_recall.evidence_min_cosine0.0 -> 0.045: a GENERIC_FACTUAL question the workspace knows nothing about now surfaces nothing instead of the min-max top hit (cross-domain noise 100% -> 0% on the measured corpus).Specificity gate.
auto_recall.specificity_strong_cosine(0.08): a hit must share a distinctive token with the message OR be a strong embedding matchremoves same-domain-but-unhelpful hits the floor alone can't separate.
Conversational gate. A meta turn ("is it better now?") with a diffuse match (small score gap + low confidence + no lexical anchor) surfaces nothing (
auto_recall.conversational_gap_max/conversational_conf_max).Query-worthiness classifier (opt-in). The SAE anchor-margin pattern on a new axis - conversational vs knowledge-seeking - via English exemplars + the multilingual embedder (
auto_recall.query_worthiness, default off; measured a clean split, kept opt-in since the cheap gates already cover the common cases).Rules vs Context split. Lessons render as RULES (high recall); recall hits render as "Possibly relevant context (background, not rules)" (high precision).
Corpus-IDF lesson gate.
find_lessons/find_decisionsrequire a token RARE in this workspace's own corpus, not just globally distinctive (recall.lesson_idf_gate).
Cross-lingual recall
OOV bm25 damping. When a query's content tokens are entirely out-of-vocabulary for the BM25 corpus (e.g. a foreign-language query over an English corpus), the lexical channel is down-weighted so the vector channel decides (
recall.crosslingual_bm25_damp, 0.3). F4 cross-lingual top-1 0.27 -> 0.55, with no in-language regression (floors raised to lock it in).
Memory model picker
pmb setupasks which embedder - Light / Balanced / Best, with plain plus/minus + RAM, and loads the chosen one. Plus an offline-LLM-tier choice (auto / claude / ollama / anthropic) - background only, no injection cost.pmb modelswitches the embedder later in ONE step: download + load + re-embed memory (reindex) + restart the daemon.pmb model best,pmb model BAAI/bge-m3, or the interactive menu.
Install flow (one warm daemon for every agent)
pmb setupshares the warm daemon by default. Followingconnect.default_daemon, setup points the host at the ONE warm daemon and starts it, so the first message is instant and N clients cost ~400 MB total, not ×N. (--stdio/connect.default_daemon falsekeeps the old per-client server.)pmb mcp proxy- stdio↔daemon bridge for codex. codex is stdio-only and can't take an HTTP entry, so it used to cold-load its own Engine+model every session (the codex start-up lag). It now launches this lightweight bridge (holds no model) that forwards to the shared daemon, autostarting it if needed - so codex shares the one warm process too.pmb connect codexwires it by default.pmb setup --allwires every detected agent at once (Claude Code + CodexCursor + …), all sharing the single daemon, with one combined summary.
In-place setup menus. The embedder / offline-brain choices are now arrow menus that redraw in place (↑↓ pick · ⏎ choose · digit quick-pick · esc keep), with a static table+prompt fallback off a TTY / in CI.
pmb daemon kill-allstops the daemon AND every registered PMB process, then clears the registry - the escape hatch when stray/duplicate warm processes pile up and starve a small box (tree-kill on Windows).pmb-aicommand alias. The CLI ispmb; installed via pip you also getpmb-ai, and via npm (npx pmb-ai) the command ispmb-ai. Same tool.npm does a real install cycle. The npm package no longer just forwards or prints "ok": a postinstall (and the launcher, on first use) installs the Python
pmb-aipackage persistently, preferringuv tool install, thenpipx, thenpip --user, with visible progress. Sonpx pmb-ai setupbootstraps Python PMB and runs setup end to end. SetPMB_SKIP_POSTINSTALL=1to opt out (CI / Docker). An existingpmbon PATH is used as-is.Clearer "you're all set" card after setup: confirms what was wired (agent · hooks · daemon), points to
pmb modelto change the embedder later, and topmb daemon kill-allto reset stray processes.
Codex integration: honest about what's a hook
Codex wires
notify→pmb codex-notify(the real mechanism) for ambient auto-write after each turn; read-first / auto-recall is driven by the AGENTS.md rules (Codex has no per-turn / session-start shell hook - only Claude Code does).pmb hooks install codex/pmb connect codexnow say exactly this instead of implying per-turn injection.Removed the dead
~/.codex/hooks/pmb-session-start.sh. Codex never executed it; it only madepmb hooks listlook like codex had a session-start hook. Install cleans up any leftover;pmb hooks listnow reports the notify.
Deleting memories (dashboard + CLI)
One clear delete, two levels. A new
engine.delete_event(ulid, hard=): soft archives (reversible), hard purges permanently. The hard path (EventStore.purge) removes the SQLite row, the vector (search.remove), and the event's graph links so nothing dangles and recall can never resurface it.pmb delete <ulid...>is the front-door: a preview + confirm, archives by default (restore with the newpmb restore),--hardto purge,--yesto skip. The permanent prompt defaults to "no".forget/forget-topicstill work for quick archives.Dashboard delete UI. The event panel now has Archive (reversible) and a red Delete (permanent, with a confirm) alongside Pin, backed by
POST /api/delete/<ulid>({"hard": true|false}). The active view refreshes after a delete so the memory disappears immediately.
Documentation
A proper docs set that renders on GitHub, all hyphen-style (no long dashes): index hub, getting-started, deleting-memories, architecture (components + read/write data flow), and design-and-tech (patterns, stack, decisions), linked from the README.
Decluttered
docs/: removed the screenshot generators (*.html,_save_png.py,_capture_server.py,_template.css) and the done planning notes underdocs/plans/, keepinglogo.pngand one dashboard screenshot. Fixed a broken README image link (it pointed at a missing02_dashboard.png) and updatedMANIFEST.into match.Reorganized the docs into a navigable tree (
guide/,concepts/,reference/,contributing/) and added a Material for MkDocs site published to GitHub Pages via.github/workflows/docs.yml(Pages Source: GitHub Actions). New deep-dive pages:concepts/how-it-works.mdandreference/configuration.md, plusguide/dashboard.md.
Guard & fixes
Command-aware PreToolUse guard. A rule that NAMES a command ("never use git") now fires before every invocation (
git push/git status/ chained), via structural command-name extraction - no hardcoded command list.No flashing console windows on Windows - background spawns use CREATE_NO_WINDOW (the daemon still survives the launching process).
CI offline-model robustness -
scripts/prewarm_models.pyretries downloads and fails fast on the essential embedder; the HF cache key no longer rotates on version bumps.Fixed a latency-trace crash - the PreToolUse shadow-sample reused the perf-timer variable name (
auto_recall.py).
[0.9.2] - 2026-06-14 - Command palette + first-run
A from-the-first-second CLI experience. No engine behavior change.
CLI - command palette. Bare
pmbin a terminal opens a fuzzy + synonym launcher over every command: type by intent ("make it fast" ->warmup, "forget old stuff" ->declutter/decay), arrows to pick, Enter runs. Instant and model-free; falls back to the status dashboard when piped (cli/palette.py).CLI - first run. The first
pmbplays a brain-forming spark boot animation and a one-screen welcome (shown once via~/.pmb/.welcomed);pmb setupis now question-free when an agent is detected (cli/intro.py).CLI - grouped
--help. ~66 commands organized into 7 ordered panels (Setup & agents / Capture / Recall & explore / Maintain / Workspaces & data / Agent internals / More) instead of one flat wall.CLI - no more blank screens. 11 model/LLM commands (recall, why, overview, reindex, rehearse, dedupe, reflect, arcs, consolidate, distill, regraph) show a spinner during cold model/LLM work instead of an empty field.
Daemon - robust start.
pmb daemon startauto-picks a free port when 8765 is busy (e.g. a streamable-http MCP server already holds it) instead of dying silently, and the spawned daemon's stdout/stderr go to~/.pmb/daemon.log(was DEVNULL) so a crash is diagnosable.Fix. The "first run pulls ~90 MB" hint corrected to ~450 MB (the real size of the multilingual embedding model) in
pmb setupand the README.Brand. The spark wordmark is consistent across setup, status, palette, help.
[0.9.1] - 2026-06-13
Repository hardening + open-source polish. No engine behavior change.
CI: prewarm the HF models before pytest so the offline suite survives a cache miss (a Dependabot PR can't restore the model cache). Fixes the gha-all run.
Tests: the 146-file suite is reorganized into 12 subsystem folders (lang, recall, engine, hooks, mcp, ingest, maintenance, security, cli, integration, eval, meta) with frozen baselines under
tests/fixtures/. 1308 passed / 0 failed - unchanged behavior; repo-root paths are now depth-independent.Docs: new
docs/usage.md(per-agent walkthrough); the shipped v0.9 PLAN is archived todocs/plans/; fixed thepmb connect claude->claude-codeid.CLI:
pmb setupwarms the embedding model inline and points atpmb doctor.Style: em/en-dashes replaced with hyphens across the docs and CLI strings.
[0.9.0] - 2026-06-12 - Anchor Engine
Memory now understands any language the embedder does - no language packs required. A German/Spanish/French/Italian/Polish query routes to the right intent and the right fact with NO pack for that language (measured: de/es/fr/pl top-1 recall 1.00 pack-free; intents 12/12 across 6 languages).
BREAKING (G3):
packs/ru.yaml+packs/uk.yamlare DELETED. RU/UK now ride the embedder: recall via the multilingual vector channel (V1 RU/UK top-1 still 1.00, byte-identical), intents + keyed-attribute extraction via the WARM anchor tier, and the COLD lexical path self-heals from the user's own traffic via ALD ($PMB_HOME/lang/auto.yaml). The loader stays for user packs (drop a YAML in$PMB_HOME/lang/to override) and the opt-in de/es templates. Honest regression: on a COLD stdio path (no warm daemon, no distilled traffic yet) RU/UK general atomic-fact extraction, first-person / self-intent / relation / negation / future-intent lexical matchers no longer fire - those had no cheap per-candidate warm replacement. The warm-daemon path (the default after S6) is unaffected. The packs-off CI gate is now BLOCKING.
Landed against the track (all additive / default-safe; recall behaviour proven
byte-identical via the V1 eval; new multilingual gate in
test_memory_eval_multilingual.py):
Pack-free extraction + data accuracy (C1-C3, F1-F4). C1 universal value- span detector (
reasoning/spans.py); C2 keyed-fact extraction by hypothesis margin (reasoning/extract_anchor.py, warm-only, gatedextract.anchor_keyed)"Я живу в Киеве" → city=Киеве with zero Russian data; C3 canonical
attr: valueatoms; F1 extraction-confidence metadata scaling the recall boost; F2 write-time contradiction via the anti-hypothesis; F3 the X2 channel- weights learning loop closed (propose in the tick, surface inpmb doctor, never auto-applied); F4 the eval grown to a multilingual + paraphrase gate.
Self-healing lexical cache + corpus stats (D3, E1, E2). D3 recency-prunes the ALD fire log so unused phrasings age out of auto.yaml; E1 derives stopwords from the workspace's own document frequency (IDF made explicit); E2 detects PDF ALL-CAPS headings via
str.isupper()(every script, no char-class list).PAMVR on anchors (B3, B4). B3 precomputes the first-person flag at write time (
metadata.fp) so the per-candidate loop never re-derives it; B4 drops the lexical verb-synonym boost inlang.mode=anchors(the vector channel covers it).Anchor Engine - language-free intent classification (A1/A2/B1/B2 + D1/D2). A new tier that replaces hand-written per-language packs with English-only semantic ANCHORS: every role the packs enumerate (goals/past/recent/lessons question, work request, self-query, trivial ack) is a set of English positives + hard negatives; a message is classified by MARGIN (one-vs-rest) against per-set thresholds CALIBRATED at FPR ≤ 1% (
scripts/calibrate_anchors.py→src/pmb/lang/anchor_calibration.json, frozen by a test). The shipped multilingual embedder does the cross-lingual transfer, so a German/Spanish/ French/Italian/Polish query lands on the English anchors with ZERO per-language data - measured 12/12 across 6 languages × 6 intents. Runs WARM-ONLY (the cold hook never loads the model);lang.anchors(on) is the kill-switch. B2 extends the same tier to two STATEMENT detectors (guidance-seeking query → lesson boost; future-plan → suggest-goal flag) in their own scoring/calibration GROUPS, so they add multilingual coverage without competing with - or regressing - the intent tier (proven: B1 τ/recall byte-identical after B2). ALD (Anchor→Lexicon Distillation): the maintenance tick mines n-grams that reliably predict an anchor in THIS machine's traffic (precision ≥ 0.95, support ≥ 6, across-anchor) and compiles them into$PMB_HOME/lang/auto.yaml, so the COLD lexical path learns the user's languages from their own messages - no model, microseconds, fully local.lang.anchor_log(on) gates the fire log.Fixed: Codex
record_batch"timed out awaiting tools/call after 120s". Root cause: the background embed-queue worker EAGERLY triggered the full torch model load inside a cold stdio MCP process; under memory pressure (a second ~400MB model next to the warm daemon → paging) the load's GIL bursts starved the server's asyncio loop, so the client's NEXT call hit its 120s deadline. The worker is now PASSIVE (waits briefly foris_ready(), never loads -embed.queue_autoload=truerestores the old behavior), writes stay durable model-free (embed_queue_pending),warmup()kicks the leftover drain, andpmb connect codexaddstool_timeout_sec=300headroom (re-run it once to pick that up). tests/test_record_batch_cold.py.Memory hygiene + project identity.
index_projectno longer writes empty structural rows or duplicate root rows;declutterarchives old empty index artifacts; project-index labels no longer become bogus person/concept nodes; exact project entities winproject_overview, whose key facts now hide machine-generated file rows.Goal reconciliation. Completed activities automatically close a single high-confidence matching open goal;
pmb goals reconcile [--apply]repairs existing divergence. Project overview now reads the canonicalgoal_status.Thread-safe model caches. Concurrent background embedding workers load one shared transformer/cross-encoder instead of racing duplicate native loads.
One base-score function + adaptive weights (X1/X2). The base recall score lives in
pmb.reasoning.scoring.combine_base_score; a per-workspacerecall.channel_weightsJSON vector (default identity = no change) scales the hit/importance/recency channels, with apropose_channel_weightslearning hook that is never auto-applied.Calibrated confidence (X3).
calibrated_confidence- RecallPack.confidence as one named, tested, monotonic, bounded function.SLOs-as-code (X4).
pmb/health/slo.pyties each quality/latency/durability objective to the test that enforces it.Fault-injection + concurrency (X5), security (X7), API contract (X10), backup/restore + migration self-heal (X6), docs-can't-lie (X8) - new gates.
pmb connectdefaults to the shared HTTP daemon (S6). JSON hosts (claude-code/cursor) point at the one warm daemon by default (connect.default_daemon);--stdioopts out. Pinsdaemon.idle_exit_min=0and servesdaemon.tool_profileso the connection stays warm + lean.Recall writes fully off the read path (S9). Tier promotions ride the touch-flusher batch; spreading activation runs on a background thread in the daemon; perf telemetry is buffered and flushed on read.
Still roadmap: X2's online weight-learning loop, X9 distribution polish.
[0.8.0] - 2026-06-11
PLAN.md v0.8.0 "invisible memory": make memory speed invisible and memory quality measurable, and finish the language-pack vision so the core carries ZERO Cyrillic. Phases 0, T, S, R, L, V, M.
Added
Thin
pmb-hookfast lane (S2). Stdlib-only console script all five lifecycle hooks call: warm-daemon localhost path (~10-50 ms) with a full-CLI cold fallback;track-actionruns a dependency-light inline path.Daemon self-heal + workspace guard (S3/S4) and
/internal/hook/ session-restore(warm semantic restore).pmb connect --daemon(S6). Point JSON hosts (claude-code / cursor) at the ONE shared warm daemon over streamable-HTTP instead of a stdio Engine + ~400 MB model per client - N clients cost ~400 MB total, not ×N. The daemon token is now PERSISTENT so the baked auth header survives restarts. Opt-in (--stdiostays the default); codex / editor extensions keep stdio.Memory-quality CI gate (V1).
tests/test_memory_eval.pyruns a frozen EN/RU/UK corpus + paraphrase queries through the full recall pipeline and asserts per-bucket + overall top-1/top-3 FLOORS. Measured: EN/RU/UK in-language top-1 = 1.00, cross-lingual EN→RU top-3 = 1.00.Intent + PAMVR regression gates (V3/V4). Labelled EN/RU/UK intent routing set; a PAMVR multiplier "freeze" so no
score *= Xchange ships silently.Honest hook trace (S10). The auto-context header now reports true end-to-end
total=…ms source=daemon|cold(was under-reported ~30×) + a perf-marked p95 latency smoke (V2).Daemon self-maintenance (M1). Once per
daemon.maintenance_interval_hof uptime and only while idle, the daemon archives cold rows (archive-only), scans conflicts (report-only) and runs a declutter DRY-RUN - surfaced in/internal/health. Decisions survive (R7). Configdaemon.maintenance(default on) +daemon.maintenance_archive.Property-based tests (T6, hypothesis) for the hot-path invariants (tokenizers / intent classifiers / atomic-fact extraction never raise on arbitrary unicode).
Activity exact-dedup (0.2), truthful CI (T1-T4) + a zero-Cyrillic ratchet test.
Changed
Zero-Cyrillic core (Phase L complete). All Russian/Ukrainian prose AND all functional matching DATA (verb stems, stopword sets, intent/heading/relation regexes, fact-extraction templates) relocated from
src/pmb/**.pyinto the active-by-defaultpmb/lang/packs/{ru,uk}.yaml, merged back from an English inline floor. Cyrillic 521 → 0 lines, enforced by an empty-allowlist CI ratchet; behaviour pinned bytests/test_regex_parity.py. Shared categories (first_person,stopwords) were kept dedicated-per-consumer so no set silently widened.Recall-path speed (S5/S7/S8/S9).
project_overview/_known_projectsmemoized by write-generation; the arcs N+1 batched (≤50 queries → 1);session_briefscoped in SQL.find_lessons/find_decisionsserved by a newidx_meta_kindexpression index instead of ametadata_json LIKEfull-scan. Workspace-meta rewrite skipped when unchanged; psutil resolved once and RSS skipped on the hot discovery path.RecallCachemade thread-safe (daemon worker threads);_adherence_nudgecached 60 s off the write path.Lazy
pmb.mcppackage (S1) (−3-6 s/hook) and durable decisions (R7).Test harness consolidated (T5). Removed 80 redundant
sys.path.insertlines + 46 duplicatedtmp_pmb_home/tmp_workspace_dirfixture copies in favour of the sharedconftest.py.
Fixed
Tree-wide ruff cleanup; the blocking lint gate is green.
test_mcp_recall_answer_quality_and_lessonsquarantined with a documented root cause (harness prewarm-thread flake, not a product bug).
[0.7.0] - 2026-06-10
This release lands the daemon + language packs + MCP token diet + write-quality work (PLAN.md phases B-E, on top of the 0.6.0 keyed-memory correctness fixes) plus the recall-singleflight and semantic-intent follow-ups.
Added (recall + hook follow-ups)
Recall singleflight (D4). Concurrent IDENTICAL top-level recalls (same workspace, query and top_k) now collapse to one computation - useful under the daemon / multi-agent fan-out; followers reuse the leader's result and fall back to an independent recall on timeout, so it can never deadlock. Config
recall.singleflight(default on); a no-op for single-client stdio.Semantic intent fallback (C5, opt-in, default OFF). When lexical intent detection finds nothing AND the engine is warm (daemon-served), the hook can classify the message by embedding cosine against per-intent exemplars, so a query in a language the lexical patterns don't cover still fires. Default OFF and eval-gated by design - the measured finding is the semantic tier doesn't beat lexical with the default embedder. Config
hooks.semantic_intents.
Fixed (write quality - Phase E)
A user negation now CLOSES the keyed value it contradicts. Task-5 retired stale negations when a positive value arrived; the reverse was unhandled - with
user::city = Tampa, "I no longer live in Tampa" left Tampa asserted as current forever. The negation now closes the keyed value (the active keyed fact is archived and stampedvalid_to/closed_by/closed_reason), so recall stops asserting it whilekeyed_fact_as_ofstill sees it as history. Only the user's own negation (post-0.6.0 subject-adjacent detector) triggers it; gated bykeyed.close_on_negation(default on).
Changed (write quality - Phase E)
The write-time quality gate now defaults ON. Safe since the junk detector became length-aware in 0.6.0 (it flags only empty / placeholder / test-pattern / pure-stopword content, never real short facts like "O+"). Flagged facts are down-weighted (importance capped at 0.2) and excluded from keyed promotion, never rejected.
pmb doctorreports how many facts were flagged in the last 30 days so you can audit; setwrite.quality_gate=falseto record everything unweighted.Routine activities can't crowd out real facts. Activity importance is capped at
write.max_activity_importance(default 0.8) unless pinned, with animportance_clampedbreadcrumb - agents habitually pass ≈0.9 for routine actions. Facts, lessons and goals are never clamped.Agent guidance gained a "DON'T record" section (in the MCP server instructions): skip secrets, transient tool output / stack traces / file listings, and anything trivially re-derivable from the repo; future intent goes to a goal, not a fact.
Changed (MCP token diet - Phase D)
Tool descriptions shrank ~71%. The full multi-paragraph tool docstrings duplicated the read-before-write workflow and write-triggers table that are already in the server
instructionsblock, costing ~15.7 KB (~3.9k tokens) of context on everydefault-profile session. Non-fullprofiles now serve compact one-line descriptions (purpose + when-to-use + key args): default drops to ~4.5 KB, lean ~4.1 KB, minimal ~2.2 KB. Thefullprofile keeps the long docstrings for debugging. A budget test pins this so a docstring can't silently re-bloat every session.Recall responses are trimmed before they go over the wire.
recall/recall_smart/recall_deepdrop genuinely-null (None) top-level fields and cap each result's content atmcp.max_item_chars(default 600 - generous, so normal facts are untouched; only pathologically long items shrink). Gated bymcp.compact_responses(default on). Structural fields (results,lessons) and 0/False values are always kept.
Added (MCP token diet - Phase D)
pmb mcp perf- per-tool latency (p50/p95), error rate and client-timeout count from themcp_callstable, so "did the token diet / daemon make tools faster" is a number, not a feeling.pmb connectalready selects theleantool profile when it installs hooks (the read-status tools the hooks cover are dropped), which now also benefits from the smaller descriptions.
Added (language packs - Phase C2/C3)
Adding a language is now one YAML file. PMB's lexical fast-paths (stopwords, function-words, verb synonyms, attribute aliases, first-person markers) shipped covering EN/RU/UK only. A language pack (
$PMB_HOME/lang/<code>.yaml) extends them to any language with no code changes. The EN/RU/UK lists stay in code as the floor and packs are extend-only, so a workspace with no pack files behaves byte-for-byte as before (pinned by a parity test). Built-in German and Spanish templates ship;pmb lang list / enable / disable / detectmanage them.detectsamples the corpus and SUGGESTS packs but never enables one silently - auto-activation by script would pollute (German and English share the Latin alphabet), so enabling is an explicit opt-in. Seedocs/adding-a-language.md.Offline keyed-fact extraction is now pack-aware (C4). The first-person prefilter that gates the offline LLM keyed-suggestion pass recognises the user in an enabled language (German "ich"/"mein" passes once
deis on), so keyed extraction works for packed languages too - third-party facts are still rejected.
Changed (faster cold start - Phase D follow-up)
pmb warmupsuggestsfastembedwhen the model cold-load is slow (>10s), a lower-RAM, faster-starting backend for the same multilingual model family (with the requiredpmb reindexcaveat). The warmup message also now points atpmb daemon startfor warm hook recall (the daemon shipped in 0.6.0).
Fixed (Unicode-correct tokenization - Phase C1)
Tokenizers no longer silently drop non-EN/RU letters. The keyed-fact label normalizer, the PAMVR token/proper-noun extractors, the vocabulary miner, and the sentence splitter used Latin+Cyrillic-only character classes (
[^0-9a-zа-яё],[a-zA-Zа-яА-Я],[A-ZА-ЯІЇЄҐ]…) that deleted German umlauts, Spanish ñ, Turkish letters, Greek, CJK - and even Ukrainian і/ї/є/ґ (so "Львові" tokenized as "львов"). They are now Unicode-aware (\w/str.isupper/casefold), provably byte-identical on EN/RU (a parity test pins this against the old regexes) and additive for every other script; proper-noun detection keeps its capital-word shape so acronyms still don't match. NOTE: this changes tokenization of Ukrainian and other non-EN/RU content already in a workspace - runpmb reindexto align the BM25 index with the corrected tokenizer.
Added (persistent memory daemon - Phase B)
pmb daemon- a persistent warm memory process. It holds ONE warm Engineembedding model + LanceDB so hook-based auto-recall finally gets REAL semantic recall instead of the per-process cold skip (
RECALL_COLD_SKIP).pmb daemon startspawns it detached,status/stop/restartmanage it. It is the same streamable-http MCP server with three internal routes (/internal/health,/internal/hook/prepare-context) mounted via fastmcp'scustom_route, behind a per-start bearer token ($PMB_HOME/daemon.token).
Hooks are now daemon clients with a hard cold fallback.
pmb prepare-contextasks the warm daemon first (localhost, ~0.6s timeout) and falls back to the existing in-process cold path the instant the daemon is absent or a version mismatch is detected - behaviour is unchanged when no daemon runs. When the cold path runs anddaemon.autostartis on (default), a daemon is spawned detached (rate-limited) so the NEXT message is warm.Idle exit. The daemon exits after
daemon.idle_exit_min(default 120) minutes with no request so it doesn't hold ~400MB forever; the next message autostarts a fresh one.
Fixed (durability + observability - Phase B)
record_batch_asyncis crash-safe via a durable outbox. The batch is persisted to awrite_outboxSQLite table SYNCHRONOUSLY before returning, then replayed by a background drainer; a crash between accept and write loses nothing (recover_outbox()replays leftovers on the next start). The old fire-and-forget daemon-thread path - which dropped items on process death - is kept only behindwrite.outbox=False. Gated ON by default.Swallowed exceptions leave a breadcrumb. A new
error_logtable + thepmb.core.errloghelper replace several bareexcept: passsites (negation tombstone, suggested-key tagging, declutter apply, outbox drain) so a silently-degrading path shows up inpmb doctor("Recent errors (24h)") instead of being invisible.
[0.6.0] - 2026-06-09
Fixed (keyed-memory correctness - Phase A)
Negation detection no longer archives facts about OTHER people. The detector previously checked a user cue and a negation INDEPENDENTLY anywhere in the text, so "I learned that Alice no longer lives in Paris" was read as the USER negating their own city - and recording the user's real city then auto-archived Alice's fact. The user subject must now sit immediately before the negated verb, evaluated per sentence. Third-party and possessive-chain forms ("my sister doesn't work at Google", "my sister's employer is unknown") return None.
Offline keyed-state suggestions can no longer mislabel a third party as the user.
suggest_keyed_from_llmgained three gates: a first-person prefilter before the LLM is called, an explicitsubject=="user"field the LLM must return, and exclusion ofsuspect_junk-flagged facts. "Alice relocated to Berlin" can never becomeuser::city.Offline LLM passes are now wall-clock bounded. A shared
LLMBudget(configllm.offline_max_calls=40,llm.offline_budget_s=120) caps the WHOLE pass, not just a single call - keyed suggestions and the declutter judge can no longer run for many minutes on a slow local model.hometownis a separate key from currentcity. "I'm from Kyiv" no longer overwrites "I live in Tampa" - origin and current residence are distinct keyed attributes.pmb declutterstops treating short facts as junk. The<8 chars → junkrule archived real memories likeO+,HIV+,ADHD,Tampa. Short non-stopword facts are now surfaced asshort_reviewand excluded from--applyunless--aggressiveis passed; keyed values are never near-empty candidates.Duplicate resolution keeps the most valuable copy. Exact-duplicate archiving previously always kept the newest; it now keeps the copy with the highest importance, then access count, then recency, and stamps the archived copies with
duplicate_of.pmb consolidateruns the keyed-suggestion pass even with zero clusters, and the command's--backend/--modelnow reach that pass (previously it returned early on quiet workspaces and ignored the chosen backend).A freshly recorded name takes effect on the next recall. The user-name cache is marked dirty on a "My name is X" write instead of refreshing only every 25 events, and the per-recall
SELECT COUNT(*)is gone (a flag check on the common path) - important for a long-lived process.pmb warmupno longer over-promises. Its message now states that warmup only warms the current process; hook-based auto-recall stays SQL-only until the persistent daemon ships.
Fixed (Phase 0.6.0 baseline - previously merged)
No personal-name or test-name literals leak into ranking. The recall identity-marker boost no longer hardcodes a name - it is driven by the mined user-name cache, and the router's identity-intent detection matches the user's OWN learned names dynamically instead of a baked-in literal.
DEFAULT_NAMED_ENTITIES(which leaked benchmark names like alice/stripe/adyen into every production query) is now empty; real entities come from the dynamic proper-noun extractor + the user-name cache.Negation / "unknown" facts no longer linger as stale noise. Once a positive keyed value exists (e.g.
user::city = Tampa), older facts that negate or mark-unknown that attribute ("the user does not currently live in Warsaw; current city is unknown") are archived (superseded_by, archive-only). Runs at write time and as apmb repair-keyedpass. Gated bykeyed.archive_obsolete_negations(default ON). Lessons and pinned events are never touched.The CLI is English-only. Russian docstrings/examples that leaked into
--helpare translated; functional multilingual trigger templates (pmb connect) are unchanged.Recall never crashes on an empty/degenerate BM25 corpus.
rank_bm25divides by zero when the corpus has no terms (a fresh-workspace recall before the embed/index queue drained); search now guards it and falls back to vector-only ranking instead of raising. Also stabilized 4 long-flaky tests (temporal proximity, rehearse cap, auto-consolidate, MCP e2e) so the full suite is deterministic.
Added
Status dashboard. Bare
pmb(no subcommand) prints a workspace status panel - active workspace + how it resolved, storage sizes, event counts, running MCP servers, embedding warm/cold.pmb --helpis unchanged. Slow paths (recall/rememberfirst run,index,migrate-workspaces,compact,declutter) show a loading spinner.Workspace switching.
pmb workspace use <name>persists a default workspace (resolution: env → project.pmb/workspace.yaml→ saved default → git/cwd),pmb workspace currentshows the active one + which rule won, andpmb workspacesmarks the active one. Fully additive - setups that never runuseresolve exactly as before.Time-based forgetting.
pmb decay --archive-coldarchives facts/activities that are old AND never recalled AND low-value (never pinned/keyed/lessons/ goals). Dry-run by default; configdecay.archive_cold_days(90),decay.archive_cold_max_importance(0.25).Junk sweeper.
pmb declutterarchives test artifacts, near-empty/stopword content, exact duplicates, and obsoleted negation tombstones; optional--llmjudge (bounded, capped, circuit-broken) reviews borderline low-value facts. Dry-run + archive-only.Plans become goals. A future-intent fact ("remember we'll do X next") is routed to a goal: MCP docstrings + the
pmb connecttemplate carry the rule,record_batchaccepts{"type": "plan"}(a goal withkind=plan), andrecord_factflags forward-looking phrasing withmetadata.suggest_goal(a hint - never an auto-convert). Newpmb goals/pmb goals done <ulid>.Offline LLM keyed-state tier. During consolidation, an offline bounded LLM proposes keyed current-state (
{attribute, value, negation, confidence}) for facts the cheap regex missed; confidence≥0.8 positives upsert via the canonical keyed path, weaker ones are taggedmetadata.suggested_key. Gated byconsolidate.suggest_keyed; never on the recall hot path.Per-deployment reference data. Optional
PMB_HOME/reference.yamlextends attribute aliases / known techs / stopwords / function-words (extend-only) and overrides kind priorities - no Python edits. Missing file = identical behaviour.
Changed
Write-time quality gate (opt-in,
write.quality_gate, default OFF). When on, suspected-junk facts are flagged (quality_flag=suspect_junk) and capped at importance 0.2 and excluded from keyed promotion - never rejected.
[0.5.0]
Fixed
recall_smart no longer hangs the interactive path. It is bounded by an overall wall-clock deadline (
recall.smart_deadline_ms, default 15s) with a local-only fast path - it never resolves an LLM / spawns the Claude CLI on the foreground path (the cause of 120s timeouts). LLM query-decomposition is opt-in (recall.smart_allow_llm) and, when on, is clamped to the remaining budget. A new explicitrecall_deeptool/method runs the slow, thorough pass on demand. Each pack carries anescalationfield (stages run + why it stopped) so callers don't fan out redundant recalls.Stale personal attributes no longer out-rank the current value. Keyed-fact attribute names are canonicalized (
city/current_city/current_city_2026/lives_in/город→ one key), so an update supersedes the old value instead of creating a competing key. Old values are kept as history.Current-state facts become keyed facts. A plain "I now live in X" / "сейчас живу в X" is detected (conservatively, with a negation guard so a "do not say X" instruction is never promoted) and upserts the matching keyed attribute.
Added
pmb repair-keyed- two-pass keyed-fact repair: promote current-state facts buried in plain text into keyed facts, then collapse alias/duplicate keys onto one canonical value. Archive-only, dry-run by default.pmb migrate-workspaces- merge a per-project workspace into a unified memory, taggedproject=<name>; the source is left intact (reversible). Therecalltool gains an optionalprojectfilter over the one memory.pmb mcp status+ a running-server registry - see how many MCP servers are live and their memory; an HTTPpmb mcp serverefuses to start a second instance on a live host:port (per-session servers each load the model + LanceDB).Backend circuit breaker - a repeatedly-failing/slow deep backend is temporarily disabled for the interactive path (
recall.breaker_threshold,recall.breaker_cooldown_s); state exposed viabreaker_status.Performance dashboard now records & shows per-call recall_smart stages, client-timeout (vs server completion), backend, and cache hit/miss.
Changed
New (additive) config keys:
recall.smart_deadline_ms,recall.smart_allow_llm,keyed.auto_detect_current_state,recall.breaker_threshold,recall.breaker_cooldown_s. Defaults preserve prior behaviour.MCP tool profiles: default now 30 tools, lean 26 (added
recall_deep).
[0.4.0]
Added
Ambient memory (auto-write). PMB journals the agent's work even when it forgets to call
record_batch. A PostToolUse hook logs significant actions (pmb track-action); a Stop hook synthesizes one activity entry per turn only if the agent didn't record its own (pmb autowrite), gated by a git-free, outcome-based importance score (tests passed / failure fixed / deploy ran - not raw file count). Every entry is taggedsource=autowrite, shown as auto, and removable withpmb forget-auto. Works on Claude Code (hooks), OpenAI Codex (rollout parse,pmb codex-notify), and MCP-only hosts (git observer,pmb ambient-watch).pmb hooks capabilitiesreports per-agent support. ON by default (autowrite.enabled).leanMCP tool profile (25 tools): the default set minus the read-status browse tools a host hook already covers, set automatically bypmb connect claude-codeso the agent isn't offered slow MCP versions of what auto-recall / session-restore already inject for free.Lesson follow-through
not_applicablestate. The Stop-hook followcheck classifies a surfaced lesson with zero overlap with the turn's work as not-applicable and excludes it from the adherence denominator, instead of counting it as a phantom "not followed". Follow-rate is now over applicable surfaces - it reflects relevant lessons, not surfacing volume.Opt-in semantic lesson tier (
recall.lesson_semantic, experimental, off by default): cosine over the existing embeddings to catch paraphrase / cross-lingual lesson matches the lexical gate can't.
Changed
Lesson-surfacing precision. Surfacing uses a shared tokenizer + stopword set (
pmb.core.text_match, symmetric with followcheck): generic and filesystem-path noise is filtered, and a relevance gate (recall.lesson_min_overlap, default 1) replaces the old "any shared 3-char word" match. Auto-recall also skips non-message blocks (task-notifications / system reminders). Materially cuts irrelevant surfacing on real workspaces.graph.async_llm(default on): LLM entity extraction runs in a background worker off the write hot path, so records return instantly;pmb regraphis the backstop.
Fixed
leanprofile was silently ignored - the post-registration tool filter fell back to the full default set; it now selects the lean set correctly.Engine.close()drains the async batch-write, deferred-graph, and touch queues (each bounded) so in-flight work isn't dropped on shutdown.Persistent WAL no longer forced on non-PMB databases - the global
sqlite3.connectpragma patch appliesjournal_mode=WALonly to PMB-owned DBs (underPMB_HOME/ namedevents.sqlite/:memory:); third-party connections in the same process get only the ephemeral pragmas.Hyphenated compound words (
lesson-surfacing) are matched by their parts.SCHEMA_VERSIONbumped to 6 to match the shippedlesson_surfacestable.
[0.3.0]
Added
Auto-recall, session-restore, and lesson follow-through lifecycle hooks; optional HTTP transport with bearer-token auth for shared/team workspaces.
[0.2.1]
Added
pmb learn "..."+pmb lessons- procedural memory: teach PMB durable lessons ("this repo uses pnpm, never npm") that surface via the hybrid + predicate-aware ranker, and review them.pmb learn --failed/ negative memory - record failures ("numpy 2.x broke lancedb") that recall flags with a warning so they're not repeated.pmb distill+ auto-distill on session end - LLM extracts durable lessons/failures from a session's events automatically (zero-command whenlessons.auto_distill_on_session_endis on). Off the recall hot path.Lesson-intent boost - on how-to/convention queries, lesson & failure memories are gently boosted so the agent applies them. Scoped to lesson/failure events only, so it cannot affect recall on datasets without them (LoCoMo stays exactly 94.5%). Config:
recall.lesson_boost.Trust signals in recall - source attribution, source-derived confidence (high/med/low), and a freshness/staleness flag, all display-only.
pmb auditmemory-health - counts of lessons, failures, stale, low- confidence, and conflicting memories.pmb note "..."- instant memory capture from the terminal, no agent.pmb audit- "what does PMB know about me?": a grouped, read-only view of everything stored, by type and by source.Source attribution on recall - every hit shows where it came from ("from: chatgpt · Project planning", "from: note (cli)", etc.). Trust feature.
pmb watch <file|dir>- auto-capture: new paragraphs in a notes file or folder (e.g.~/journal.md) get ingested as memory; content-hash dedup.6 more agent integrations (9 total).
pmb connectnow wires windsurf, gemini, vscode, zed, opencode and continue in addition to claude-code / cursor / codex.pmb connect --listshows every agent and its config path;--config-pathoverrides the location.Git-backed workspace sync.
pmb workspace init|push|pull|status|cloneversions and syncs a workspace to any git remote - cross-device, team memory, and backups with no server.Encrypted workspace bundles.
pmb workspace export|importpacks a workspace into a single authenticated-encrypted file (scrypt + AES/HMAC), safe to store even on a public remote. Needspip install 'pmb-ai[crypto]'.Memory import.
pmb import chatgpt|claude|mem0|markdown <path>brings existing history into a fresh workspace; the entity graph rebuilds after.pmb why "<query>". Explains recall ranking with a full trace of which PAMVR rules fired and each multiplier - no more black box.Pluggable embedders.
embedding.backendnow also acceptsollamaandopenai. A dimension guard refuses to mix embedders of different vector sizes in one workspace (which would corrupt recall).scripts/benchmarks/vs_mem0.py. Reproducible head-to-head: same data, same queries, same scorer. PMB measured live; mem0 measured with--with-mem0or shown from published numbers (clearly labelled).
Fixed
PyPI page now renders the README logo + screenshots (absolute image URLs).
LanceDB table is created with the active embedder's real vector dimension instead of a hardcoded 384, enabling non-default embedders on fresh workspaces.
Notes
57 new regression tests. The headline 94.5% LoCoMo recall@10 and 70ms p50 are unchanged - the hardening suite verifies no recall regression.
[0.2.5]
Onboarding, agent logging, cross-platform & docs
pmb setup- guided first-time setup: detects your agent, asks active vs conservative logging, and wires PMB in one go (--yesfor non-interactive).pmb connect <agent> --active- proactive-logging rules: the agent records its own decisions / done / lessons / failures / goals during coding, not just on "remember". Recall stays lazy; the conservative default is unchanged.Pro config:
agent.log_decisions/.log_completed/.log_lessons/.log_failures/.log_goalstoggle exactly what gets logged, andagent.apply_lessonsenables the self-improvement loop - recall + apply past lessons/failures before a task so the agent gets better at the project over time. Set viapmb config set/pmb tune, then re-runpmb connect <agent> --activeto regenerate the rules.
pmb overview "<topic>"+ MCPoverviewtool - a structured "what do I know about X?" synthesis (key facts & decisions, lessons, failures, goals, a timeline, related topics) from memory, no LLM, fully local. The MCP tool lets an agent get up to speed on a project/feature in ONE call instead of several recalls. Config:overview.max_events.agent.active_mode- auto-logging switch: when on,pmb connect/pmb setupinstall the proactive rules by default (no--activeneeded).Session continuity (
pmb session brief+ MCPsession_brief) - a digest of what was decided / done / learned this session, so an agent can re-orient after its OWN context window compacts in a long session instead of re-asking the user what it already did. Active-mode rules tell the agent to use it (agent.context_continuity); fallback windowsession.brief_minutes.docs/COMMANDS.md- full command reference grouped by task, with examples and a clear mark of which commands run fully offline vs need an LLM backend.macOS in CI - a macOS (arm64) job added to the test matrix so the "runs on macOS" claim is tested, not just asserted.
New tests:
tests/test_connect_active.py(10: active rules + agent detection).
MCP correctness: new tools exposed + session_brief fixes
End-to-end MCP tests (tests/test_mcp_e2e.py, via the fastmcp in-memory client)
drive the real tool routing for the new features on a long-chat scenario, and
caught three bugs that made session_brief / overview unusable from an agent:
session_briefandovervieware now actually exposed. The post- registration tool-profile filter (minimal / default whitelists) was silently dropping both new tools, so an agent that called them got "Unknown tool". Addedsession_briefto the minimal profile andoverviewto the default.session_briefnow covers the whole session, not just activities. Onlyrecord_activityauto-binds an event to the session; facts / goals / lessons do not, so the old tag-only scope dropped them once a session existed. It now scopes as a union: tagged with the session or recorded since the session began. (This is why a long chat's lessons/goals went missing from the brief.)session_briefclassifies decisions / done correctly. It keyed offmetadata.kind, butrecord_activitystores the kind underactivity_kind, so every decision / completed item fell into "other". It now reads both.Tool-profile filter is event-loop-safe. It used
asyncio.run(list_tools()), which raised (and left an un-awaited coroutine) when the server was built inside a running loop (in-memory client / embedded host). It now detects a running loop and skips the introspection cleanly; the stdio server path - where gating actually matters - is unchanged.
Tests: tests/test_mcp_e2e.py (3: tool exposure, long-chat session_brief,
recall answer-quality + lessons + overview).
Answer-ready recall output + temporal validity windows
Three product-code levers targeting end-to-end answer quality (the gap between strong retrieval and the final answer), informed by per-question J-score failure analysis. All additive / out of the recall ranking hot path - retrieval recall@10 and latency are unchanged.
Resolved date in every recall result.
RecallResult.to_dict()now includes a human-readabledate, resolved as event_time (the date the content refers to) -> session date -> creation time. An agent can answer "when …?" without epoch math and anchors relative dates to the EVENT, not to "today".to_text()(prompt injection) uses it too.More write-time atomic-fact patterns (no-LLM regex): relationship status ("X is single") and origin ("X moved from Y"). Still opt-in via
consolidate.write_atomic_facts(default off); turning it on by default is gated on a LoCoMo regression run.Temporal validity windows + as-of query.
record_keyed_factnow stampsvalid_fromon the new value andvalid_toon each superseded value, andEngine.keyed_fact_as_of(subject, attribute, at_time)returns the value that was current at a past time (Zep-style "what was true in March") - prior values stay queryable instead of just being archived.
Tests: tests/test_jscore_levers.py (10).
[0.2.4]
LLM-as-judge (J-score) eval harness improvements
The --judge mode of scripts/benchmarks/benchmark_locomo.py reports a
J-score (LLM-as-judge) - the end-to-end metric mem0 / Zep / Letta publish,
where a reader LLM answers from retrieved context and a judge LLM grades the
answer against gold. This release makes that harness fair and debuggable:
Full reader context. Per-chunk cap raised 1500 -> 6000 and total 6000 -> 20000. Previously the answer turn could be truncated out of the reader's view, capping the J-score far below retrieval recall@10.
Reader prompt now scans every numbered chunk (not just the first) and resolves relative dates step by step.
Per-question failure logging (question / gold / prediction / verdict) in the output JSON, so a miss can be attributed to reader vs retrieval vs judge.
EVAL-harness only - no product / recall code is touched, so recall@10 and latency are unchanged. The J figure is still measured on small samples; a full multi-conversation run (with a fast LLM backend) is needed for a publishable number.
Local-use & own-your-data commands
New CLI surface for using PMB as a personal memory you fully own and organize offline. All of these are CLI + display + write-layer only - none touch the recall hot path, so the 94.5% LoCoMo recall@10 and ~70ms p50 are unchanged (verified: full hardening regression suite green).
pmb timeline- chronological, day-grouped view of your memory (--days,--type,--newest-first).pmb insights- personal analytics: totals, type breakdown, growth per week, top topics (entity graph), and lessons/failures/goals/pinned counts.pmb digest [today|week|month]- quick recap of recent memories (--days N).pmb export [--format markdown|json] [--out FILE]- dump all memory to readable Markdown or JSON (--include-archived). Plain/unencrypted; for an encrypted portable bundle usepmb workspace export.pmb forget-topic <topic>- archive every memory about a topic in one command (--dry-run,--yes,--in content|tag|source). Reversible (archived, not deleted).TTL / expiry -
pmb ttl <ulid> 30d(orclear), a--ttloption onnote/learn/fact, andpmb prune-expiredto sweep. Enforced only by the explicit sweep, never inside recall.Tags / collections -
pmb tag,pmb untag,pmb tags, andpmb tagged <tag>for local organization.pmb reminders- surfaces open goals that are overdue or due soon (--within N,--all).pmb snapshot create|list|restore- local, offline, timestamped workspace snapshots (WAL-checkpointed copy; restore auto-backs-up current state first).
New store helpers: EventStore.set_metadata (annotate an event without
touching its content or embeddings) and EventStore.list_all (export /
analytics, optionally including archived rows). 34 new tests in
tests/test_local_features.py.
Hardening pass 2 - lazy LanceDB + use-case clarity
pmb statsand friends now run in ~1 s (was ~14 s). The single biggest user-facing cost wasimport lancedbitself: on Windows it pulls in pyarrow + torch and takes ~22 s to import.HybridSearch.__init__triggered that import for every CLI command, even ones that never touch vectors. Fix:HybridSearchdeferslancedb.connect(...)and the table-open to a lazy_tableproperty;Engine.__init__no longer eagerly callsreload_bm25(). The cost is now paid on the firstrecall()or write that actually needs vector search.README "What gets stored, when" gets a
Which features help which use casetable. Honest mapping of feature flags to workloads (multi-hop, narrative, temporal, code, multilingual, etc.) - so contributors don't assume every feature must boost LoCoMo recall.All 88 core tests + 9 smoke tests still pass.
Hardening pass 1 - import hygiene + test foundation
Lazy top-level imports.
import pmbno longer pulls in LanceDB, sentence-transformers, numpy, rank_bm25, fastmcp, yaml, torch or transformers. Heavy attributes (Engine,Workspace,detect_workspace) are exposed via PEP 562__getattr__and loaded on first access. Measured: bareimport pmbis now 2.4 ms (was ~14 s when the engine was eagerly imported). Same treatment applied topmb.core.tests/conftest.pyadded with shared fixtures (tmp_pmb_home,tmp_workspace_dir,isolated_engine) and asys.pathfallback so new tests don't need the boilerplate.tests/test_lightweight_imports.pyadded - 9 smoke tests that spawn fresh interpreters and assert which heavy modules are loaded after specific imports. If a future change re-introduces an eager heavy import atpmb/__init__.pyit will fail this suite.No behaviour change. All 88 core tests (the
make testset used in CI) still pass;from pmb import Enginestill works.
Recall ablation findings + default changes
Ran a full-system ablation across 19 retrieval components on LoCoMo conv-26/30/41 (see scripts/benchmarks/ablation_full.py). Key findings:
recall.typo_correction = Truewas hurting recall by ~6.2 points. The Levenshtein-≤2 fuzzy rewriter was "correcting" correctly-spelled tokens into similar-looking but wrong entity names. Default flipped toFalse. Existing per-workspace overrides are unaffected.BM25-heavy fusion outperformed the symmetric default.
recall.bm25_weightraised0.5 -> 0.7. Vector-only retrieval loses 18 points on this dataset; the embedding channel adds only marginal signal.Net effect on the full 10-conversation LoCoMo benchmark: 91.6 % -> 94.1 % evidence-recall@10 (+2.5 pp, every conversation improved, range now 91.2-96.2 %).
Twelve of nineteen ablated features show 0.000 delta on LoCoMo: tiers, causation walk, arc expansion, collapse-reflections, reflection-to-edges, predictive cache, code-AST, LRU cache, multi-entity bonus, PPR, adaptive routing, spreading activation, temporal. These are not removed - some are designed for long-term dynamics that LoCoMo doesn't probe - but the README and docs no longer claim they carry the benchmark number.
Cross-encoder reranker (
recall.rerank = True) regresses 17 points and adds 845 ms p50. Recommendation removed from default setup; flag is still available as experimental.
See scripts/benchmarks/ablation_full.py and docs/HARDENING_NOTES.md for the raw data and methodology.
[0.1.0] - Initial public release
Highlights
Single-file install:
pip install -e .exposespmbon$PATH.91.6 % evidence-recall@10 on LoCoMo full 10-conversation run (vs published mem0 / Letta / Zep numbers of 70-80 %).
90-140 ms p50 recall latency, 2 ms async writes.
13 semantic layers, 5 access paths, 3 tiers - every layer optional and configurable.
Web dashboard + 5-tab terminal TUI for inspection.
MCP server for Claude Code, Codex CLI, Cursor.
Optional Ollama integration for fully-local LLM ops (consolidation, dedup verify, pmb-chat).
Architecture decisions worth knowing
Local-first. SQLite + LanceDB on disk; no daemon, no service, no network.
Lazy-by-default agent prompt. PMB is OFF until an explicit trigger ("remember", personal fact, "what did I…"). General Q&A bypasses PMB entirely.
Async writes (fire-and-forget MCP).
record_batchreturns in ~2 ms; embedding + LanceDB indexing happen in a background thread.BM25 fallback for cold reads. First
recallafter process start returns text-match results in ~100 ms while the sentence-transformers model finishes loading.Multi-layer dedup. L1 exact (5 ms) + L2 cosine ≥ 0.92 (50 ms) at write time; L2.5 borderline queue for LLM-verified merges; L3 dashboard review tab for ambiguous pairs.
Conservative defaults. False-merge risk minimised: never merges across event types, threshold 0.92 leaves a safe gap.
Tools and surfaces
pmb tui- five tabs: Memory, Recall, Stats, Dedup, Tunepmb dashboard- HTTP dashboard on :8765 with Graph, Events, Performance, Duplicates, Recall Debugpmb tune- settings-only TUI (67 knobs)pmb ollama- health, install/use models, smoke testpmb connect codex | claude | cursor- wires MCP into the agent's config and rules filepmb dedupe/pmb regraph/pmb prune-graph- maintenance ops
Settings (67 across 9 categories)
recall (36), consolidate (9), dedup (6), chat (5), decay (3), embedding (3), feedback (2), ollama (2), mcp (1). All exposed in TUI Tune tab, CLI pmb config, and dashboard.
Known limits
Single-machine. No cross-device sync.
Cold first recall after process start blocks on model load if the BM25 fallback path is disabled.
Code-AST extraction is Python-only (regex fallback for broken / partial code).
Dashboard and TUI assume one workspace at a time.
512 files · 496 not served here
- .claude/launch.json (not served here)
- .dockerignore (not served here)
- .editorconfig (not served here)
- .github/ISSUE_TEMPLATE/bug_report.md (not served here)
- .github/ISSUE_TEMPLATE/feature_request.md (not served here)
- .github/dependabot.yml (not served here)
- .github/pull_request_template.md (not served here)
- .github/release-drafter.yml (not served here)
- .github/workflows/ci.yml (not served here)
- .github/workflows/codeql.yml (not served here)
- .github/workflows/publish-npm.yml (not served here)
- .github/workflows/publish.yml (not served here)
- .github/workflows/release-drafter.yml (not served here)
- .gitignore (not served here)
- ATTRIBUTION.md
- AUTOGINEER-RUNS.md
- CHANGELOG.md
- CITATION.cff (not served here)
- CODE_OF_CONDUCT.md
- CONTRIBUTING.md
- LICENSE
- MANIFEST.in (not served here)
- Makefile (not served here)
- NOTICE
- README.md
- SECURITY.md
- compose.yaml (not served here)
- docker/Dockerfile (not served here)
- docker/README.md (not served here)
- docker/compose.gpu.yaml (not served here)
- docker/data/.gitkeep (not served here)
- docs/404.md
- docs/HARDENING_NOTES.md
- docs/PROJECT_REVIEW.md
- docs/README.md
- docs/ROADMAP.md
- docs/assets/PMB_LOGO_BLACK.svg (not served here)
- docs/assets/PMB_LOGO_BLAC_WHITE.svg (not served here)
- docs/assets/PMB_LOGO_WHITE.svg (not served here)
- docs/assets/before-after.svg (not served here)
- docs/assets/dashboard-map.png (not served here)
- docs/assets/dashboard-timeline.png (not served here)
- docs/assets/logo.png (not served here)
- docs/assets/pmb-setup-poster.png (not served here)
- docs/assets/pmb-setup.mp4 (not served here)
- docs/assistant-integration-notes.md
- docs/concepts/architecture.md (not served here)
- docs/concepts/core-engine.md (not served here)
- docs/concepts/design-and-tech.md (not served here)
- docs/concepts/how-it-works.md (not served here)
- docs/concepts/index.md (not served here)
- docs/concepts/measuring-impact.md (not served here)
- docs/concepts/memory-model.md (not served here)
- docs/concepts/privacy-and-security.md (not served here)
- docs/contributing/adding-a-language.md (not served here)
- docs/contributing/index.md (not served here)
- docs/guide/SETUP_OLLAMA.md (not served here)
- docs/guide/TEAM.md (not served here)
- docs/guide/backups.md (not served here)
- docs/guide/dashboard.md (not served here)
- docs/guide/deleting-memories.md (not served here)
- docs/guide/getting-started.md (not served here)
- docs/guide/index.md (not served here)
- docs/guide/troubleshooting.md (not served here)
- docs/guide/usage.md (not served here)
- docs/javascripts/mermaid-init.js (not served here)
- docs/javascripts/pmb-anim.js (not served here)
- docs/reference/COMMANDS.md (not served here)
- docs/reference/configuration.md (not served here)
- docs/reference/index.md (not served here)
- docs/reference/mcp-tools.md (not served here)
- docs/stylesheets/extra.css (not served here)
- mintlify/concepts/architecture.mdx (not served here)
- mintlify/concepts/core-engine.mdx (not served here)
- mintlify/concepts/how-it-works.mdx (not served here)
- mintlify/concepts/measuring-impact.mdx (not served here)
- mintlify/concepts/memory-model.mdx (not served here)
- mintlify/concepts/privacy-and-security.mdx (not served here)
- mintlify/contributing/adding-a-language.mdx (not served here)
- mintlify/contributing/contributing.mdx (not served here)
- mintlify/contributing/roadmap.mdx (not served here)
- mintlify/docs.json (not served here)
- mintlify/favicon.svg (not served here)
- mintlify/guides/connect.mdx (not served here)
- mintlify/guides/dashboard.mdx (not served here)
- mintlify/guides/deleting-memories.mdx (not served here)
- mintlify/guides/ingest.mdx (not served here)
- mintlify/guides/ollama.mdx (not served here)
- mintlify/guides/team.mdx (not served here)
- mintlify/guides/troubleshooting.mdx (not served here)
- mintlify/images/before-after.svg (not served here)
- mintlify/images/dashboard-map.png (not served here)
- mintlify/images/dashboard-timeline.png (not served here)
- mintlify/images/setup-poster.png (not served here)
- mintlify/introduction.mdx (not served here)
- mintlify/logo/black.svg (not served here)
- mintlify/logo/white.svg (not served here)
- mintlify/quickstart.mdx (not served here)
- mintlify/reference/cli/config.mdx (not served here)
- mintlify/reference/cli/hooks.mdx (not served here)
- mintlify/reference/cli/manage.mdx (not served here)
- mintlify/reference/cli/read.mdx (not served here)
- mintlify/reference/cli/setup-connect.mdx (not served here)
- mintlify/reference/cli/write.mdx (not served here)
- mintlify/reference/configuration.mdx (not served here)
- mintlify/reference/mcp-tools.mdx (not served here)
- npm/README.md (not served here)
- npm/bin/bootstrap.js (not served here)
- npm/bin/install.js (not served here)
- npm/bin/pmb-ai.js (not served here)
- npm/package.json (not served here)
- pyproject.toml (not served here)
- requirements-dev.lock (not served here)
- scripts/README.md (not served here)
- scripts/_bench_data.py (not served here)
- scripts/benchmarks/_ab_pattern_split.py (not served here)
- scripts/benchmarks/ab_all.py (not served here)
- scripts/benchmarks/ab_compression.py (not served here)
- scripts/benchmarks/ab_compression_live.py (not served here)
- scripts/benchmarks/ab_outcome_weight.py (not served here)
- scripts/benchmarks/ab_outcome_weight_ctx.py (not served here)
- scripts/benchmarks/ab_pamvr_locomo.py (not served here)
- scripts/benchmarks/ab_surprise_gate.py (not served here)
- scripts/benchmarks/ablation_full.py (not served here)
- scripts/benchmarks/ablation_tiers.py (not served here)
- scripts/benchmarks/bench_full_flow.py (not served here)
- scripts/benchmarks/bench_qa_scenarios.py (not served here)
- scripts/benchmarks/bench_user_flow.py (not served here)
- scripts/benchmarks/benchmark.py (not served here)
- scripts/benchmarks/benchmark_cross_event.py (not served here)
- scripts/benchmarks/benchmark_locomo.py (not served here)
- scripts/benchmarks/big_cross_chat_test.py (not served here)
- scripts/benchmarks/confirm_new_defaults.py (not served here)
- scripts/benchmarks/e2e_demo.py (not served here)
- scripts/benchmarks/e2e_ru_uk_demo.py (not served here)
- scripts/benchmarks/full_validation.py (not served here)
- scripts/benchmarks/mega_stress_test.py (not served here)
- scripts/benchmarks/perf_bench.py (not served here)
- scripts/benchmarks/quality_demo.py (not served here)
- scripts/benchmarks/replay_repeat_guard.py (not served here)
- scripts/benchmarks/research_top1.py (not served here)
- scripts/benchmarks/scenario_test.py (not served here)
- scripts/benchmarks/stress_3000.py (not served here)
- scripts/benchmarks/vs_mem0.py (not served here)
- scripts/calibrate_anchors.py (not served here)
- scripts/codeql_local.sh (not served here)
- scripts/debug/analyze_failures.py (not served here)
- scripts/debug/analyze_failures_all.py (not served here)
- scripts/debug/debug_judge.py (not served here)
- scripts/debug/debug_judge2.py (not served here)
- scripts/debug/debug_multihop.py (not served here)
- scripts/debug/profile_recall.py (not served here)
- scripts/demos/demo_graph.py (not served here)
- scripts/demos/demo_seed.py (not served here)
- scripts/demos/e2e_test.py (not served here)
- scripts/hooks/pre-commit (not served here)
- scripts/install-dev-hooks.sh (not served here)
- scripts/precommit.sh (not served here)
- scripts/prewarm_models.py (not served here)
- scripts/test.sh (not served here)
- server.json
- src/pmb/__init__.py (not served here)
- src/pmb/agent_wrapper/PLAN.md (not served here)
- src/pmb/agent_wrapper/__init__.py (not served here)
- src/pmb/agent_wrapper/__main__.py (not served here)
- src/pmb/agent_wrapper/budget.py (not served here)
- src/pmb/agent_wrapper/loop.py (not served here)
- src/pmb/agent_wrapper/policy.py (not served here)
- src/pmb/cli/__init__.py (not served here)
- src/pmb/cli/__main__.py (not served here)
- src/pmb/cli/_common.py (not served here)
- src/pmb/cli/commands/__init__.py (not served here)
- src/pmb/cli/commands/ambient.py (not served here)
- src/pmb/cli/commands/capture.py (not served here)
- src/pmb/cli/commands/config.py (not served here)
- src/pmb/cli/commands/daemon.py (not served here)
- src/pmb/cli/commands/graph.py (not served here)
- src/pmb/cli/commands/health.py (not served here)
- src/pmb/cli/commands/hooks.py (not served here)
- src/pmb/cli/commands/index.py (not served here)
- src/pmb/cli/commands/lang.py (not served here)
- src/pmb/cli/commands/maintenance.py (not served here)
- src/pmb/cli/commands/manage.py (not served here)
- src/pmb/cli/commands/memo.py (not served here)
- src/pmb/cli/commands/resume.py (not served here)
- src/pmb/cli/commands/snapshot.py (not served here)
- src/pmb/cli/commands/track.py (not served here)
- src/pmb/cli/commands/workspace.py (not served here)
- src/pmb/cli/connect.py (not served here)
- src/pmb/cli/doctor.py (not served here)
- src/pmb/cli/hooks.py (not served here)
- src/pmb/cli/intro.py (not served here)
- src/pmb/cli/main.py (not served here)
- src/pmb/cli/ollama_cmd.py (not served here)
- src/pmb/cli/palette.py (not served here)
- src/pmb/cli/status_panel.py (not served here)
- src/pmb/config.py (not served here)
- src/pmb/core/__init__.py (not served here)
- src/pmb/core/ambient_log.py (not served here)
- src/pmb/core/circuit_breaker.py (not served here)
- src/pmb/core/embed_queue.py (not served here)
- src/pmb/core/encryption.py (not served here)
- src/pmb/core/engine/__init__.py (not served here)
- src/pmb/core/engine/ambient.py (not served here)
- src/pmb/core/engine/base.py (not served here)
- src/pmb/core/engine/batch.py (not served here)
- src/pmb/core/engine/dedup.py (not served here)
- src/pmb/core/engine/embed.py (not served here)
- src/pmb/core/engine/goals.py (not served here)
- src/pmb/core/engine/graph.py (not served here)
- src/pmb/core/engine/health.py (not served here)
- src/pmb/core/engine/lessons.py (not served here)
- src/pmb/core/engine/overview.py (not served here)
- src/pmb/core/engine/reasoning.py (not served here)
- src/pmb/core/engine/recall.py (not served here)
- src/pmb/core/engine/types.py (not served here)
- src/pmb/core/engine/write.py (not served here)
- src/pmb/core/errlog.py (not served here)
- src/pmb/core/events.py (not served here)
- src/pmb/core/git_sync.py (not served here)
- src/pmb/core/llm_budget.py (not served here)
- src/pmb/core/recall_cache.py (not served here)
- src/pmb/core/search.py (not served here)
- src/pmb/core/snapshots.py (not served here)
- src/pmb/core/sqlite_helper.py (not served here)
- src/pmb/core/text_match.py (not served here)
- src/pmb/core/workspace.py (not served here)
- src/pmb/dashboard/__init__.py (not served here)
- src/pmb/dashboard/server.py (not served here)
- src/pmb/dashboard/static/index.html (not served here)
- src/pmb/dashboard/viz.py (not served here)
- src/pmb/eval/__init__.py (not served here)
- src/pmb/eval/locomo_judge.py (not served here)
- src/pmb/graph/__init__.py (not served here)
- src/pmb/graph/entities.py (not served here)
- src/pmb/graph/expansion.py (not served here)
- src/pmb/graph/extractors_llm.py (not served here)
- src/pmb/graph/extractors_spacy.py (not served here)
- src/pmb/graph/persons.py (not served here)
- src/pmb/graph/ppr.py (not served here)
- src/pmb/graph/spreading.py (not served here)
- src/pmb/graph/store.py (not served here)
- src/pmb/health/__init__.py (not served here)
- src/pmb/health/adaptive.py (not served here)
- src/pmb/health/auto_consolidate.py (not served here)
- src/pmb/health/conflicts.py (not served here)
- src/pmb/health/consolidate.py (not served here)
- src/pmb/health/distill_lessons.py (not served here)
- src/pmb/health/earned_memory.py (not served here)
- src/pmb/health/feedback.py (not served here)
- src/pmb/health/multilingual_check.py (not served here)
- src/pmb/health/rehearse.py (not served here)
- src/pmb/health/self_test.py (not served here)
- src/pmb/health/slo.py (not served here)
- src/pmb/hookclient/__init__.py (not served here)
- src/pmb/hookclient/__main__.py (not served here)
- src/pmb/hooks/__init__.py (not served here)
- src/pmb/hooks/auto_recall.py (not served here)
- src/pmb/hooks/autowrite.py (not served here)
- src/pmb/hooks/codex_rollout.py (not served here)
- src/pmb/hooks/correction_capture.py (not served here)
- src/pmb/hooks/exploration_capture.py (not served here)
- src/pmb/hooks/followcheck.py (not served here)
- src/pmb/hooks/project_observer.py (not served here)
- src/pmb/hooks/semantic_intent.py (not served here)
- src/pmb/hooks/session_restore.py (not served here)
- src/pmb/ingest/__init__.py (not served here)
- src/pmb/ingest/importers.py (not served here)
- src/pmb/ingest/pdf.py (not served here)
- src/pmb/ingest/project.py (not served here)
- src/pmb/ingest/track.py (not served here)
- src/pmb/ingest/watch.py (not served here)
- src/pmb/lang/__init__.py (not served here)
- src/pmb/lang/anchor_calibration.json (not served here)
- src/pmb/lang/anchors.py (not served here)
- src/pmb/lang/packs/de.yaml (not served here)
- src/pmb/lang/packs/es.yaml (not served here)
- src/pmb/lang/packs/fr.yaml (not served here)
- src/pmb/maintenance/__init__.py (not served here)
- src/pmb/maintenance/compact.py (not served here)
- src/pmb/maintenance/corpus_stopwords.py (not served here)
- src/pmb/maintenance/declutter.py (not served here)
- src/pmb/maintenance/distill.py (not served here)
- src/pmb/maintenance/scheduler.py (not served here)
- src/pmb/maintenance/tick.py (not served here)
- src/pmb/mcp/__init__.py (not served here)
- src/pmb/mcp/_toolspec.py (not served here)
- src/pmb/mcp/daemon.py (not served here)
- src/pmb/mcp/perf.py (not served here)
- src/pmb/mcp/registry.py (not served here)
- src/pmb/mcp/server.py (not served here)
- src/pmb/mcp/tools.py (not served here)
- src/pmb/memo/__init__.py (not served here)
- src/pmb/memo/delta_render.py (not served here)
- src/pmb/memo/exploration.py (not served here)
- src/pmb/memo/ledger.py (not served here)
- src/pmb/memory_quality.py (not served here)
- src/pmb/provenance.py (not served here)
- src/pmb/py.typed (not served here)
- src/pmb/reasoning/__init__.py (not served here)
- src/pmb/reasoning/arcs.py (not served here)
- src/pmb/reasoning/attributes.py (not served here)
- src/pmb/reasoning/causation.py (not served here)
- src/pmb/reasoning/code_ast.py (not served here)
- src/pmb/reasoning/decompose.py (not served here)
- src/pmb/reasoning/dedup.py (not served here)
- src/pmb/reasoning/extract_anchor.py (not served here)
- src/pmb/reasoning/fact_extract.py (not served here)
- src/pmb/reasoning/facts.py (not served here)
- src/pmb/reasoning/images.py (not served here)
- src/pmb/reasoning/llm_rerank.py (not served here)
- src/pmb/reasoning/pamvr.py (not served here)
- src/pmb/reasoning/predictive.py (not served here)
- src/pmb/reasoning/query_split.py (not served here)
- src/pmb/reasoning/query_worthiness.py (not served here)
- src/pmb/reasoning/reflect.py (not served here)
- src/pmb/reasoning/router.py (not served here)
- src/pmb/reasoning/scoring.py (not served here)
- src/pmb/reasoning/spans.py (not served here)
- src/pmb/reasoning/temporal.py (not served here)
- src/pmb/reasoning/typo_fix.py (not served here)
- src/pmb/reasoning/user_names.py (not served here)
- src/pmb/reasoning/vocab_miner.py (not served here)
- src/pmb/reasoning/weight_learning.py (not served here)
- src/pmb/reference_data.py (not served here)
- src/pmb/resume/__init__.py (not served here)
- src/pmb/resume/builder.py (not served here)
- src/pmb/security/__init__.py (not served here)
- src/pmb/security/redact.py (not served here)
- src/pmb/signals/__init__.py (not served here)
- src/pmb/signals/decay.py (not served here)
- src/pmb/signals/files.py (not served here)
- src/pmb/signals/git.py (not served here)
- src/pmb/signals/session.py (not served here)
- tests/_http.py (not served here)
- tests/cli/test_ambient_watch_targets.py (not served here)
- tests/cli/test_cli_english_and_status.py (not served here)
- tests/cli/test_connect.py (not served here)
- tests/cli/test_connect_active.py (not served here)
- tests/cli/test_connect_codex.py (not served here)
- tests/cli/test_connect_daemon.py (not served here)
- tests/cli/test_connect_extended.py (not served here)
- tests/cli/test_connect_lean.py (not served here)
- tests/cli/test_connect_rules.py (not served here)
- tests/cli/test_daemon_start.py (not served here)
- tests/cli/test_dashboard_port.py (not served here)
- tests/cli/test_delete_cli_and_api.py (not served here)
- tests/cli/test_doctor.py (not served here)
- tests/cli/test_hooks_cmd.py (not served here)
- tests/cli/test_intro.py (not served here)
- tests/cli/test_mcp_proxy.py (not served here)
- tests/cli/test_model_switch.py (not served here)
- tests/cli/test_palette.py (not served here)
- tests/cli/test_recall_daemon.py (not served here)
- tests/cli/test_setup_embedder_choice.py (not served here)
- tests/cli/test_setup_llm_tier_choice.py (not served here)
- tests/conftest.py (not served here)
- tests/engine/test_activity_dedup.py (not served here)
- tests/engine/test_archive_cold.py (not served here)
- tests/engine/test_async_graph.py (not served here)
- tests/engine/test_cold_write_index.py (not served here)
- tests/engine/test_config.py (not served here)
- tests/engine/test_conflict_merge.py (not served here)
- tests/engine/test_decision_tier.py (not served here)
- tests/engine/test_delete.py (not served here)
- tests/engine/test_entity_stopwords.py (not served here)
- tests/engine/test_fact_tree.py (not served here)
- tests/engine/test_facts.py (not served here)
- tests/engine/test_goals_chains.py (not served here)
- tests/engine/test_graph.py (not served here)
- tests/engine/test_hardening.py (not served here)
- tests/engine/test_import.py (not served here)
- tests/engine/test_importance_budget.py (not served here)
- tests/engine/test_index_freshness.py (not served here)
- tests/engine/test_keyed_canonical.py (not served here)
- tests/engine/test_keyed_close_negation.py (not served here)
- tests/engine/test_keyed_suggestions_llm.py (not served here)
- tests/engine/test_lesson_decay_floor.py (not served here)
- tests/engine/test_local_features.py (not served here)
- tests/engine/test_meta_kind_index.py (not served here)
- tests/engine/test_negation_tombstones.py (not served here)
- tests/engine/test_persons.py (not served here)
- tests/engine/test_phase1.py (not served here)
- tests/engine/test_phase2.py (not served here)
- tests/engine/test_phase3.py (not served here)
- tests/engine/test_plans_as_goals.py (not served here)
- tests/engine/test_project_lesson_scope.py (not served here)
- tests/engine/test_project_structure.py (not served here)
- tests/engine/test_quality_gate.py (not served here)
- tests/engine/test_record_batch_cold.py (not served here)
- tests/engine/test_swallow_observability.py (not served here)
- tests/engine/test_tiers.py (not served here)
- tests/engine/test_working_memory.py (not served here)
- tests/engine/test_workspace_use.py (not served here)
- tests/engine/test_write_outbox.py (not served here)
- tests/eval/test_anchor_latency.py (not served here)
- tests/eval/test_api_contract.py (not served here)
- tests/eval/test_locomo_judge.py (not served here)
- tests/eval/test_memory_eval.py (not served here)
- tests/eval/test_memory_eval_multilingual.py (not served here)
- tests/eval/test_packs_off_ratchet.py (not served here)
- tests/eval/test_perf_stages.py (not served here)
- tests/eval/test_property_invariants.py (not served here)
- tests/eval/test_slo.py (not served here)
- tests/fixtures/_fact_extract_baseline.json (not served here)
- tests/fixtures/_lang_parity_snapshot.json (not served here)
- tests/fixtures/_regex_parity_baseline.json (not served here)
- tests/graph/test_file_regex_redos.py (not served here)
- tests/health/test_earned_memory.py (not served here)
- tests/hooks/test_adherence_metric.py (not served here)
- tests/hooks/test_agent_wrapper.py (not served here)
- tests/hooks/test_auto_recall.py (not served here)
- tests/hooks/test_autowrite_importance.py (not served here)
- tests/hooks/test_correction_capture.py (not served here)
- tests/hooks/test_exploration_capture.py (not served here)
- tests/hooks/test_feedback.py (not served here)
- tests/hooks/test_followcheck.py (not served here)
- tests/hooks/test_hook_client.py (not served here)
- tests/hooks/test_intent_routing.py (not served here)
- tests/hooks/test_lesson_idf_gate.py (not served here)
- tests/hooks/test_lesson_scoring.py (not served here)
- tests/hooks/test_prepare_context_stdin.py (not served here)
- tests/hooks/test_pretool_command_guard.py (not served here)
- tests/hooks/test_pretool_guard.py (not served here)
- tests/hooks/test_pretool_repeat_guard.py (not served here)
- tests/hooks/test_session_restore.py (not served here)
- tests/hooks/test_session_restore_surface_ids.py (not served here)
- tests/hooks/test_specificity_gate.py (not served here)
- tests/hooks/test_surface_dedup.py (not served here)
- tests/hooks/test_write_division.py (not served here)
- tests/ingest/test_code_ast_constants.py (not served here)
- tests/ingest/test_git_sync.py (not served here)
- tests/ingest/test_git_sync_limits.py (not served here)
- tests/ingest/test_known_projects_filter.py (not served here)
- tests/ingest/test_multimodal.py (not served here)
- tests/ingest/test_pdf_headings.py (not served here)
- tests/ingest/test_project_index_hygiene.py (not served here)
- tests/ingest/test_project_observer.py (not served here)
- tests/ingest/test_reference_data.py (not served here)
- tests/ingest/test_track.py (not served here)
- tests/ingest/test_track_hook_splice.py (not served here)
- tests/ingest/test_viz.py (not served here)
- tests/integration/test_ambient_e2e.py (not served here)
- tests/integration/test_backup_restore.py (not served here)
- tests/integration/test_circuit_breaker.py (not served here)
- tests/integration/test_codex_ambient.py (not served here)
- tests/integration/test_connect_daemon_roundtrip.py (not served here)
- tests/integration/test_dashboard.py (not served here)
- tests/integration/test_fault_injection.py (not served here)
- tests/integration/test_hooks_e2e.py (not served here)
- tests/integration/test_http_bearer_auth.py (not served here)
- tests/integration/test_lessons_e2e.py (not served here)
- tests/integration/test_mcp_e2e.py (not served here)
- tests/lang/test_ald_distill.py (not served here)
- tests/lang/test_anchor_calibration.py (not served here)
- tests/lang/test_anchors.py (not served here)
- tests/lang/test_canonical_atoms.py (not served here)
- tests/lang/test_corpus_stopwords.py (not served here)
- tests/lang/test_distill.py (not served here)
- tests/lang/test_eval_intent_pamvr.py (not served here)
- tests/lang/test_extract_anchor.py (not served here)
- tests/lang/test_extract_anchor_wiring.py (not served here)
- tests/lang/test_keyed_parity.py (not served here)
- tests/lang/test_lang_pack_parity.py (not served here)
- tests/lang/test_language_packs.py (not served here)
- tests/lang/test_pamvr_explain.py (not served here)
- tests/lang/test_pamvr_first_person.py (not served here)
- tests/lang/test_pamvr_verb_gate.py (not served here)
- tests/lang/test_regex_parity.py (not served here)
- tests/lang/test_ru_uk_suite.py (not served here)
- tests/lang/test_semantic_intent.py (not served here)
- tests/lang/test_spans.py (not served here)
- tests/lang/test_statement_anchors.py (not served here)
- tests/lang/test_unicode_tokenization.py (not served here)
- tests/lang/test_work_request_intent.py (not served here)
- tests/maintenance/test_auto_consolidate.py (not served here)
- tests/maintenance/test_consolidate.py (not served here)
- tests/maintenance/test_decay_cli.py (not served here)
- tests/maintenance/test_declutter.py (not served here)
- tests/maintenance/test_maintenance_tick.py (not served here)
- tests/maintenance/test_migrate_workspaces.py (not served here)
- tests/maintenance/test_ollama_config.py (not served here)
- tests/maintenance/test_provenance_watch.py (not served here)
- tests/maintenance/test_snapshots.py (not served here)
- tests/mcp/test_daemon.py (not served here)
- tests/mcp/test_lazy_mcp_import.py (not served here)
- tests/mcp/test_mcp_compaction.py (not served here)
- tests/mcp/test_mcp_registry.py (not served here)
- tests/mcp/test_perf_shutdown_flush.py (not served here)
- tests/mcp/test_stdio_stdin_isolation.py (not served here)
- tests/mcp/test_toolspec_budget.py (not served here)
- tests/memo/test_exploration.py (not served here)
- tests/memo/test_ledger.py (not served here)
- tests/meta/test_docs_consistency.py (not served here)
- tests/meta/test_lightweight_imports.py (not served here)
- tests/meta/test_no_cyrillic_core.py (not served here)
- tests/recall/test_arcs.py (not served here)
- tests/recall/test_causation.py (not served here)
- tests/recall/test_conversational_gate.py (not served here)
- tests/recall/test_decompose.py (not served here)
- tests/recall/test_embedder_backends.py (not served here)
- tests/recall/test_evidence_channel.py (not served here)
- tests/recall/test_identity_boost_names.py (not served here)
- tests/recall/test_jscore_levers.py (not served here)
- tests/recall/test_keyed_boost_gating.py (not served here)
- tests/recall/test_memory_quality.py (not served here)
- tests/recall/test_model_cache_threadsafe.py (not served here)
- tests/recall/test_overview_cache.py (not served here)
- tests/recall/test_ppr.py (not served here)
- tests/recall/test_predictive.py (not served here)
- tests/recall/test_project_scope.py (not served here)
- tests/recall/test_query_expansion.py (not served here)
Advantages
- Operates entirely locally with no cloud accounts, API keys, or telemetry required. evidence: README.md
- Supports multiple AI coding agents through a unified MCP-native interface. evidence: README.md
Limitations
- Requires manual setup and configuration for each agent integration. evidence: README.md
- Some advanced features and maintenance tasks require manual CLI intervention. evidence: README.md
Security
Risk level: Low risk
This brain runs
Install scripts (1)
Makefile(make install):pip install -e .
- Low risk: network-instructions (Makefile:5)
- Low risk: scripts-present (scripts/_bench_data.py)
- Low risk: scripts-present (scripts/benchmarks/bench_qa_scenarios.py)
- Low risk: scripts-present (scripts/benchmarks/benchmark_locomo.py)
Attribution and licence
- First committed by
oleksiijko
- Declared authors
- PMB contributors (declared in pyproject.toml)
- PMB contributors (declared in CITATION.cff)
- Publisher
- Oleksii Bondar (Community)
- Source
- oleksiijko/pmb · commit d0e2f2e
- Licence
- Apache License 2.0 (files served here)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
- Contributors
- oleksiijko, dmitrii-starikov, VIVAAN-DHAWAN, jbendotnet, motojojoe
AutoGineer is not affiliated with or endorsed by oleksiijko.
Install from source
496 of its files are not served here, so there is no ZIP. oleksiijko/pmb at d0e2f2e