Publish a changelog for your app
Ship a CHANGELOG.md with your Pear app so users read release notes over peer-to-peer with the pear changelog command.
Any Pear application can ship a CHANGELOG.md. Stage it with the rest of your project and your users—or any third party—read your release notes straight from the app drive with pear changelog pear://<link>, semver-filtered and pretty-printed. It is the same command that prints the Pear platform's own changelog when you run pear changelog with no link.
The changelog lives in the app's Hyperdrive, so it is versioned, replicated, and readable peer-to-peer with no server and no separate publishing step—it travels with every stage and provision.
This is your application's own changelog. It is distinct from the docs-team Release Overview, which is a curated view of changes across Pear and its modules. To publish release notes for your app, follow this guide.
How it works
pear changelog reads a single file at the root of your app drive: /CHANGELOG.md. Under the hood the pear-changelog module parses it into one entry per release, then the command filters by version and prints each entry's notes. The filename and drive-root location are the entire contract—there is no manifest field to set and nothing to register.
Write CHANGELOG.md
Create a CHANGELOG.md at your project root (next to package.json). The format is lightweight:
- A header block at the top (typically a
# Title)—everything before the first##heading is ignored by the parser. Don't start the file with a##heading: the parser only recognizes headings that follow a line, so the first release would be dropped. - One release per level-2 heading (
## <version>), newest first. - The first space-separated token of each heading must be a SemVer version (a leading
vis allowed and stripped). Everything under a heading until the next##is free-form Markdown.
# Acme Chat Changelog
## v1.2.0
### Features
- Group threads with @mentions.
### Fixes
- Reconnect automatically after the sidecar restarts.
## v1.1.0
### Features
- Full-text message search.
## v1.0.0
Initial release.Keep the version as the first word of the heading, followed by a space. Bracketed Keep a Changelog headings such as ## [1.2.0] - 2026-01-01 aren't valid versions—those releases drop out of the default view and of any --of range (only --full still shows them). Use ## v1.2.0 or ## 1.2.0 instead. You can still add a date after the version, for example, ## v1.2.0 — 2026-01-01.
Check the format locally
Before staging, confirm the file parses the way pear changelog will read it—with the same pear-changelog module the CLI uses. Install it as a dev dependency:
npm install --save-dev pear-changelogCreate check-changelog.js next to the changelog:
const { readFileSync } = require('node:fs')
const { parse } = require('pear-changelog')
for (const [version] of parse(readFileSync('CHANGELOG.md'))) {
console.log('release:', version)
}Run it with Node:
node check-changelog.jsIt prints one line per release the parser found, newest first:
release: v1.2.0
release: v1.1.0
release: v1.0.0If a release is missing from the output, its heading didn't parse—pear changelog won't show it either.
Stage and seed it with your app
A root CHANGELOG.md is staged like any other project file—no extra flags. Just make sure it is not excluded by a pear.stage.ignore entry or dropped by a pear.stage.only filter that omits it.
Deploying a desktop app? The deployment directory that pear build assembles contains only package.json and by-arch/—your project's CHANGELOG.md is not copied in. Add it before staging: cp CHANGELOG.md ../<name>-<version>/.
pear stage --dry-run pear://<link> # confirm CHANGELOG.md appears in the diff
pear stage pear://<link>Then pear seed the link so peers can fetch it. Once staged, the file is retrievable at pear://<link>/CHANGELOG.md. Bump CHANGELOG.md in the same commit as your version bump so each release carries its own notes—see Ship your app for the full stage → provision flow.
Read it back
Anyone with the link reads your changelog with:
pear changelog pear://<link>By default this prints up to the 10 newest releases within the current major version, each with its full notes, separated by a divider. Tune it with the flags:
| Flag | Effect |
|---|---|
--of <semver> | Filter to a version range, for example, --of 1.x.x or --of '>=1.1.0 <2.0.0'. Defaults to the latest major. |
--max, -m <n> | Cap the number of entries shown (default 10). |
--full | Show every release (overrides --max); without --of, it also widens the range to all majors. |
--json | Emit newline-delimited JSON—one tagged object per release plus a final status object. Filter on "tag": "changelog" when scripting. |
pear changelog pear://<link> --of 1.x.x # only the 1.x releases
pear changelog pear://<link> --full # the entire history
pear changelog pear://<link> --json # machine-readableUse it for release announcements
Because the changelog is queryable by version range, it doubles as your source of truth for release notes. When you cut a release, pull the exact entries for the range you shipped and paste them into your announcement:
pear changelog pear://<link> --of '>=1.1.0' # everything since 1.1.0Relationship to pear dump
pear changelog is the structured view of the same file that pear dump returns raw:
pear dump pear://<link>/CHANGELOG.md - # raw Markdown, unparsed, to stdoutUse pear dump when you want the exact file bytes; use pear changelog when you want it parsed, semver-filtered, and formatted.
See also
pear changelogreference—the command and its flags.pear-changelogmodule—the parser that defines the format, with adiff()API for comparing changelogs.- Ship your app—the stage and provision flow the changelog travels with.
- Deploy your application—the full operator release flow.
- Configuration—
pear.stageoptions that control what gets staged.