Metadata-Version: 2.4
Name: projmem
Version: 0.1.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
```

See [docs/demo/quick-demo.md](docs/demo/quick-demo.md) for a fully annotated walkthrough.

---

## Installation

Public PyPI install after the alpha release is published:

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

TestPyPI rehearsal install for `0.1.0a0`:

```bash
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:

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

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](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

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

→ [docs/specs/schema-v1.md](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 / 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.

---

## 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](ROADMAP.md) for gates with acceptance criteria.

---

## Key Docs

- [ARCHITECTURE.md](ARCHITECTURE.md) — layer design and decision records
- [ROADMAP.md](ROADMAP.md) — phase breakdown with acceptance criteria
- [DEFINITION_OF_DONE.md](DEFINITION_OF_DONE.md) — what "done" means per gate
- [SECURITY.md](SECURITY.md) — security and privacy policy
- [DATABASE.md](DATABASE.md) — schema design and migration strategy
- [docs/demo/quick-demo.md](docs/demo/quick-demo.md) — annotated CLI walkthrough
- [docs/specs/run-contract.md](docs/specs/run-contract.md) — run capture contract
- [docs/specs/failure-taxonomy.md](docs/specs/failure-taxonomy.md) — failure classification spec
- [docs/specs/summary.md](docs/specs/summary.md) — summary and timeline/status contract
- [docs/specs/export.md](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
```
