# Setup and Operation Guide — PMP Reference Node This guide covers installing the reference node, what it puts on disk, a tour of every CLI command, running the demo and tests, and troubleshooting. ## 1. Requirements * **Python 3.10 or newer.** The code uses modern typing and the standard-library `zoneinfo`/`datetime` machinery; older interpreters are not supported. * **No external services.** The node is entirely local: storage is SQLite (via the standard library), and cryptography is provided by the `cryptography` package (Ed25519), declared in `pyproject.toml`. * Linux, macOS, and WSL are tested targets. Native Windows should work but key files cannot be permission-restricted the same way (see §7). ## 2. Installation From a clone of the repository: ```bash python -m venv .venv source .venv/bin/activate pip install -e ".[dev]" # dev extra adds pytest ``` This installs the `pmp` console script. You can equivalently invoke everything as `python -m pmp …`. Verify the install: ```bash pmp --help ``` ## 3. What a node is on disk A node is just a directory. `pmp init --node-dir ` creates: ``` / keys/ # node identity keys (Ed25519) node.key # private key — mode 0600, never leaves the machine node.pub # public key — safe to share; identifies this author oplog.db # SQLite database holding the append-only operation log node.json # node metadata: node id, schema/wire-format version, # creation time ``` Everything the node knows is in this directory. Back it up by copying the directory; destroy the node by deleting it. There is no hidden global state — two nodes in two directories are fully independent identities. > **The private key is the node's identity.** Anyone holding `node.key` can sign > operations as this node. Treat the directory like a password store. ## 4. CLI tour All commands accept `--node-dir ` (the examples below assume `--node-dir ./avery-node`). Run any command with `--help` for its full options. ### `pmp init` Creates the node directory, generates the Ed25519 keypair, initializes the empty log, and writes node metadata. Refuses to overwrite an existing node. ```bash pmp init --node-dir ./avery-node ``` ### `pmp import ` Runs an import adapter against a source and appends one signed `evidence` operation per evidence item. Adapters shipped in this milestone: ```bash pmp import calendar samples/calendar/avery-personal.ics --node-dir ./avery-node pmp import notes samples/notes --node-dir ./avery-node # file or directory pmp import photos samples/photos/avery-photos.json --node-dir ./avery-node ``` Import is **idempotent**: each evidence item carries a content-derived external ID, and the node skips items whose identical content has already been ingested. The command reports how many items were imported and how many were skipped as duplicates. Re-running the same import is always safe. ### `pmp log` Lists operations in append order: sequence number, operation ID (truncated), type, source/adapter, and a one-line summary. Useful filters are available (e.g. limiting count or filtering by adapter — see `pmp log --help`). ### `pmp show ` Prints a single operation in full as pretty-printed canonical JSON: header (author, sequence, previous-operation hash, timestamp), payload (the evidence body), provenance block, and signature. Operation IDs may be given truncated as long as the prefix is unambiguous. ### `pmp verify` Re-verifies the entire log: 1. every operation's canonical hash matches its stored operation ID; 2. every signature verifies against the author's public key; 3. the per-author hash chain is intact (each operation's `prev` matches the hash of the previous operation, sequence numbers are contiguous from 0). Exits non-zero and names the first offending operation if anything fails. Run this after restoring a node from backup or whenever you suspect corruption. ### `pmp export` Streams the log as **canonical JSON Lines** to stdout (one operation per line, in append order). This is the portable interchange form defined by the milestone-2 wire format — another implementation can verify the stream with nothing but the spec and the node's public key. ```bash pmp export --node-dir ./avery-node > avery.oplog.jsonl ``` ### `pmp info` Prints node identity (node ID / public key), wire-format version, operation count, and storage path — handy when juggling multiple nodes. ## 5. End-to-end demo ```bash bash scripts/demo.sh ``` The script creates a fresh node in a temporary directory, imports all sample datasets for the fictional user Avery Reyes, lists the log, shows one full operation, verifies the chain, re-runs an import to demonstrate idempotency, and exports the log to JSONL. Read the script — it is short and is the best "executable documentation" of the CLI. ## 6. Running the tests ```bash pytest # whole suite pytest tests/test_oplog.py -q # one module pytest -k idempotent -q # by keyword ``` The suite needs no network and writes only to pytest-managed temp directories. It includes tamper tests that mutate stored operations and assert that `pmp verify` (and the underlying library call) detects the corruption — if you change storage or canonicalization, those tests are your tripwire. ## 7. Troubleshooting * **`pmp: command not found`** — the virtualenv isn't activated, or the package was installed without `-e`. Use `python -m pmp …` as a fallback. * **"node directory already exists"** on `init` — `init` never overwrites. Choose a new directory or delete the old one deliberately. * **Verification failure after copying a node** — copy the whole directory, not just `oplog.db`; verification needs `keys/node.pub`. If `verify` reports a hash mismatch, the database was modified outside the API; restore from backup (append-only means an untampered backup is always a valid prefix). * **Windows key permissions** — on POSIX systems the private key is written mode `0600`. On native Windows this chmod is best-effort; rely on filesystem ACLs or run under WSL if this matters to you. * **Time zones in ICS imports** — events are normalized to UTC where the ICS provides zone information; floating times are preserved as such in the evidence payload and flagged, so downstream derivation can decide. If your calendar export uses exotic `VTIMEZONE` definitions, inspect the resulting evidence with `pmp show` to confirm normalization did what you expect. ## 8. Where to go next * Writing a new source adapter: [`adapter-authoring.md`](adapter-authoring.md) * Understanding and auditing the log: [`log-inspection.md`](log-inspection.md) * Wire format and schema reference: milestone-2 documents in `docs/`