Six field reports closed, and the check that runs before every edit no longer gets slower as your project ages.
Every fix below was found by running projectmem on the machine that reported it — Windows 11, and all four MCP clients — not by reading the code. Two of them were found only because a client launched the server from a directory we did not expect.
pip install -U projectmemFaster
pjm precheck was taking 26 seconds on a 1,200-event project, and getting worse every week.
The instructions tell agents to call it before modifying anything, so its cost is paid constantly. It ran one git log per event — 1,201 subprocesses — to answer a question about a single file. Three faults compounded: staleness was computed across the whole log and then filtered down to the one file being checked; the memo key was (file, timestamp), which looks right but never hits because real events carry distinct timestamps; and nothing bounded the git walk.
It now makes one git log per distinct file, bounded by the oldest event citing it, and counts in memory.
| events | before | after |
|---|---|---|
| 100 | 2,210 ms | 48 ms |
| 400 | 8,905 ms | 51 ms |
| 1,500 | ~33 s, 1,501 git processes | 82 ms, 2 processes |
Latency is flat rather than linear in project age. The project-wide path behind pjm brief and the dashboard went from 26,294 ms to 450 ms. Results are unchanged — verified against a reimplementation of the old algorithm, including across merge commits.
Fixed
A retired decision came back. (#17) supersedes has existed since 0.1.4 and the summary renderer honours it, but the two surfaces an agent actually reads while working — get_context and precheck_file — were not filtering it. You could retire a decision and still be told about it. Both filter now. The deeper cause was that AI_INSTRUCTIONS.md mentioned supersedes zero times in 12,503 characters, so models never called it and summary.md accumulated decisions that contradicted each other; it is documented now on all three surfaces an agent may read.
get_context described the wrong directory. (#15) generate_context defaults its root to the current directory, and the MCP server was the only caller that omitted it. For an MCP server the current directory is wherever the client launched the process, so the git status and architecture came from the agent harness rather than your project.
precheck_file invented warnings about every project but the server's own. The same defect one tool over, found while re-testing the fix above. A four-file precheck on an untouched repository came back with 373 phantom "cited file no longer exists" warnings, and a churn count read from whatever git repository the process happened to sit in. Both surface only when the project root differs from the working directory — which is every MCP client that does not change into the project, and never the CLI. That is why pjm precheck was always correct and this survived several releases.
Git hooks aborted commits on Windows. (#16) An unresolvable shebang does not cause git to skip a hook — it makes git refuse the commit. The hooks shipped #!/usr/bin/env bash, which depends on PATH, and under GitHub Desktop bash often is not there. Two more faults fed the same failure: the baked binary path went in raw and the shell ate its backslashes, so C:\Users\ripon became C:\Usersipon; and the venv fallback looked in <prefix>/bin/pjm, which cannot exist on Windows.
A decorative character killed pjm init on a Windows console. It created .projectmem/, the hooks, CLAUDE.md and AGENTS.md, then raised UnicodeEncodeError printing a box-drawing rule and exited 1 — so the command both did its work and reported failure, which is the worst outcome for any script checking the exit code. A stock Windows install runs the console on cp1252, where U+2550 has no mapping. 11 of the 14 glyphs projectmem prints were affected; fixing the reported line alone would have moved the crash to the next command.
A follow-up report found punctuation still rendering as black diamonds. An em dash is cp1252-encodable (0x97), so no fallback fired — and it still came out wrong, because Python wrote 0x97 and a terminal set to UTF-8 read that as an invalid lead byte. Encodable was never the right test. On a stream that cannot carry Unicode, projectmem now emits no non-ASCII byte at all. UTF-8 terminals keep their real typography.
Expected errors were reported as crashes. pjm fix with no open issue printed a clear message and then a full traceback underneath it.
Changed
Your project is named in the bridge file. (#14) One server serves every project, so a tool call naming none is refused rather than guessed at — correctly, since guessing would write into the wrong audit trail. But nothing ever told the agent the name, so it learned it from the error and retried. That round trip happened every session.
AGENTS.md is written alongside CLAUDE.md. The first attempt at the fix above put the name in CLAUDE.md — which Antigravity and Codex never read, so for those clients the fix did not exist. pjm init now writes both, and the guidance leads with the active project instead of asking the agent to look it up.
Deferred
pjm import was advertised for this release. 0.3.3 became a correctness and performance release driven by field reports, so import moves to 0.4.0 rather than being half-shipped to keep a date.
Verified
The four acceptance tests were run against this build in Antigravity, Claude and Codex, and the full Windows suite on Windows 11 / Python 3.12.10 / Git 2.54.0. 279 automated tests pass against the installed wheel.
Every issue in this release was reported by @medium-effort, who also contributed the Windows daemon support in 0.3.2. Thank you — the two precheck bugs above exist in every release before this one and would not have been found without that testing.
Full changelog: CHANGELOG.md · PyPI: projectmem 0.3.3