Guides
Workstreams
A workstream is a piece of work that takes more than one commit, such as “Keyboard support”. Start it, and your commits carry its name. Ship it, and the changelog shows them as one Highlight, with the commits folded underneath, instead of a flat list.
git commit adds the workstream’s line only through chamoji’s hook, and git
doesn’t clone hooks. Run chamoji hook install once in each clone, or commit
with chamoji commit.
Start, commit, ship
- Start it.
chamoji ws start "Keyboard support" ⌨️adds the workstream to.chamoji/workstreams.yml, stages the file, and makes it active in this worktree. - Commit as usual. While it’s active, each commit made with
git commit -mor-F, or withchamoji commit, gets aWorkstream: keyboard-supportline. - Ship it.
chamoji ws shipmarks it shipped in the file, stages the file, and stops adding the line.chamoji ws dropmarks it dropped instead. - Commit the file.
ws start,ws shipandws dropnever commit. Your next commit records the change. - Release. The next release shows the shipped workstream as one Highlight.
These are real runs in a small repo called widgets, which already has a v0.1.0 release and the hook installed:
Start and commit
$ chamoji ws start "Keyboard support" ⌨️
Started keyboard-support. Staged .chamoji/workstreams.yml; your next commit records it.
New commits in this worktree get "Workstream: keyboard-support".
* marks the active workstream. Three commits since the last tag carry its line. Now ship it:
chamoji ws ship
Shipped keyboard-support. Staged .chamoji/workstreams.yml; your next commit records it.
Saved 3 commits to memory.
The changelog reads the committed file, so until you commit the ship, the commits are still listed loose:
chamoji changelog --since v0.1.0
# Changelog
## Unreleased
### Added
- ✨ Jump to the first day with Home (360d510)
- ✨ Move between days with the arrow keys (73c619f)
…
Commit it with git commit -m "🔧 Ship keyboard support", and run chamoji release. The release’s section in CHANGELOG.md opens with the Highlight:
CHANGELOG.md
## v0.2.0 - 2026-11-05
### Highlights
- ⌨️ **Keyboard support**
- ✨ Jump to the first day with Home (360d510)
- ✨ Move between days with the arrow keys (73c619f)
- 🐛 Trap focus inside the dialog (ec02bc2)
### Added
- ✨ **picker:** Move between months with Page Up and Page Down (f553368)
### Changed
- 🔧 Ship keyboard support (8e496c1)
- ♿️ Label the day buttons (0792561)
### Fixed
- 🐛 Return null for an empty date (6f99029)
“Label the day buttons” was written in the editor during the workstream, so it has no Workstream: line and stays loose. What gets stamped explains why.
When it becomes a Highlight
- Only shipped workstreams fold. Commits of a workstream that is still active, or dropped, are listed as usual.
- As of that release. chamoji reads
.chamoji/workstreams.ymlas it was at each release’s tag, and for Unreleased atHEAD. So a workstream folds from the release that marked it shipped. Earlier releases don’t change, and its commits in an earlier release stay loose. - Breaking commits stay out. A breaking commit stays under Breaking changes, so it can’t be missed.
- The committed file counts. A ship that is only staged doesn’t show yet. Commit it before you preview the changelog.
A description in the file shows after the title:
chamoji changelog --since v0.1.0
…
### Highlights
- ⌨️ **Keyboard support:** Use the whole picker without a mouse.
- ✨ Jump to the first day with Home (360d510)
- ✨ Move between days with the arrow keys (73c619f)
- 🐛 Trap focus inside the dialog (ec02bc2)
…
What’s shared and what’s local
.chamoji/workstreams.yml is committed, so the team shares each workstream’s title, emoji, description, status and links. ws start writes the title, emoji and status, and ws ship and ws drop change the status. With a description and a link added by hand, it looks like this:
.chamoji/workstreams.yml
workstreams:
keyboard-support:
title: Keyboard support
emoji: ⌨️
status: shipped
description: Use the whole picker without a mouse.
links:
- https://github.com/acme/widgets/issues/12
The links appear in chamoji ws --json and in the JSON changelog, not in the Markdown or HTML one.
Which workstream is active is local. It lives in .git/chamoji/active, one per worktree, so two worktrees can work on two workstreams at once. Change it with chamoji ws switch <slug>, or clear it with chamoji ws switch --none to commit something unrelated.
What gets stamped
Stamped: commits made with git commit -m or -F, an amend with -m (the hook can’t tell it apart), and chamoji commit, including a message the composer writes through the hook.
git commit -F msg.txt
$ git log -1 --format=%B
✨ Jump to the first day with Home
Workstream: keyboard-support
Not stamped: merges, squashes, amends without -m, rebases, cherry-picks and reverts. A -m subject that starts Revert " or Reapply " isn’t stamped either, because a clean git revert looks the same to the hook.
Editor commits aren’t stamped. The hook runs before the editor opens, and adding a line to an empty message would stop git from aborting when you quit the editor. So for a plain git commit whose message you write in the editor, the hook prints a notice:
git commit
chamoji: editor commits aren't stamped; add "Workstream: keyboard-support" to the message, or use -m or chamoji commit.
[main 0792561] ♿️ Label the day buttons
1 file changed, 1 insertion(+)
create mode 100644 src/label.js
Add the Workstream: line yourself, or use -m or chamoji commit. A message from a commit.template works the same way.
In a fresh clone, no hook runs chamoji until you install it. ws start and ws switch read the hook git would run, including one set up through husky or lefthook, and say so:
chamoji ws start "Time zones" 🌍
Started time-zones. Staged .chamoji/workstreams.yml; your next commit records it.
chamoji: no hook runs chamoji here, so `git commit` won't add "Workstream: time-zones". Run `chamoji hook install`, or commit with `chamoji commit`.
They never install a hook for you.
Squash merges
chamoji reads Workstream: lines anywhere in a commit’s body. A squash that mixes workstreams gets the first one it finds. Whether the line survives a squash on GitHub depends on the repo’s squash message setting:
| GitHub’s squash message | The Workstream: line |
|---|---|
| Default message | Kept |
| Pull request title and commit details | Kept |
| Pull request title and description | Kept only if you add it to the description |
| Pull request title | Dropped, unless you add it in the merge box |
Commits that lose the line land outside their Highlight. chamoji setup checks this setting when it can, and recommends one of the first two.
What it leaves behind
ws ship and ws drop also save a summary of the workstream to project memory: its title, status, and its commits with their intent cards. It survives deleting the branch and a squash merge. The summary comes from the commits on HEAD, so run them on the branch that holds the work. Project memory shows how to read it back.