pm-changelog
Generate CHANGELOG.md and release notes from completed pm items for local releases, GitHub Actions, runners, and scripts. Can run as a standalone CLI/API package or as `pm changelog generate`.
Installieren
Mit installiertem pm
pm install npm:pm-changelog --projectMit npm, ohne pm zu installieren
npx -y @unbrained/pm-cli install npm:pm-changelog --projectMit Bun, ohne pm zu installieren
bunx @unbrained/pm-cli install npm:pm-changelog --projectREADME
Generate CHANGELOG.md from pm-cli items.
Install
pm install npm:pm-changelog --project
pm changelog generate --mode prepend --output CHANGELOG.md
Rebuild a full project changelog from git release tags:
pm changelog generate --all-release-tags --mode replace --output CHANGELOG.md
Tag-derived flags (--all-release-tags, --since-previous-tag,
--until-release-tag) require complete git tag history: in a shallow clone
they fail with an actionable E_MISSING_TAG_HISTORY diagnostic instead of
deriving an incomplete window. The diagnostic names the exact recovery for the
detected state — git fetch --tags --unshallow for a plain shallow clone, or
git config --unset remote.origin.tagOpt && git fetch --tags --unshallow when
the clone is also --no-tags; follow all commands it lists (see
Release and CI).
Standalone npm usage:
npm install --save-dev pm-changelog @unbrained/pm-cli
npx pm-changelog --mode prepend --output CHANGELOG.md
The standalone CLI accepts both --flag value and --flag=value for value
options, and supports --release-version as a compatibility alias for
--version (matching pm changelog generate syntax).
Caller-supplied --stdin and --input JSON refuses envelopes whose explicit
pagination, source completeness, field omission, or compaction receipts report
unsafe delivery. Refusal exits nonzero before writing, preserving an existing
changelog. The public pm SDK (peer minimum 2026.10.23) inspects these receipts. Ordinary status/date
filters select the caller's scope and do not imply incomplete retrieval.
Bare arrays and receipt-free { "items": [...] } documents retain their
intentional subset contract: the caller owns their scope and must supply the
full intended history when replacing a changelog. See JSON input.
Whole-tracker reads explicitly request the list-local --full projection because pm-cli 2026.10.18+ treats --all as row scope only and otherwise omits fields needed for changelog generation.
Date precedence is explicit: --date is an unconditional override, then an
existing release tag supplies its commit date, then --date-fallback or
--date-from-version applies only while that tag is absent. With none of those,
generation uses the current UTC calendar date. Release-gated CalVer packages can
therefore use --date-from-version (for example 2026.8.8 or 2026.8.8-2
becomes 2026-08-08) without masking the authoritative tag date after publication.
The optional numeric -N suffix distinguishes same-day releases and stays in
the version heading. Non-numeric suffixes and impossible calendar dates are rejected.
--date-fallback and --date-from-version are mutually exclusive. Explicit
and fallback date text is rendered verbatim; use YYYY-MM-DD for a conventional
changelog heading.
npx pm-changelog --release-version-from-package --date-from-version
npx pm-changelog --version 1.2.0 --date-fallback 2026-08-08
Opt-in extras
These flags are strictly additive — omitting them keeps output byte-for-byte identical to the default:
npx pm-changelog --stdout --section-by type # group by type/status/label instead of categories
npx pm-changelog --stdout --conventional # Features / Bug Fixes / ... headings
npx pm-changelog --stdout --contributors # per-release contributor list
npx pm-changelog --all-release-tags --limit 10 # keep only the newest N releases
npx pm-changelog --all-release-tags --since-version 2.0.0
npx pm-changelog --all-release-tags --changelog-json > changelog.json
npx pm-changelog --stdout --breaking-changes # add a Breaking Changes section
npx pm-changelog --suggest-semver # print a suggested semver bump as JSON
npx pm-changelog --stdout --body-preview 80 # append first 80 chars of each item body
npx pm-changelog --stdout --emoji-prefix # prefix headings with emoji (Added 🎉, Fixed 🐛, ...)
npx pm-changelog --stdout --include-metadata # append type/status/priority/release/milestone per item
npx pm-changelog --stdout --json --explain # emit selection diagnostics (counts + exclusion hints) for agents
npx pm-changelog --stdout --item-ref-style github # link item IDs to public GitHub issues/PRs, not .agents/pm blobs
npx pm-changelog --stdout --item-ref-style label # neutral (id) labels — safe for a published/public changelog
npx pm-changelog --stdout --respect-item-release # honor each item's release field, not just closed_at
npx pm-changelog --stdout --exclude-tag changelog:ignore # keep tagged items out of the changelog entirely
Section rules
Closed Issue/Bug/Bugfix/Defect items use tracker evidence before type, tags or title:
| Recorded closure | Output |
|---|---|
| Not planned, duplicate, invalid, won't fix, superseded, cannot reproduce (any closed item type) | Omitted from changelog and release notes |
Linked file path or test command/path; affirmative fix/repair/correction/resolution in close_reason or resolution; or delivered/merged PR or commit in close_reason, resolution, actual_result or links |
Existing category rules, including Fixed for repairs |
| Other closed issues, including factual GitHub completion | ### Closed with Closed: <title> |
A title, bug tag, completed timestamp, bare PR URL or GitHub issue link does not
prove a repair. Dispositions must lead close_reason or resolution (optionally
following “Closed as”, “Resolved as” or “Closed on GitHub as”); incidental words
like “Fixed duplicate grouping” remain repairs. Affirmative passive wording such
as “The parser crash was fixed” also records a repair. Negated, hypothetical or pending repair/delivery
statements do not qualify. Instructions such as “Fix after the next deploy” or
“Resolve in a follow-up release” need independent file/test or delivery evidence;
completed wording such as “Fixed the parser” qualifies on its own.
Structured delivery links use url with state: merged
or relation: delivered; string links must name delivery and a PR/commit reference.
Linked files/tests are recorded evidence, not independent verification that a test
passed or a repair shipped. Feature/Task category rules are retained.
The neutral prefix always uses the title, including with --entry-from close_reason
and alternate grouping, so factual closure prose never becomes a repair claim.
Neutral closures stay under Closed with --section-by type, status or label
too; a fixed label cannot bypass the evidence requirement.
They contribute no semver change counts and never appear in Breaking Changes,
even when their title, tags or metadata contain breaking signals.
JSON receipts/documents expose excluded_non_change_count, counted across input
before status/time/release filters. SDK generation/write results expose
excludedNonChangeCount. All projections omit the same non-change items.
Classification is deterministic and reads tracker data only. Existing tags and
release files are unchanged; regenerating history applies these rules to that output.
Prepending a new release preserves older sections unless explicitly regenerated.
Requested release notes
--version X (also --release-version and --release-version-from-package)
requires a visible section for X before any output or file write. This applies
to markdown, JSON, summaries, checks and CI outputs. In particular,
--stdout --limit 1 fails instead of substituting an older release when X has
no qualifying entries. The typed MISSING_REQUESTED_RELEASE error includes
selection counts and a remedy. Missing release: fields retain timestamp and
Git membership inference; they are reported as unassigned, not assumed skipped.
Close delivered items and assign the intended release using the pm CLI when
that is the cause. A refused run never reaches --explain, so the error
carries the selection report itself: the standalone CLI's JSON error has
selection_report (filters, stage counts, exclusion counts), and the
pm changelog generate/export refusal carries the same facts as
filter_*, stage_* and excluded_* entries in its typed context.
For an intentionally empty release, opt in with --include-empty; it emits
the requested versioned heading and No changes.. Empty Unreleased sections
are always omitted, including after the package version is tagged. Pending items
(or explicitly requested dependency notes) still create Unreleased. The same
visibility rule applies to Markdown, JSON, summaries, diagnostics and limits.
Visibility filters must still retain
that section. For historical-only regeneration, --no-pending-release
together with --all-release-tags suppresses the untagged requested version's
pending window, and only that window may then be absent. A requested version
that already has a tag still needs its own section, and without
--all-release-tags a missing requested section is always refused. Neither option
is appropriate as a workaround for omitted delivered work.
Without git
Generate from --stdin, --input or a tracker directory, export release notes,
classify closures and use explicit versions/dates without git. Git tag windows,
previous/release-tag selection and dependency commit notes need a git repository
with the required tag history.
Resolution prose for release notes
Keep a defect description in the tracker title and put the fix in close_reason,
using pm close <id> "Describe the fix" or pm update <id> --close-reason "Describe the fix".
Opt in with --entry-from close_reason on every generation, check, and release-notes
command (including the scripts in package.json). For example:
pm update <id> --close-reason "Fixed the comment-sync test to be independent of the root directory"
npx pm-changelog --entry-from close_reason --mode replace
npx pm-changelog --entry-from close_reason --mode replace --check
pm changelog generate --entry-from close_reason
pm changelog export --entry-from close_reason
Under Fixed, an Issue titled "The comment-sync test is root-sensitive" then renders
"Fixed the comment-sync test to be independent of the root directory". The title stays in the
tracker and still determines ordering; recorded evidence controls whether the issue can
be a repair. The selected field supplies prose in every category, markdown, summary,
structured JSON, and breaking change entry, except neutral Closed entries always use
the title across all output formats, including with --entry-from close_reason.
Markdown escaping and single-line normalization apply to the resolution too.
Only title (the default) and close_reason are supported; missing, empty, whitespace-only,
or non-string resolutions fall back to title. Omitting the flag uses the title; closure
evidence rules still apply.
The standalone --json receipt and structured document record an explicit source as
entry_from; SDK callers use entryFrom: "close_reason".
--check also emits an advisory defect_title warning on stderr for visible closed Fixed
items with no usable close_reason and a recognized English present-tense failure or broken
state (such as "fails", "cannot", "is broken", or "is root-sensitive"). This conservative
heuristic is not a grammar validator. Leading resolution verbs such as "Fix" and "Correct"
are excluded. It follows the same status, tag, time, release, and
visibility filters as generation, and applies to conventional/emoji Fixed headings too.
Grouping by type, status, or label has no Fixed heading and produces no warning. The warning
leaves markdown, JSON stdout, and the drift exit code unchanged. Follow its pm update <id> --close-reason "Describe the fix" recovery and use --entry-from close_reason consistently.
Stable checks across tag publication
Empty Unreleased sections are always omitted; --include-empty retains only
versioned release sections. Callers' committed changelogs drop the legacy empty
Unreleased / No changes. block on their next regeneration, including in
prepend mode. Non-empty unreleased items and dependency notes are preserved.
Prepend merging ignores release headings inside backtick or tilde code fences
and preserves indentation and hard-break spaces in retained Markdown. Nested list
and quote fences end at their block boundaries, preserving later release history.
With --all-release-tags --release-version-from-package --include-empty,
publishing the requested release tag preserves the versioned output when the
release boundary and date match the prepared release. This holds for empty and
item-bearing releases. Version tags accept a leading v or no prefix by default;
calendar padding aliases share one window (2026.11.7, v2026.11.07, and mixed
padding). When commit timestamps tie, a same-day -2 release sorts before its
base release (and -10 before -2), followed by other suffixes in normalized
spelling order. All equal-time tags use one normalized ordering key, so aliases
cannot reorder distinct releases. An explicit --release-tag-pattern still
limits discovery.
Tags remain release-history inputs: adding a previously unknown different
version can add a release section or change timestamp attribution. Tagging an
older commit with a different date/boundary can also change that release's
window. Conflicting aliases on different commits select the newest commit time;
aliases should identify the same release commit. Use immutable tracker milestones
for history independent of Git tags. --date-from-version supplies a pending
calendar date; tagged windows retain their commit date. Stability does not imply
migration of changelogs generated with a different generator version.
Dependency updates and itemless releases
By default, an itemless pending release with non-merge Dependabot-shaped commits gets
its own version heading and ### Dependencies section. Only subjects accepted by
parseDependencyCommit (<type>(deps|deps-dev): bump …) qualify, including Dependabot workflow-pin
bumps. Type, scope and bump are case-insensitive (for example, Build(deps-dev): Bump …
and CHORE(DEPS): BUMP …). The exact scope, separators and bump verb are required;
bumped, Bumps, dependencies, unscoped subjects and deps)!: do not qualify.
Description text keeps its original case, with the existing first-letter capitalization
and trailing PR-number extraction. Docs, release subjects, merge commits and empty subjects
do not create notes or a section.
No tracker items are invented.
After tagging, an itemless window retains these notes only if the changelog committed at that tag
contains ## <version> followed by end of line or -, matching the release resume extractor.
This applies to both all-tag and single-window generation. Tagged itemless windows without that
heading keep their previous output byte for byte. Git failures mean no committed section.
Windows with items keep their existing output unless --dependency-updates is passed.
--no-dependency-updates disables all git dependency notes, including this default.
The CLI reads --output relative to the git working directory for that tag lookup; --stdout uses
CHANGELOG.md. The extension uses its output option (default CHANGELOG.md). SDK callers set
changelogPath, which defaults to CHANGELOG.md relative to gitCwd and also accepts absolute paths.
The lookup reads the immutable tag blob, never the current working file.
A pending window is resolved by --all-release-tags with the requested untagged version, or by
--since-previous-tag / --until-release-tag with that version. SDK callers provide gitCwd and
release windows (a pending window has a releaseTag and no until), or pendingRelease: true for
single-window generation. For a tagged single window, set dependencyUntilRef to the release tag.
Plain tracker-only generation does not infer a pending git window.
--dependency-updates additionally reads every historical or item-bearing window's non-merge
Dependabot subjects. Notes appear last in markdown, structured JSON (dependencies) and --summary.
pm changelog generate and export accept both switches. Explicit opt-in cannot be combined with
--group-by release or milestone, which have no git window.
Ranges run from the previous tag (exclusive) to the release tag, or HEAD for a pending release.
An explicit --until also bounds the single-window range. Orphaned tags fall back to window timestamps.
Dependabot PR links derive from a GitHub --item-url-base; descriptions are escaped literal text.
--stdout --limit 1 with a requested pending version returns that version's own section. If no section
survives selection, the CLI exits non-zero with typed MISSING_REQUESTED_RELEASE before writing output;
it never substitutes the previous release. Unbounded full-file --all-release-tags generation and
checks preserve sectionless historical releases without requiring a heading for the package version.
--include-empty explicitly permits intentionally empty notes.
npx pm-changelog --stdout --since-previous-tag --until-release-tag --release-version-from-package \
--item-url-base https://github.com/unbraind/pm-csv/blob/main/.agents/pm --dependency-updates
## 2026.9.23 - 2026-09-23
### Dependencies
- Bump jscpd from 5.2.0 to 5.3.0 ([#129](https://github.com/unbraind/pm-csv/pull/129))
- Bump @types/node from 26.5.1 to 26.6.1 ([#132](https://github.com/unbraind/pm-csv/pull/132))
PR numbers link to https://github.com/<owner>/<repo>/pull/<n> only when --item-url-base is a
https://github.com/<owner>/<repo>/… URL; otherwise they print unlinked as (#129). The flag is
opt-in because turning it on changes the generated CHANGELOG.md of any repository whose history
contains Dependabot merges, so each repository adopts it in one reviewed change.
--item-ref-style controls how pm item IDs render as references:
auto(default) — an internal.toonblob link when--item-url-baseis set, otherwise a neutral(id)label. Byte-for-byte identical to prior behavior.label— always a neutral(id)label, never a link. Use for changelogs published to a public registry, where.agents/pm/...blob URLs leak tracker structure and may 404.toon— force the internal.toonblob link (requires--item-url-base; falls back to a label when it is unset).github— render a public GitHub issue/PR link derived from the item'sgh:owner/repo#numberprovenance tag (written by pm-github); items without a valid provenance tag fall back to a neutral label.
See Usage for details.
Release attribution: work that shipped before its tracker was closed
By default an item lands in the release window that contains its authoritative completion time — completed_at (recorded by pm-cli ≥ 2026.7.29 separately from tracker close time). When completed_at is absent, generation falls back to closed_at, then updated_at, then created_at; those fallbacks are inferred, not authoritative. In multi-agent workflows an agent often ships the fix in one release and closes the tracker during a later one, which would date months-old work as new — and is why shipped-but-unclosed trackers pile up: closing them corrupts the changelog.
Record where the work actually landed and generation stops trusting closed_at:
pm update <id> --release 2026.6.1 # the release the fix actually shipped in
npx pm-changelog --stdout --release-version 2026.7.24 --respect-item-release
With --respect-item-release, an item that declares a release (top-level field or
metadata.release) is pinned to it: kept when it matches the generated version regardless of
timestamps, dropped otherwise (including from an unversioned Unreleased window — it already
shipped). Items without a declared release keep the plain time-window behavior, so output is
unchanged for workspaces that never set the field. --all-release-tags already honors the field and
is unaffected; the flag makes the single-window path (--since-previous-tag --until-release-tag,
changelog:check, release notes) agree with it. --explain reports what attribution dropped.
Inferred-attribution report
--explain also reports attribution provenance: how many visible items were placed in their
release window from the authoritative completed_at versus an inferred fallback (closed_at,
updated_at, or created_at), plus a bounded sample of the inferred item ids. This is how a
maintainer catches a shipped-but-late-closed item — one whose completed_at is missing so its
placement fell back to a closed_at recorded in a later release. Inspect the inferred sample, set
completed_at (or pin the item with --release), and regenerate.
Excluding items
--exclude-tag <tags> (repeatable, comma-separated) omits items carrying any listed tag from every
generation path — an ignore convention for pm items that are legitimately tracked but are not
user-facing package changes (upstream issue mirrors, internal chores, superseded work):
pm update <id> --add-tags changelog:ignore
npx pm-changelog --stdout --exclude-tag changelog:ignore
Matching is case-insensitive and trims whitespace. The item stays in the tracker with its full history — only the generated changelog skips it.
Docs
Multi-agent merge safety
This repo tracks its project management in .agents/pm/ and ships a committed .gitattributes
that maps those tracker artifacts to pm-cli's field-aware Git merge drivers, so concurrent-branch
tracker edits merge cleanly instead of hard-conflicting. The driver definitions live in
per-clone Git config; npm install / npm ci wires them automatically via the prepare script, scripts/prepare-merge-driver.ts: the launcher template pm-ops ships, copied unchanged, which a test compares byte for byte with the pinned template. It runs pm-ops's installer, which calls pm merge install when the pm CLI is on PATH and skips with a notice when it is not. A production install of a clone (npm ci --omit=dev) has no pm-ops, so the launcher skips with one notice, while a stale or broken pm-ops fails the install. Registry installs of this package never run prepare. Being Node-based, it behaves identically on POSIX shells and Windows cmd.exe. To (re)run manually: npm run merge:install.
After merging a branch that touched .agents/pm/, reconcile any residual history-hash drift with
pm merge reconcile (pm-cli ≥ 2026.7.22): preview with pm merge reconcile --dry-run, apply with
pm merge reconcile --message "post-merge reconcile", then confirm with pm validate, which scans the
whole tracker and flags remaining history drift across every affected item (pm merge reconcile
itself lists each affected stream in its output; pm history --verify <id> spot-checks one item). The field-aware driver already unions every author's
content, so reconcile only re-greens the hash chain (no data loss) — see the authoritative
pm-cli merge-safety guide. The
older blunt pm history-repair --all remains available as a lower-level primitive.
Tracker release milestones
A named release can come from tracker state instead of Git tags. Freeze its membership, then generate notes from those boundaries:
pm changelog milestone create 2026.10.21 --items 'tag:shipping'
pm changelog generate --milestones --stdout
pm changelog generate --milestones --summary --format json
# Standalone generator uses the same tracker source:
pm-changelog --milestones --stdout
Omitting --items freezes every item, including open work. Queries support *
or space-separated id:, status:, type:, tag:, and release: terms. Terms
are ANDed; comma-separated values within a term are alternatives. Values are
case-sensitive. This is a deliberately small selection grammar, not a shell
command. Use status:closed when only already-completed work belongs to a release.
An ID belongs to the first milestone that captures it closed, using that frozen
row. Earlier open captures reserve no release membership; live closures remain
Unreleased until captured closed. Later edits, reopening and deletion cannot grow
or rewrite an earlier release. Normal status and non-change filters still apply.
New captures must have strictly increasing RFC 3339 instants with explicit offsets;
backward/equal clocks and ambiguous ordering refuse. Repeating a
name with the same IDs returns the original snapshot; changed membership refuses
with milestone_membership_changed and a remedy to create a new name. Snapshot
fingerprints are checked before generation. New names are lowercase portable
tokens of at most 80 characters, excluding reserved device names. Snapshots live
under the tracker's changelog/milestones/ directory.
Keep these records with tracker backups and synchronize them with tracker data.
The creation receipt contains only name, fingerprint, timestamp and item count;
body/description, comments and unrelated metadata are never stored. Retained
rendering and classification fields are fingerprinted; full rows are not printed.
The host renders receipts as TOON or JSON.
--milestones selects the release source. Git-window, explicit version/date and
metadata-grouping options, --body-preview, --pm-bin and --pm-arg cannot be
combined with it. Existing --group-by milestone remains mutable item-field grouping. A tracker inside a Git repository
can still use --all-release-tags in a separate invocation. Outside a Git
repository, explicit tag options (--all-release-tags, --since-previous-tag,
and --until-release-tag) now fail with MissingTagHistoryError instead of
silently falling back to a single section.
The typed SDK accepts complete backend snapshots through createReleaseMilestone
and an atomic ReleaseMilestoneStore. Use resolveTrackerReleaseHistory with
createChangelog, buildChangelogDocument or createChangelogSummary. Database
adapters must use transactional insert-if-absent and consistent complete snapshot
reads; no SQL server or hosted access is required by this package. See the
SDK example.
Audit release claims before publication
pm changelog audit maps every generated release-note line to its source item,
resolution, linked files/tests and recorded delivery. It preserves the generator's
selection and wording, including neutral Closed entries for factual closures.
Missing evidence stays in gaps; a closed issue alone cannot justify Fixed.
Repair gaps follow the classified item category across conventional headings,
custom grouping and repeated Breaking Changes entries.
pm changelog audit --entry-from close_reason
pm changelog audit --entry-from close_reason --format json
pm changelog audit --audit-receipts receipts.json --format json --check
# Standalone: all generation filters and release-window flags still apply.
pm-changelog audit --pm-root .agents/pm --entry-from close_reason --json
The default compact TOON report has one row per claim, one evidence record per
item, and a shared remedy dictionary. JSON carries native arrays/objects; TOON
encodes nested collections as JSON strings. Line numbers are one-based in the
freshly generated Markdown, identified by markdown_sha256. Repeated items in
label groups or Breaking Changes retain separate line mappings. Contributors map
to the selected items' credit metadata; No changes. maps to the empty selection.
Existing prepended history is outside this generated-document audit.
--check exits nonzero on any gap; normal audit mode exits zero and returns the
complete report. The standalone command prints that report to stdout before
refusing. Host commands (pm changelog audit and pm changelog generate --audit-evidence) print the selected JSON or TOON report to stderr before a failed
check throws, preserving line mappings, gaps and remedies. Successful host checks
return one report through normal output.
ClaimAuditError exposes code, remedy and, for unsupported claims, report.
Git-dependent dependency audits refuse as git_required without a repository; drop
--dependency-updates to continue a tracker-only audit. Duplicate or missing item IDs refuse as ambiguous_items; malformed execution
receipts refuse as invalid_receipts. Fix the named input and regenerate.
A linked test command is a declaration, not a passing run. Supply a JSON array
of { "item", "command", "outcome", "reference" } execution receipts through
--audit-receipts. Outcomes are passed or failed; commands must match a linked
command or test path. Every linked command/path needs a passing receipt. A failed matching receipt prevents that command from being
accepted as passing. References remain in the report for inspection. Recorded
merge/delivery language must name a PR or commit; a bare issue URL does not count.
Dependency commit subjects retain an explicit evidence gap.
This is an audit of recorded support, with no test execution, file existence
check, remote receipt authentication or semantic proof of arbitrary prose. Caller
receipts are assertions: maintainers must verify their relevance to the release.
pm-review owns review validation; pm-ops owns publication provenance.
See the SDK and receipt example.
Append-only release corrections
Correct a published milestone claim while retaining the original wording and historical output:
pm changelog corrections view --release v1 --item example-claim --format json
pm changelog corrections append --input correction.json --format json
The current view exposes the original, corrected wording, evidence and complete
correction chain. Exact replays create nothing; stale revisions, reused identities
and supersession cycles return typed refusals with remedies. Native SDK context events
and transactions preserve history and coordinate writers without git.
Corrections target the first capture that actually publishes the claim; later
snapshots, edits and reopenings cannot transfer the published claim to another release.
Omitted duplicates, other non-change closures, query-filtered rows and empty titles
reserve no ownership; a later repair publishes once in its first eligible release.
New captures freeze publication eligibility, so later status-role or alias edits
also leave historical wording and existing correction chains accessible.
Closure evidence uses that same frozen meaning: custom done-role duplicates are
omitted, and issue closures without repair evidence stay under Closed without
contributing a breaking change or fix. Live commands load configured SDK roles;
SDK callers pass statusRegistry, or use the context returned by the milestone resolver.
See the input example and typed SDK.
Without git
Tracker milestone creation/generation, ordinary generation, export, audience contracts, consumer upgrades, release corrections and claim audits work in plain directories and through caller-supplied SDK items without Git. Milestone paths invoke no Git subprocess. Git tag windows, historical Git membership and dependency commit collection require a Git repository. Use tracker fields or explicit dates for a tracker-only audit.
Ordered consumer upgrade obligations
Author breaking: true and upgrade_actions on a change_facets declaration,
then compile the obligations between an installed version and a target version:
pm changelog upgrades --audience operator --from 1.0.0 --to 4.0.0 --format json
pm-changelog upgrades --pm-root .agents/pm --audience operator --from 1.0.0 --to 4.0.0
Only explicitly authored actions become pending core Plan step data. The SDK
orders their prerequisites, deduplicates identical action IDs across releases,
and refuses missing prerequisites, conflicting definitions and cycles with
typed remedies. Commands, titles and release prose are never executed or inferred
as actions. Both commands read complete native metadata through the SDK without
git. Output defaults to compact TOON; --json selects compact JSON.
Use buildConsumerUpgrades, readConsumerUpgrades and formatConsumerUpgrades
from the typed SDK. See the three-release example and range contract
and measured public-tracker validation.
Audience-specific change contracts
Publish only explicitly tagged facets of closed change items for API users, operators and agents, preserving one canonical attribution ledger:
pm changelog contracts --group-by release --audience operator --format json
pm-changelog contracts --pm-root .agents/pm --format toon
Core metadata stores change_facets as {audience, text} or
{audience, source: "close_reason"} declarations. Audiences are api-user,
operator and agent-behavior; omit the audience to generate all three.
Missing facets and missing requested resolutions produce explicit omissions.
The generator reuses release selection, section rules and resolution rendering.
buildAudienceContracts, readAudienceContracts and formatAudienceContracts
provide the typed SDK, compact JSON/TOON and typed refusals with remedies.
These commands work without git. See the worked example and contract.
Agent contract drift index
Compare explicitly declared agent obligations over (from,to] without reading
every release note:
pm changelog drift --from 1.0.0 --to 10.0.0 --format toon
pm-changelog drift --pm-root .agents/pm --from 1.0.0 --to 10.0.0 --json
Stable obligations on agent-behavior facets retain additions, removals, changed
assumptions, affected commands and evidence IDs. Unchanged declarations reference
a shared definition table; ordinary prose is never interpreted. Legacy or malformed
declarations produce individual omissions. The typed SDK and both commands work
without git. See the declaration example, output and limits.
Orphan removals remain omissions even at or before from; baseline seeding and
interval replay apply the same validity rules, preserving missing-history evidence.
Agent contract JSON and TOON share a Unicode policy: lone UTF-16 surrogates are replaced with U+FFFD, while valid Unicode and authored whitespace stay intact. See the drift example and Unicode rules. Native tracker data and historical digests are unchanged.
Aus der README des Pakets auf GitHub. Auf GitHub ansehen