Metadata-Version: 2.4
Name: projmem
Version: 0.2.0a0
Summary: Local-first long-horizon project memory for AI research
Author: Quoc Bao Tran
License-Expression: MIT
Project-URL: Repository, https://github.com/umynameislove/projmem
Project-URL: Issues, https://github.com/umynameislove/projmem/issues
Keywords: ai,cli,experiment-tracking,local-first,research-memory
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pydantic>=2.7
Requires-Dist: rich>=13.7
Requires-Dist: typer>=0.12
Dynamic: license-file

# projmem

[![CI](https://github.com/umynameislove/projmem/actions/workflows/ci.yml/badge.svg)](https://github.com/umynameislove/projmem/actions/workflows/ci.yml)
[![Python](https://img.shields.io/badge/python-3.10%20|%203.11%20|%203.12-blue)](https://github.com/umynameislove/projmem)
[![Coverage](https://img.shields.io/badge/coverage-95%25%2B-brightgreen)](https://github.com/umynameislove/projmem)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

**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
```

## Installation

Public PyPI install for the latest published alpha:

```bash
pip install projmem
pmem --help
```

TestPyPI rehearsal install for the Phase 2A alpha candidate after rehearsal
publish:

```bash
pip install -i https://test.pypi.org/simple/ \
  --extra-index-url https://pypi.org/simple \
  projmem==0.2.0a0
pmem --help
```

Development install from source:

```bash
# 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 |
| `pmem export-bundle --out <path> [--json]` | Write a deterministic Phase 2 bundle; artifact bytes are opt-in |
| `pmem import --dry-run <bundle> [--json]` | Validate a Phase 2 bundle without mutating SQLite |
| `pmem import --apply <bundle> --confirm [--json]` | Quarantine a validated bundle as a pending import job |
| `pmem conflict-check <bundle> [--json]` | Detect bundle conflicts before merge or destructive write |
| `pmem resolve <conflict-id> --action <action> [--json]` | Record a non-destructive conflict resolution audit event |
| `pmem share init <path> [--alias] [--json]` | Register an explicit local shared memory path |
| `pmem share status [--json]` | Validate registered shared memory paths |
| `pmem failures list [--json]` | List confirmed failures without raw free text by default |
| `pmem failures export --out <path> [--json]` | Export failure records as deterministic JSON; raw text requires `--include-text --confirm` |
| `pmem failures embed [--json]` | Compute deterministic local failure embeddings without network or vector DB |
| `pmem failures cluster [--json]` | Cluster local failure embeddings and emit a deterministic 2D projection |
| `pmem failures patterns [--json]` | Generate human-reviewable pattern candidates with heuristic labels |
| `pmem failures summary [--json]` | Summarize failure analysis status and top pattern candidates |

---

## 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.

## Quality

- **300+ tests** — unit + integration + security, 95%+ 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

```bash
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 |
| `export_packages` | Phase 2 bundle manifest/payload hash and local export audit metadata |
| `import_jobs` | pending/quarantined import jobs and dry-run validation reports |
| `shared_paths` | explicit local shared memory path registrations |
| `audit_events` | portability and import/export audit evidence |

## Security & Privacy

- All data stays local — `.pmem/` is project-local by design
- Git remote URLs are **never** stored
- Config keys matching `token / password / secret / key` patterns are redacted before DB insert
- Path traversal and command injection are actively guarded against
- `.pmem/` itself cannot be tracked (prevents recursive capture)

→ [SECURITY.md](SECURITY.md) for full policy.

Phase 1 alpha is complete: local CLI, SQLite persistence, run capture,
failure/decision/note memory, baseline comparison, summary, export, TestPyPI
rehearsal, and PyPI install smoke have all passed.

Phase 2A foundation is scoped around local-first portability and collaboration:
schema portability tables, deterministic export bundles, import dry-run
validation, pending/quarantined import apply, conflict detection, non-destructive
resolution audit events, shared memory path registration/status, schema
compatibility, evidence-bundle provenance, security/privacy hardening, and
release-readiness review. See
[`docs/roadmap/phase-2.md`](docs/roadmap/phase-2.md).

Phase 2B starts from the accepted Phase 2A contracts and focuses on
privacy-safe failure analysis. `pmem failures list/export` provides a local
substrate for later embedding, clustering, and pattern reporting.
`pmem failures embed/cluster/patterns/summary` uses deterministic local hashing
vectors, cosine-threshold clustering, and metadata-first heuristic labels by
default. Pattern labels are audit candidates, not confirmed root causes.
Optional heavier NLP features are gated behind local capability checks and are
not part of the core runtime path.

---

## 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
```
