shelbi changelog
View as markdownshelbi changelog add --title <TITLE> [--date <DATE>] [--author <NAME>]
[--issue <ID>]... [--pr <N|URL>]... [--link <URL>]...
[-d <DESC> | stdin] [--format text|markdown|json]
shelbi changelog list [--limit <N>] [--since <DATE>] [--format text|markdown|json]
shelbi changelog search <QUERY> [--limit <N>] [--format text|markdown|json]
shelbi changelog show <ENTRY-ID> [--format text|markdown|json]Every project keeps a changelog: a blog-style record of what has shipped, so you and your agents can see what recently landed. The orchestrator adds an entry each time it merges work (see Changelog for the rule it follows), and you can add your own. The Changelog page in the sidebar of the TUI and the desktop app shows it, newest first.
Where entries live
Each entry is one markdown file with YAML frontmatter, in the project's Shelbi state directory:
~/.shelbi/projects/<project>/changelog/2026-10-28-213005-changelog-lands-in-the-sidebar.mdFiles are named <date>-<time>-<slug>.md from the entry's date in UTC, so they
sort by date. The slug is the title in lowercase words joined by -, cut at a
word boundary to at most 48 characters. The file name without .md is the
entry's id. Entries stay out
of your repository whatever the project's config mode.
---
title: Changelog lands in the sidebar
date: 2026-10-28T14:30:05-07:00
author: orchestrator
issues:
- changelog
prs:
- 1953
links:
- https://shelbi.dev/docs/cli/changelog
---
The sidebar's Activity row becomes Changelog.The frontmatter holds the title, the date (with time and offset), the author
(orchestrator, user, or an agent's name) and the links given as flags. The
body is the description. You can edit an entry by hand; a bare date: like
2026-10-28 still loads.
Two writers adding at the same moment never clobber each other: each add
claims a new file name, adding -2, -3 and so on when the name is taken.
Links
An entry can link Shelbi issues, pull requests, and any other URL. Give them as flags, or write them in the description:
| Flag | In the description | Links to |
|---|---|---|
--issue <id> | issue:<id> | A Shelbi issue by id, such as issue:tui-about. The TUI and the desktop app open it inside Shelbi. |
--pr <n|url> | #<n> | A pull request: a number in the project's GitHub repository (#1942), or a PR URL. |
--link <url> | any http:// or https:// URL | Any other page. A GitHub pull request URL counts as a PR. |
Code spans and fenced code blocks in the description are not scanned, and a
link must start a word (foo#12 is not a PR). A PR number resolves to a URL
against the project's GitHub issue tracker or, failing that, its repository's
origin remote when it points at github.com. With neither, the PR keeps its
number and has no URL.
The template
New entries are written from the project's changelog template:
~/.shelbi/projects/<project>/changelog-template.mdFor an in-repo project it sits in <repo>/.shelbi/ beside the other project
config. Every new project gets the default, and Shelbi adds it on start to any
project that predates it, never overwriting one that exists. Open it from
Settings, or from the command palette's Edit Changelog Template.
add fills these placeholders:
| Placeholder | Becomes |
|---|---|
{{title}} | The entry's title. |
{{date}} | Its date, YYYY-MM-DD. |
{{time}} | Its time of day, HH:MM. |
{{author}} | Who wrote it. |
{{description}} | The description from -d or stdin. |
{{links}} | The flag links, one per line as a markdown list. |
The default template is the description alone. The links live in the entry's
frontmatter, and the Changelog page in the TUI and the desktop app shows them
under every entry, so the default leaves {{links}} out. Add it back to your
template if you want the list in the description too. A comment at the top of
the template (<!-- ... -->) explains the placeholders and is left out of
every entry. Blank lines left by an empty placeholder are tidied away.
Older Shelbi releases shipped a template that ended with {{links}}. A project
whose template is still exactly that default moves to the current one on
start. A template you have edited is never changed. Entries written with the
old template keep their list until you run strip-links.
add
Adds an entry and prints its id and file.
| Option | Meaning |
|---|---|
--title <TITLE> | The entry's title, one line. Required. |
--date <DATE> | When it shipped. Defaults to now. Takes YYYY-MM-DD (keeping the current time of day), a local date and time (2026-10-28 14:30), or RFC 3339 (2026-10-28T14:30:00-07:00). |
--author <NAME> | orchestrator, user, or an agent's name. Defaults to $SHELBI_AGENT inside an agent's session, else user. |
--issue <ID> | Link a Shelbi issue. Repeatable. |
--pr <N|URL> | Link a pull request (1942, #1942, or a URL). Repeatable. |
--link <URL> | Link any other URL. Repeatable. |
-d, --description <DESC> | The description, in markdown. Without it, the description is read from stdin when stdin is not a terminal. |
--format <FORMAT> | How to print the new entry. Default text. |
Each link is stored once: a --link that is the URL of a --pr is dropped,
as is a flag given twice.
add refuses an --issue that isn't a valid issue id, a --pr that isn't a
number or URL, a --link that isn't an http(s) URL, an unreadable --date,
and a title or author that is empty or longer than one line. It writes nothing
when one is refused.
list
Lists entries, newest first.
| Option | Meaning |
|---|---|
--limit <N> | Show at most N entries. |
--since <DATE> | Only entries on or after this date. A bare date means the start of that day. |
--format <FORMAT> | Default text. |
search
Lists the entries whose title, description, or link targets contain every word
of the query, ignoring case, newest first. Link targets include issue ids
(board-perf), PR numbers (#1953) and URLs (pull/1953).
| Option | Meaning |
|---|---|
--limit <N> | Show at most N entries. |
--format <FORMAT> | Default text. |
show
Prints one entry. <ENTRY-ID> is the id list shows, or any prefix of it that
names one entry (2026-10-28-2130). The default format is markdown.
strip-links
Removes the list of links at the end of an entry's description when every item
in it is a link the entry already has in its frontmatter (issues:, prs: and
links:). That is the list the old default template wrote. A list with
anything else in it, or one that sits right under a line of prose, is left
alone, and the frontmatter is never changed. Prints each entry it changes.
| Option | Meaning |
|---|---|
--dry-run | List the entries that would change without writing them. |
Formats
text is a compact list: the date and title, then the id, the author and
the links. With nothing to show, it prints No changelog entries yet. (or
No changelog entries match `<query>`. for search). An entry file that
can't be read is skipped with a warning on stderr.
2026-10-28 14:30 Changelog lands in the sidebar
2026-10-28-213005-changelog-lands-in-the-sidebar orchestrator issue:changelog #1953markdown reads like the blog, full entries ready to paste or for an agent to read: a heading, a line with the date, author and id, the description, and any links the description doesn't already show.
json is for agents and scripts. list and search print an object with
the entries; show and add print one entry:
{
"schema_version": 1,
"project": "shelbi",
"query": "sidebar",
"entries": [
{
"id": "2026-10-28-213005-changelog-lands-in-the-sidebar",
"title": "Changelog lands in the sidebar",
"date": "2026-10-28T14:30:05-07:00",
"author": "orchestrator",
"description": "The sidebar's Activity row becomes Changelog.",
"links": [
{ "kind": "issue", "id": "changelog" },
{ "kind": "pr", "number": 1953, "url": "https://github.com/jlong/shelbi/pull/1953" },
{ "kind": "url", "url": "https://shelbi.dev/docs/cli/changelog" }
],
"path": "/Users/you/.shelbi/projects/shelbi/changelog/2026-10-28-213005-changelog-lands-in-the-sidebar.md"
}
]
}schema_versionchanges only when the shape breaks.queryappears onsearchonly.showandaddprintentryin place ofentries.dateis RFC 3339 with the offset the entry was written in.descriptionis the markdown body.linksholds every link, the flags' first and then the description's, without duplicates. Each has akind:issuewith anid;prwith anumberand aurl, either of which can benull(a#12with no known repository has no URL, a non-GitHub PR URL has no number);urlwith aurl.
Examples
Record a merge, linking its issue and PR:
shelbi changelog add --title "Faster board" --issue dt-board-perf --pr 1900 \
-d "Board columns are a virtualized list, so a long column scrolls smoothly."Take the description from a file on stdin:
shelbi changelog add --title "Zen pill redesign" --pr 1951 < notes.mdWhat landed this week, as an agent would read it:
shelbi changelog list --since 2026-10-26 --format markdownEverything about the board, as JSON:
shelbi changelog search board --format json