pm-rust-development
Independent Rust-native pm CLI and SDK implementation
Instalar
Este paquete aún no se ha publicado, así que todavía no se puede instalar.
README
pm-rust is an independent, Rust-native implementation of the public
pm workspace contracts for agents and
native applications.
The project is pre-release. Its current delivery slice reads workspaces and
creates, updates, comments on, closes, claims, and releases canonical items
against the published pm 2026.10.21 on-disk contract. Production code, tests, benchmarks,
and build tooling use Rust and typed test harnesses; the distributed binary does not require Node.js,
Bun, JavaScript, or TypeScript.
See large tracker hot-path benchmarks for just bench,
the generated 1k/10k/50k matrix, peak RSS, byte comparisons and known parity gaps.
See the command and storage parity matrix and 2026.10.7 pagination contract for supported read flags and remaining gaps. The explicit ownership contract details claim/release parity and its tested boundaries. The native selection and lifecycle contract covers claim-next, start, pause and session principals. The 2026.10.14 closure and safety contract details closure fields, lock refusal, cyclic readiness, lineage and legacy cursors.
| Read surface | Native parity |
|---|---|
JSON and TOON list / Workspace::list_page |
Producer pages, offsets, query fingerprints, continuation envelopes, empty/final pages |
| Bounded JSON and TOON list | Output limits, budget compaction and omission receipts, snapshot continuations and stale refusal |
| Triage list | Built-in projection, token-budget ceilings, intent receipts and rebased cursors |
| Legacy SDK list methods | Existing native and unbounded envelopes retained |
Parity uses both real CLIs over shared fixtures. Every advertised producer cursor
resumes after the last emitted row, including when --output-limit trims a
--limit page (pm-cli#1420,
pm-rust-8qbo). Explicit terminal output caps
still disclose withheld rows without inventing a cursor; lift that cap at the
same incoming boundary to finish the tail. --after accepts workspace
mutations, while --output-cursor refuses changed row snapshots. Combined
amount and budget ceilings bind the original uncapped snapshot, so unchanged
output-cursor replay works and deleted-identity fallback uses the emitted
producer position.
String compaction preserves split UTF-16 code units as escaped JSON, and full
list projections preserve stored extra metadata key order. Generated differential
checks and independent revert proofs are documented in
the output parity receipt.
See the October 21 parity contract for lock-owner recovery, strict mutation admission, ordering and cursor changes.
Native item mutations recover pending journals across operation names before applying later edits. See journal recovery for crash-state regressions and operator conflict remedies.
Explain native query cost
Run pm-rust explain list (TOON) or pm-rust explain list --full --json before
requesting a large result. The native SDK exposes Workspace::explain_list with
typed requests, bounds and refusals. Plans disclose candidate files, source I/O
and actual projected decoder-input work; output bytes, heap use and time remain
unknown. Planning itself scans bounded source bytes and performs zero mutations.
The bounds require unchanged files and do not certify valid items or reserve state.
See the contract and remedies and SDK example. Brief projection reduces decoder work on body-heavy trackers; output/page limits alone do not reduce source scanning.
Embeddable bounded read sessions
Workspace::read_session freezes a private disk-backed snapshot, strictly decodes
all items and checks unique identities before serving any context. Native hosts
pull SessionPage values with backpressure; no Node, Bun, Git or background worker
is required. The session reuses canonical list pagination, lifecycle registries,
output budgeting and lossless JSON/TOON codecs. Its receipt certifies the admitted
snapshot and completion of brief projected context, not full-field delivery.
cargo run -- read-session --memory-bytes 536870912 --page-items 20 --output-tokens 4000 --json
cargo run --example read_session -- path/to/project
JSON emits one compact {output,receipt} frame per line. Default TOON emits a
receipt and canonical page followed by ---. An optional --cancel-file marker
requests cancellation before admission or between pages; removing it allows a new
CLI invocation. SDK callers can share SessionCancellation across threads or call
ReadSession::cancel() for immediate cleanup while idle. Drop and terminal pulls
attempt snapshot cleanup; explicit calls report storage failures. See the embedding contract for
accounting limits, cancellation latency, integrity boundaries and typed remedies.
Native incremental changes
pm-rust changes [--cursor <opaque>] [--limit 20] [--output-bytes 65536] [--json]
returns a bounded page of canonical mutation facts and a continuation cursor.
changes::ChangeReader and LocalChangeAdapter provide the same pull interface
for Rust consumers over the existing authorized adapter ABI. Per-stream prefix
cursors retain equal-time/backdated appends and refuse stale history explicitly.
No tracker writes, Node, Git, shared checkpoints or background polling are needed.
See cursor semantics and resource bounds and the
SDK example. The validation report
records SDK comparisons, seeded sequences, revert proofs and public-data numbers.
Without git
Incremental change pulls work on a plain tracker with no Git or Node executable.
Adapter compatibility checks work without a tracker or Git. Query cost explanations, read sessions and
workspace discovery, list/get/search/context/history/dependencies, item mutations,
ownership and linked artifacts work in plain directories. Concurrent writers share
the same tracker and retain every admitted item edit and append-only history entry.
The multi-process write contract tests 50 writers against one such tracker without
a Git executable. Native context refuses trackers with 10,000 or more items;
see the large tracker limits and benchmark protocol.
Linked-test branch provenance is optional and inspects Git only when a repository
marker exists. GitHub synchronization and Git history tooling require a Git
repository and are outside the distributed native command slice.
Evidence recorders and the receipt commit gate require Git
and a reachable origin; the crash corpus itself still runs in plain trackers.
Crash-consistency differential corpus
The TypeScript SDK in scripts/crash-harness.mts
and just crash compare real native processes with the locked pm-cli 2026.10.21
oracle. On Linux, strace injects SIGKILL at every declared per-task rename and
fsync entry ordinal observed in uninterrupted update/comment reference runs.
Each case starts after an acknowledged synthetic create, restarts through a
different operation and returns to the original one, and checks exact item/history bytes, immutable history
prefixes and recovery receipts. These commands work in plain directories without
a Git executable. The source tracker is read only; all mutations use disposable
non-git clones.
just oracle-install
cargo build --locked --bin pm-rust
just crash --native target/debug/pm-rust --artifacts .crash-failures --json
Default TOON and compact JSON contain bounded counts and per-case outcomes;
--full --json adds durable-byte and receipt hashes. Exit codes are 0 for full
conformance, 1 for measured failures, and 2 for typed setup/boundary refusals with
remedies. Failures retain a minimal synthetic tracker, the acknowledged/recovered
probe bytes and a replay manifest under the ignored artifact directory. Original
histories are never repaired or rewritten. A read-copy failure is independently
replayed on a synthetic tracker before retaining evidence.
See the SDK, read-copy and replay example for the declared
boundary scope and measured results. Process-kill evidence does not establish
power-loss durability. Different syscall ordinals across runtimes do not denote
the same semantic phase; the receipt reports each runtime's observed counts,
including zero fsync calls in the published implementation.
Current native slice
cargo run -- --workspace /path/to/project list --status open
cargo run -- --workspace /path/to/project list --type Feature
cargo run -- list --json --limit 20 --output-budget unbounded
cargo run -- list --limit 20 --tag rust --sort updated --order desc
cargo run -- list --cursor "$NEXT_CURSOR" --limit 20 --output-budget unbounded
cargo run -- list --json --for triage --token-budget 1000
cargo run -- context --limit 10
cargo run -- context --depth deep --limit 10
cargo run -- context --limit 10 --token-budget 4000 --json
cargo run -- history pm-example --limit 10
cargo run -- history pm-example --verify --strict-exit --json
cargo run -- deps pm-example --json
cargo run -- search "native search" --limit 20 --json
cargo run -- search "Unicode café" --type Feature --status open --tag rust
cargo run -- search "native" --after "$NEXT_CURSOR" --output-budget unbounded
cargo run -- files pm-example --add path=src/lib.rs,note=Implementation --author agent
cargo run -- docs pm-example --add path=README.md --author agent
cargo run -- test pm-example --add 'command=cargo test,path=tests/example.rs' --author agent
cargo run -- files pm-example
cargo run -- test pm-example --remove-index 1 --author agent --json
cargo run -- --workspace /path/to/project list --json --output-budget unbounded --output-limit unbounded --all
cargo run -- --workspace /path/to/project get pm-example
cargo run -- --workspace /path/to/project create --id pm-example --title "Native item" --type Task --author agent
cargo run -- --workspace /path/to/project update pm-example --title "Renamed" --priority 1 --author agent
cargo run -- --workspace /path/to/project comment pm-example "Status note" --author agent
cargo run -- claim pm-example --author agent --json
cargo run -- release pm-example --author agent --json
cargo run -- --workspace /path/to/project close pm-example --reason "Done: shipped" --author agent --resolution "Fixed" --expected-result "Expected" --actual-result "Observed" --validate-close strict --json
List pagination uses the pinned 2026.10.21 oracle in both JSON and default TOON.
Configured lifecycle roles and declarative custom hierarchy kinds are resolved
before selection; see configured list registries.
Parent and tag filters and all six published sort fields run before slicing;
--order desc also reverses the default tie-break ordering. --cursor is a
native alias for the oracle's --after spelling. Producer cursors tolerate row
edits; snapshot-bound --output-cursor rejects changed projected rows. TOON
budgets measure rendered UTF-8 bytes, including table compaction; defaults are
4,000 tokens for TOON and 6,000 for JSON. See
the mixed-status pagination receipt for the 270-item
walks and negative controls.
The library discovers .agents/pm from a workspace, nested directory, file, or
tracker root; strictly decodes TOON item documents; retains unknown package
fields; rejects merge markers and duplicate IDs; and returns deterministic JSON
projections. Create uses explicit IDs, per-item ownership locks, synced
same-directory atomic writes, a durable recovery journal, canonical history,
and exact post-document hashes. See
the compatibility contract.
Keyword search and the item files, docs, and test collection commands are
native. Search ranks weighted literal occurrences across item text, including
comments, notes, learnings, reminders, events, dependencies and plans; exact IDs,
title words, phrases and all-term coverage carry the oracle's bonuses. Collection
edits read the current item under its writer lock, skip no-ops, and append
canonical history through the existing recovery journal. See the
search and collections contract for tested
flags, selectors, refusal differences and concurrency evidence.
context at brief, standard, deep and full depth, append-only history, and dependency
tree/graph/context deps reads are native. See the orientation contract for
supported flags, integrity behavior, explicit refusals and measured latency.
Rust formatting, strict Clippy (deny warnings, pedantic), complete
private-item rustdoc coverage, a native Rust identity-audit gate, and tests
run on Linux, macOS, and Windows. Each platform also gates the dependency
audit, generated changelog, strict pm health, the release:check aggregate
gate, and 100 percent line, region, function, and branch coverage.
Publication and automated releases remain disabled until a maintainer
explicitly approves publishing. The daily release workflow is present and
correct but cannot fire without the PM_RELEASE_APPROVED repository variable
being set to true.
Identity audit gate
A native Rust identity-audit gate (tests/identity_audit.rs) scans every object
in the local object store — via git cat-file --batch-all-objects, so both
objects reachable from refs and any unreachable (dangling or orphaned) ones that
store holds — for author and committer identities, and fails closed on any
identity not listed in
.github/approved-git-identities.txt.
What CI can and cannot prove. Workflow jobs check out with fetch-depth: 0
and fetch-tags: true, which fetches the complete reachable history — so in
CI the gate covers every commit on every ref and tag. It does not cover
objects that are unreachable on the server: a clone never transfers dangling
objects, so they cannot be in the runner's object store to scan. The
unreachable-object capability therefore protects a run against a repository that
actually holds such objects — a maintainer's local clone, or a forensic mirror —
and CI's guarantee is the narrower reachable one. Treat a green CI run as
evidence about refs, not about the whole upstream object database.
Changelog and release tooling
The root package.json exposes npm run release:check and
bun run release:check aliases for the unchanged native gate. Changelog and
release-note targets remain available through the justfile:
just changelog # prepend new release section to CHANGELOG.md
just changelog-full # rebuild full changelog from all release tags
just changelog-check # verify committed changelog matches generated (CI gate)
just release-notes # print release notes for the current release window
just release-check # aggregate release gate (fmt, clippy, docs, tests, coverage, audit, changelog)
The changelog heading date is fixed (not clock-derived) so the gate produces identical output across all timezones.
Runners without just can use npm run changelog:full --prefix tests/oracle
and append -- --check to verify the result. Both entry points use
scripts/changelog.mts, which reads the pins, fixed date, and item URL base
from the justfile. Gated issue sync and closeout use this npm entry point.
Without git
Regular tracker reads and writes work in plain directories. Changelog generation from release tags needs Git history and a Git executable; the wrapper identifies this prerequisite before invoking the generator.
Work is managed in this repository with the latest pm CLI under
.agents/pm/. The ecosystem-level lineage is the private companion item
pm-cli-website-204t.
Development
The published parity oracle is pinned to exactly 2026.10.21 in
tests/oracle/package.json and installed from its committed package-lock.json.
Both local runs and every CI matrix job use npm ci; the lock records the
registry tarball and integrity, including the bundled runtime closure. This
avoids the transitive range drift described in
pm-cli#1417.
Dependabot tracks this manifest; oracle upgrades must also update the native
compatibility version and tooling contracts. Changelog generation keeps its
separate exact pm-changelog/CLI pairing.
npm ci --prefix tests/oracle --ignore-scripts
export PM_NODE_CLI="$PWD/tests/oracle/node_modules/@unbrained/pm-cli"
export PM_RUST_REQUIRE_PUBLISHED_CLI=1
cargo test --locked --test pagination_differential
# Run the aggregate release gate (fmt, clippy, docs, tests, coverage, audit, changelog)
just release-check # installs the lockfile oracle and selects it by default
# Individual gates
cargo fmt --all -- --check
cargo clippy --locked --all-targets --all-features -- -D warnings
RUSTDOCFLAGS='--document-private-items -D missing-docs' cargo doc --locked --all-features --no-deps
cargo test --locked --all-targets --all-features
cargo +nightly-2026-08-06 llvm-cov --locked --branch --all-targets --all-features --json --output-path coverage-branch.json
jq -e '.data[0].totals.lines.percent == 100 and .data[0].totals.functions.percent == 100 and .data[0].totals.regions.percent == 100 and .data[0].totals.branches.percent == 100' coverage-branch.json
cargo audit
node tests/oracle/node_modules/@unbrained/pm-cli/dist/cli.js merge install
node tests/oracle/node_modules/@unbrained/pm-cli/dist/cli.js health --check-only --require-merge-drivers --strict-exit
License
MIT. See LICENSE.
Portable native adapter ABI
Rust embeddings can use an explicitly supplied NativeAdapter through
native_adapter::NativeAdapterClient. The pm-native-adapter/1 contract
exchanges bounded UTF-8 JSON bytes, with typed get, paginated list, claim and
release requests. It requires neither Git nor Node. The caller supplies an
existing authorized backend transport; core SDK semantics and pm-web/MCP
transports retain their ownership.
The client checks the exact ABI, declared capability, arguments and frame
ceiling before dispatch. It makes one exchange, preserves canonical backend
output (including refusal, omission and mutation receipts), and never retries.
A successful response can describe a skipped claim or a peer's success; inspect
the canonical receipt before proceeding. AdapterRefusal.dispatched distinguishes
preflight refusal from an uncertain dispatched outcome. Reconcile authoritative
receipts before retrying an interrupted mutation.
pm-rust adapter-check [--json] reads a transcript from stdin and emits a compact
TOON or JSON compatibility receipt. It works without a tracker. It validates
recorded responses supplied as exact reply_bytes arrays without replaying them; dispatched: false and
receipt_scope: abi_compatibility_only are explicit. It does not certify backend
authorization, durable writes or corpus completeness.
pm-rust adapter-check --json <<'JSON'
{"manifest":{"abi":"pm-native-adapter/1","capabilities":["get"],"max_frame_bytes":1048576},"request":{"abi":"pm-native-adapter/1","request_id":"read-1","operation":{"action":"get","id":"demo-1"}}}
JSON
See the ABI and adapter obligations and the
compilable read adapter example. Build the example
with cargo build --locked --example native_adapter, then pass an explicitly
authorized tracker directory as its argument and one AdapterRequest on stdin.
Replace its exchange implementation with the existing authorized transport
when embedding against a remote backend. The example grants only get and list.
The expanded crash corpus includes history-path openat cuts and native runtime
journals. Historical same-operation receipts do not establish complete recovery
conformance; the locked published oracle still has measured history-open failures.
The repository check node scripts/crash-history-prefix.mts requires Git and
compares every changed history stream with origin/main as exact bytes. Main
history must remain a prefix; new item streams are permitted. Tracker commands
and just crash continue to work in plain directories without Git.
Del README del paquete en GitHub. Ver en GitHub