@openthink/pm
v0.1.4
Published
pm — local-first, relational ticketing (the vault, as a database)
Downloads
1,042
Readme
pm
Local-first, relational ticketing for agents and humans. Tickets and
projects live in a local SQLite database; every change is an operation in
an append-only log. One static binary, pm, is both the human CLI and the
agent contract — non-interactive, --json on every read, stable exit
codes.
No dispatch, no assignment, no pipelines: pm stores and serves ticket
state. It does not fan out agents or run a "team" — that's a build loop's
job, calling pm the way it calls git.
Install
npm i -g @openthink/pmPrebuilt binaries for macOS (arm64, x64) and Linux x64 (glibc and musl);
no Rust toolchain needed. The npm package downloads the binary for your
platform from the matching GitHub Release. Each release carries SLSA build
provenance; check a downloaded archive with
gh attestation verify <archive> --repo OpenThinkAi/pm.
Without npm, the shell installer from the same release:
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/OpenThinkAi/pm/releases/latest/download/pm-installer.sh | shnpm puts pm on its global bin path; the shell installer puts it in
~/.cargo/bin. There's no separate daemon or service to run.
From source (stable Rust 1.85 or newer; the workspace uses edition
2024. The workspace declares no rust-version, and the minimum is not
CI-verified; it is known to build on 1.91 and current stable):
cargo install --locked --git https://github.com/OpenThinkAi/pm pmFirst workspace
pm initWith no flags, pm init creates a neutral workspace: ticket ids prefixed
PM-, four workflow states (backlog, todo, in-progress, done), and
no gate or model labels. It writes the workspace's directory into
~/.config/pm/config.toml the first time that file doesn't already exist,
so every later command finds it without --workspace.
pm new --title "Write the release notes"
# -> PM-1
pm show PM-1
pm move PM-1 in-progress
pm done PM-1pm new files a ticket into the lowest-position unstarted state
(todo, by default) — not backlog. backlog exists so you can park
work below the ready frontier without deleting it; pm ready/pm claim
only ever pick up unstarted-category tickets, so a ticket sitting in
backlog won't be claimed until you move it to todo.
Want a different starting point?
--prefix <PREFIX>overrides the ticket-id prefix (1–16 uppercase letters/digits, starting with a letter).--preset saltlineseeds this project's own historical workflow instead: prefixAGT, statestriage/in-progress/done/canceled, and amanualgate label. Mostly relevant if you're migrating a saltline-style markdown vault withpm import vault— see thepm initentry indocs/cli-contract.md.
The agent contract
pm is designed to be driven by an agent (a build loop, a script, another
CLI) as comfortably as by a person at a terminal:
- Non-interactive. No verb reads stdin or prompts. A command run with stdin closed or redirected behaves exactly as it does at a terminal.
--jsonon every read, and on every verb that writes something worth reporting back:{"schema": 1, ...}. The schema number is a versioned contract — a breaking shape change bumps it; an additive field does not.- Stable exit codes:
0ok,1error (an unhealthy database fordoctor, findings forcheck),2usage,3not found,75taken (someone else already has the ticket you tried toclaim). - Workspace resolution is
--workspace <DIR>, thenPM_WORKSPACE, thenworkspacein~/.config/pm/config.toml(or$XDG_CONFIG_HOME/pm/config.toml) — so a script can pin a workspace explicitly, or just letpm init's config write carry every later command to the same place. - Actor resolution is
PM_ACTOR, then--as <ACTOR>, then$USER— every op records who wrote it.
The full verb-by-verb reference — every flag, every --json shape, every
exit code beyond the table above — is
docs/cli-contract.md. It's generated by
hand from the CLI's source and kept honest by two test suites
(crates/pm/tests/json_contract.rs, crates/pm/tests/help_contract.rs);
where the doc and pm --help disagree, the code is the bug.
Data retention
Deleting a ticket or project only tombstones it: titles, comments, hold
reasons and removed body text remain in the op log, the Loro body history,
the hub and any git backups, and there is no purge command today. See
docs/data-retention.md before storing
anything sensitive.
License
MIT OR Apache-2.0.
