Local-first long-horizon project memory for AI research
Project description
projmem
Local-first long-horizon project memory for AI/ML research — no account, no cloud, no telemetry.
pmem is a CLI tool that records what you did and why: which files you tracked, every command you ran, configs/metrics/artifacts from each run, Git state at the time, and failure taxonomy for experiments that went wrong. Everything lives in a local SQLite database inside .pmem/.
Why projmem?
| MLflow / W&B | projmem | |
|---|---|---|
| Needs account / server | ✅ | ❌ |
| Works fully offline | ❌ | ✅ |
| Records failure taxonomy | ❌ | ✅ |
| Privacy: no remote URL stored | ❌ | ✅ |
| Secret redaction in config | ❌ | ✅ |
| Dependency footprint | Heavy | pydantic + rich + typer |
projmem is built for researchers and engineers who want experiment memory without giving up privacy or requiring infra.
Demo
$ pmem init --objective "Train AG News baseline" --metric accuracy \
--metric-direction max --target 0.9
✓ Initialized project 'my-experiment' in .pmem/
$ pmem track train.py
✓ Tracked train.py (sha256: a3f8c1…)
$ pmem run --name smoke --seed 42 --config config.json \
--metrics metrics.json -- python train.py
● Running: python train.py
✓ Run completed exit=0 run_id=r-01j…
stdout → .pmem/artifacts/runs/r-01j…/stdout.txt
metrics → .pmem/artifacts/runs/r-01j…/metrics.json
$ pmem run --name failed-run -- python train.py --bad-flag
✗ Run failed exit=1 run_id=r-02j…
stderr → .pmem/artifacts/runs/r-02j…/stderr.txt
See docs/demo/quick-demo.md for a fully annotated walkthrough.
Installation
Public PyPI install after the alpha release is published:
pip install projmem
pmem --help
TestPyPI rehearsal install for 0.1.0a0:
pip install -i https://test.pypi.org/simple/ \
--extra-index-url https://pypi.org/simple \
projmem==0.1.0a0
pmem --help
Development install from source:
# Requires uv — https://docs.astral.sh/uv/
uv sync --all-groups --no-editable
uv run --no-sync pmem --help
Commands
| Command | What it does |
|---|---|
pmem init |
Create .pmem/ and record project goal, metric, target |
pmem track <path> |
Hash and register a file; --update refreshes the hash |
pmem run -- <cmd> |
Execute a command and capture stdout/stderr, Git state, exit code |
pmem run --seed --config --metrics --artifact |
Full metadata run (D8) |
pmem log-failure <run-id> <type> <description> |
Store a confirmed failure with D11 taxonomy; supports --output json |
pmem log-decision <description> |
Store a durable project decision and optional rationale |
pmem note <content> |
Store a lightweight project note |
pmem baseline <run-id> |
Mark a run as experiment baseline; --compare compares another run |
pmem summary |
Print project objective, target status, best run, timeline, and warnings |
pmem export --json |
Export Phase 1 project memory as deterministic JSON |
Coming next: real PyPI publish after user confirmation.
Architecture
pmem run -- python train.py
│
▼
cli/ ← parse args, render output (Typer + Rich)
services/ ← use-case orchestration, transactions
domain/ ← entities, enums, Pydantic v2 validation
repositories/ ← SQLite read/write (parameterized queries only)
migrations/ ← schema versioning, backup, integrity check
integrations/ ← Git metadata capture (best-effort, no remote URL)
utils/ ← SHA-256 hashing, helpers
Dependency direction is strictly one-way: cli → services → domain / repositories / integrations. Domain never imports CLI, service, or migration code.
→ ARCHITECTURE.md for layer responsibilities and ADRs.
Quality
- 244 tests — unit + integration, 95%+ branch coverage enforced at CI
- Matrix CI — Python 3.10 / 3.11 / 3.12 × Ubuntu 22.04 / macOS 14
- Static analysis —
ruff(lint + format) +pyright(strict type checking) - Pre-commit hooks —
detect-secrets, ruff, pyright on every commit - Security hardening — path traversal guard, secret redaction, no remote URL stored
uv run ruff check .
uv run ruff format --check .
uv run pyright
uv run pytest --cov=pmem --cov-report=term-missing
uv run pre-commit run --all-files
Data Model
.pmem/pmem.db — local SQLite, never leaves the machine:
| Table | Stores |
|---|---|
projects |
name, goal, objective, metric, target |
tracked_paths |
file path, SHA-256 hash, timestamps |
experiments |
name, description |
runs |
command, exit code, seed, config hash, stdout/stderr preview, Git metadata |
failures |
confirmed failure records with severity/source/tags |
decisions |
durable decisions with rationale |
notes |
lightweight project notes and run/experiment links |
experiments.metadata_json |
baseline run id and baseline metrics |
→ docs/specs/schema-v1.md for full schema and migration strategy.
Security & Privacy
- All data stays local —
.pmem/is project-local by design - Git remote URLs are never stored
- Config keys matching
token / password / secret / keypatterns are redacted before DB insert - Path traversal and command injection are actively guarded against
.pmem/itself cannot be tracked (prevents recursive capture)
→ SECURITY.md for full policy.
Roadmap
| Phase | Gates | Status |
|---|---|---|
| Phase 1 core | D1–D18: init, track, run, memory, JSON, baseline, summary/status | ✅ Done |
| Phase 1 wrap-up | D19–D20: docs, demo, export, TestPyPI rehearsal | ✅ Done |
| Phase 2 | Export/import, shared memory path | 📋 Planned |
| Phase 3 | Evidence-aware recommendation, graph/sync | 📋 Planned |
→ ROADMAP.md for gates with acceptance criteria.
Key Docs
- ARCHITECTURE.md — layer design and decision records
- ROADMAP.md — phase breakdown with acceptance criteria
- DEFINITION_OF_DONE.md — what "done" means per gate
- SECURITY.md — security and privacy policy
- DATABASE.md — schema design and migration strategy
- docs/demo/quick-demo.md — annotated CLI walkthrough
- docs/specs/run-contract.md — run capture contract
- docs/specs/failure-taxonomy.md — failure classification spec
- docs/specs/summary.md — summary and timeline/status contract
- docs/specs/export.md — Phase 1 JSON export contract
Local-First Guarantee
All Phase 1 commands run offline and write only to .pmem/:
.pmem/
config.yaml ← project metadata
pmem.db ← SQLite database
artifacts/runs/ ← stdout, stderr, metrics, artifact files per run
snapshots/ ← (planned) file snapshots
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file projmem-0.1.0a0.tar.gz.
File metadata
- Download URL: projmem-0.1.0a0.tar.gz
- Upload date:
- Size: 48.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c2d0903b9b2cf5831daaf583e28c8df63328d6cdc3da50d2cb0fd1446fbee520
|
|
| MD5 |
3b77ea51bdf33a9a51e2bfef57224166
|
|
| BLAKE2b-256 |
b71333be6763ca5bd027951b1808eed635e8c5b11c116b3931dafea8a54727bd
|
Provenance
The following attestation bundles were made for projmem-0.1.0a0.tar.gz:
Publisher:
publish-pypi.yml on umynameislove/projmem
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
projmem-0.1.0a0.tar.gz -
Subject digest:
c2d0903b9b2cf5831daaf583e28c8df63328d6cdc3da50d2cb0fd1446fbee520 - Sigstore transparency entry: 1568424858
- Sigstore integration time:
-
Permalink:
umynameislove/projmem@d882c43ecd4c5ec0698c188e52a7e51f5a098853 -
Branch / Tag:
refs/tags/v0.1.0a0 - Owner: https://github.com/umynameislove
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@d882c43ecd4c5ec0698c188e52a7e51f5a098853 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file projmem-0.1.0a0-py3-none-any.whl.
File metadata
- Download URL: projmem-0.1.0a0-py3-none-any.whl
- Upload date:
- Size: 67.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3fb4c963f685bce1b5a9e5342d00630ce53b6a3b28e537d57eeee9281f11d52b
|
|
| MD5 |
948135f25790ac8d1360be9a37caf6dc
|
|
| BLAKE2b-256 |
195ea1bb5333cb51657013270ef9606ed62921e0c02c6d0ab53b9ba58f8b296d
|
Provenance
The following attestation bundles were made for projmem-0.1.0a0-py3-none-any.whl:
Publisher:
publish-pypi.yml on umynameislove/projmem
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
projmem-0.1.0a0-py3-none-any.whl -
Subject digest:
3fb4c963f685bce1b5a9e5342d00630ce53b6a3b28e537d57eeee9281f11d52b - Sigstore transparency entry: 1568424882
- Sigstore integration time:
-
Permalink:
umynameislove/projmem@d882c43ecd4c5ec0698c188e52a7e51f5a098853 -
Branch / Tag:
refs/tags/v0.1.0a0 - Owner: https://github.com/umynameislove
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@d882c43ecd4c5ec0698c188e52a7e51f5a098853 -
Trigger Event:
workflow_dispatch
-
Statement type: