ml-party
by paul-krug
README.md
<p align="center">
<img src=".github/media/logo.png" alt="ml-party" width="460">
</p>
<p align="center">
<a href="https://github.com/paul-krug/ml-party/actions/workflows/ci.yml"><img
src="https://github.com/paul-krug/ml-party/actions/workflows/ci.yml/badge.svg"
alt="ci"></a>
<a href="https://pypi.org/project/mlparty/"><img
src="https://img.shields.io/pypi/v/mlparty" alt="pypi"></a>
<a href="https://paul-krug.github.io/ml-party/"><img
src="https://img.shields.io/badge/docs-user%20guide-blue" alt="docs"></a>
</p>

**An agent-native platform for ML experiment tracking and lineage/knowledge.**
Every existing tracker is human-dashboard-first: great at scalars-over-time,
silent about *why* a run exists and *how it relates* to the others. ml-party
treats a run's **abstract, typed relationships, and reproducibility contract
as first-class data** — a durable, queryable lab notebook that agents write
(over MCP) and query, and that humans read live (CLI + web viewer). It is
also a full local tracker: metrics, artifacts, checkpoints, all stored
locally; mirroring to W&B/MLflow is a future optional adapter, not the
product.
Core ideas:
- **The write contract is the product.** `run_start` pre-registers intent
(title, purpose, hypothesis, full parameters) and auto-captures the repro
tuple (source snapshot, env lock, invocation, hardware, outer-git
provenance). `run_finalize` refuses without method + result/verdict +
reproduce — refusals are machine-readable `{missing, invalid}`. Failures
are knowledge (`run_fail`); silent deaths become `abandoned`.
- **Internal git per experiment.** A run snapshots the actually-running
source — the directory you name, bounded by what git tracks there, never a
guess — as a commit in a bare
internal repo. A run *references* a commit — a launch-arg sweep is many
runs on one commit, distinguished by mandatory `parameters`. Declared
`derives_from` lineage becomes the commit's parent; every run gets its own
ref (no races).
- **A knowledge graph over it.** Typed nodes (`project / experiment / run /
note`), a controlled edge vocabulary (`derives-from`, `supersedes`,
`refutes`, …), hybrid BM25(+optional embeddings)+graph retrieval that
downranks superseded/refuted beliefs. Knowledge is append-only; correction
is an edge.
- **Boards: agents author whole views.** An agent logs a self-contained
HTML page as an artifact and the UI renders it sandboxed — comparison
dashboards, demo galleries, live reports that fetch current data from the
read-only API at view time ([boards guide](https://paul-krug.github.io/ml-party/boards.html)).
- **Run control through registered templates.** Users register shell
templates with typed placeholders — the allowlist; agents invoke them
with validated, shell-quoted *values* (never commands), and every
invocation is recorded in the graph, edged to the run it controlled.
Restart is never a mutation: a new run, `derives-from` the old
([run-control guide](https://paul-krug.github.io/ml-party/actions.html)).
- **Local-first, remote-ready.** Writers always write a local spool store;
spool-and-flush sync ships runs to a served store over three idempotent
streams ([remote-tracking guide](https://paul-krug.github.io/ml-party/remote.html)). Multi-user auth (roles,
per-user tokens, UI login) activates with the first `mlp user add`
([deployment guide](https://paul-krug.github.io/ml-party/deploy.html)).
- **Runs that execute elsewhere stay findable.** Launching from a laptop
onto a cluster, a queue or a cloud box? `run_set_compute` records the job
system, its id and **the link back to the job** — and a run that declares it
up front stops recording your laptop's hardware as its own. A pointer, not an
integration — ml-party submits nothing and polls nothing, so it works with
any job system, including your in-house one
([tracking guide](https://paul-krug.github.io/ml-party/tracking.html#runs-that-execute-somewhere-else)).
# Quickstart
**Requirements:** Linux or macOS (Windows via WSL — the store relies on
POSIX file locking) and Python ≥ 3.11. The web UI ships prebuilt in the
wheel; nothing to compile, no Node required.
## Option 1 — let your agent install it
Open your agent **in the project you want to track** and give it this prompt:
```text
Look at https://github.com/paul-krug/ml-party — install ml-party and set up the MCP server for this project.
```
It will find [the install skill](.agents/skills/install-ml-party/SKILL.md)
in this repo and follow it: install the package, reuse your store if you
already have one (rather than starting a second, disconnected notebook),
and register the server with your client.
**Then restart your agent session.** A newly registered MCP server cannot
load into the session that registered it — the skill tells your agent to say
this, but restart even if it forgets. On the next start, approve `ml-party`
when prompted; `/mcp` should then list it.
## Option 2 — install it yourself
You will need to follow three small steps.
**1) Run the install.** One personal store holds all your projects.
```bash
pip install mlparty
mlp init --root ~/.mlparty --no-mcp
export ML_PARTY_STORE=~/.mlparty # put this in your shell profile
```
**2) Make the MCP server visible to your agent.**
Register the store once, globally, so it is there in every session.
Claude Code users paste:
```bash
claude mcp add -s user ml-party -- "$(which mlp)" serve-mcp --root ~/.mlparty
```
For any other agent/harness, print the snippet and paste it into that
client's own MCP configuration:
```bash
mlp mcp-config
```
It prints a standard `mcpServers` entry; its home differs per client
(Cursor's `.cursor/mcp.json`, and so on — a few use a different top-level
key, so check your client's docs).
Either way ml-party is then available in every session, in any directory,
and each codebase you work in becomes a `project` inside that one graph.
Prefer a store that lives inside one repository instead — because the
notebook should travel with it, or a team shares it? That variant, and when
it is worth the trade-off, is in the
[MCP setup guide](https://paul-krug.github.io/ml-party/mcp.html#one-store-or-one-per-project).
**3) Restart the session.** A newly registered MCP server only loads on the
next start. Approve `ml-party` when prompted; `/mcp` lists what is active,
and `claude mcp list` shows what was loaded if it is missing.
## See it running
```bash
mlp demo & # a real run: contract + live metrics
mlp ui # → http://127.0.0.1:7327
```
Open the browser: the demo run is streaming its loss curve live. It went
through the full lifecycle a real training does — pre-registered with
purpose/hypothesis/parameters, metrics streamed, then finalized with a
verdict. Click into it: Overview | Metrics | Artifacts | Code.
## Then just tell your agent
The server is **self-teaching**: *"use ml-party for this run"* is all an agent
needs to hear. Connecting hands it a short brief pointing at a
`workflow_guide` tool that returns the full operating manual — a tool rather
than the connection text, because MCP clients truncate server instructions
(Claude Code at 2048 characters, silently), and a tool is the one channel an
agent can pull on its own initiative.
**You can also just ask it about ml-party.** The guides ship *inside the
wheel*, and a `help` tool serves them — so "how do I run the demo?", "how do I
instrument my training script?", "how do I share this store with my team?" are
answered from the installed package, with no checkout and no browser. `help()`
also reports every `mlp` command, the installed version, which store it is
serving, and where to file a bug.
Before the first run it will **ask which directory holds your code**. That
directory (`source_root`) is what gets snapshotted into the store, so the
agent shows you the file list before anything is written, and never captures
what your `.gitignore` excludes. Name no directory and the run simply
records no code — nothing is ever swept up silently.
Other setups: `mlp connect --root <store> --project <dir>` registers an
existing store for one more project.
### Instrument a training script
The agent brackets the run over MCP and launches your script with
`ML_PARTY_STORE`/`ML_PARTY_RUN` set; the script attaches as the second
writer:
```python
import mlparty
h = mlparty.attach() # env-var handshake (inert without ML_PARTY_RUN)
h.log_metric("loss", loss, step=step) # streams to the live view
h.log_artifact("ckpt/best.pt")
h.finalize(method=..., result={"summary": ..., "verdict": "confirmed",
"metrics": {"wer": 0.048}},
reproduce="python train.py --lr 1e-3")
# unhandled exceptions auto-fail the run with the traceback
```
CLI mirror: `mlp status / runs / show <ref> / tail <run> / query "…" /
diff <a> <b> / janitor / rebuild-index`.
# Web viewer
`mlp ui` serves a read-only SPA: experiments → runs → tabbed run pages with
live SSE metric dashboards, a finder-style artifact browser (image/audio/
video viewers, an `.npy`/`.npz` tensor slicer), agent-authored boards, the
lineage graph, search, and diff. Remote box → tunnel like TensorBoard:
`ssh -L 7327:localhost:7327 <box>`. For a shared server with logins and
sync ingest, see the [deployment guide](https://paul-krug.github.io/ml-party/deploy.html)
and the [remote-tracking guide](https://paul-krug.github.io/ml-party/remote.html).
# From source
For development, or to run an unreleased revision — needs Node ≥ 20, since
the UI bundle is built rather than downloaded:
```bash
git clone https://github.com/paul-krug/ml-party && cd ml-party
python -m venv .venv && .venv/bin/pip install -e .
(cd ui && npm install && npm run build) # web UI bundle, once
.venv/bin/python -m pytest tests/ -q
```
Contributions: [CONTRIBUTING.md](CONTRIBUTING.md) for the flow and the
maintainer-only paths, [AGENTS.md](AGENTS.md) for conventions,
[SECURITY.md](SECURITY.md) for the trust model.
# Design
- **[User guide](https://paul-krug.github.io/ml-party/)** (rendered from
[docs/](docs/)): [tracking runs](https://paul-krug.github.io/ml-party/tracking.html),
[the web UI](https://paul-krug.github.io/ml-party/ui.html),
[boards](https://paul-krug.github.io/ml-party/boards.html),
[run control](https://paul-krug.github.io/ml-party/actions.html),
[MCP setup & tools](https://paul-krug.github.io/ml-party/mcp.html),
[remote tracking](https://paul-krug.github.io/ml-party/remote.html),
[deployment & auth](https://paul-krug.github.io/ml-party/deploy.html).
- [DESIGN.md](DESIGN.md) — **the living design document** (ontology,
contract, internal-git model, storage, surfaces, remote mode, forward
design).
- [AGENTS.md](AGENTS.md) — conventions for agents/contributors working in
this repo (incl. the doc-sync rule). Planning lives in the repo's
GitHub Project, not in tracked files.
Layering: pydantic ontology → journal-first store (`journal.jsonl` is the
source of truth; SQLite/FTS5 is a rebuildable index) → dulwich internal-git
engine → `MlParty` core API → thin frontends (MCP server, `mlp` CLI,
in-process client, read-only HTTP+SSE for the viewer).
# Status
Beta (0.x): APIs may still move between minor versions; the store format is
journal-first and rebuildable, and every release migrates it forward.
Licensed [Apache-2.0](LICENSE).
Tests: `.venv/bin/python -m pytest tests/ -q`
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessResponsive