Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .agents/memory/LESSONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ Caps: 10 entries per section, 40 in total. Over the cap, the next review merges

## writing-user-docs

## writing-changelog

## cut-release

## work-issue
9 changes: 5 additions & 4 deletions .claude/skills/implement-issue/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ question under it, apply `status:blocked`, and stop. Do not guess.

Add one criterion of your own when the change is user-visible: the docs. Name the surfaces
from the `writing-user-docs` skill's table (README, `docs/`, website, the shipped skill, CLI
help, error text) and write them with that skill. The changelog line is separate and always
required.
help, error text) and write them with that skill. The changelog entry is always required and
is written with the `writing-changelog` skill.

## 3. Red tests

Expand Down Expand Up @@ -94,8 +94,9 @@ Do not widen scope. Something you notice that is not a criterion becomes an issu

## 5. Finish

- Add or amend the changelog line under `## Unreleased` if the change is user-visible. If
`Unreleased` is missing because a release was just cut, add the section.
- Add or amend the changelog entry under `## Unreleased` if the change is user-visible, with
the `writing-changelog` skill loaded. If `Unreleased` is missing because a release was just
cut, add the section.
- Run the `architecture` skill's "Before you open the PR" list against the diff.
- Fill the PR template fully. The E2E evidence section is filled by the `e2e-device` skill
(a separate run or subagent); leave it marked pending and say so in your report.
Expand Down
12 changes: 8 additions & 4 deletions .claude/skills/review-pr/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,14 @@ PR added and check each criterion has one that fails without the change.
- **Simplification checklist** from the `architecture` skill.
- **Changelog and docs.** A user-visible change that neither adds nor amends an `Unreleased`
line; a surface `docs/ARCHITECTURE.md` still describes the old way.
- **User-facing text.** READMEs, `docs/`, website, `skills/appduct`, CLI help, error messages
and changelog entries follow the `writing-user-docs` skill: implementation detail leaked,
marketing adjectives, time-relative words, an unhappy path left out. Load that skill when
the diff touches those paths.
- **Changelog entries** follow the `writing-changelog` skill: longer than two sentences, a
function, module, process or cause named, the kind wrong (`Breaking` missing on something
a user must act on, or `New` on a fix), a change no user could notice. Load that skill when
the diff touches `CHANGELOG.md`.
- **User-facing text.** READMEs, `docs/`, website, `skills/appduct`, CLI help and error
messages follow the `writing-user-docs` skill: implementation detail leaked, marketing
adjectives, time-relative words, an unhappy path left out. Load that skill when the diff
touches those paths.

You may run `pnpm typecheck` and the affected tests on the PR head. CI results come from
`gh pr checks`; do not repeat green CI jobs.
Expand Down
82 changes: 82 additions & 0 deletions .claude/skills/writing-changelog/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
name: writing-changelog
description: How to write a CHANGELOG.md entry - one bullet per change, one or two sentences, about what the user notices and never about how it was built. Load before adding or amending anything under Unreleased in CHANGELOG.md, before reviewing a diff that touches it, and before turning Unreleased into release notes.
---

# Changelog entries

Read the `writing-changelog` section of `.agents/memory/LESSONS.md` before starting, plus General.

The changelog is read by someone deciding whether an upgrade affects them. They scan it. They
are not implementing Appduct and they are not reading it to learn how a feature works; the
docs do that. The `writing-user-docs` voice and scope rules apply here unchanged; this skill
adds the form.

## Shape

One bullet per change, under `## Unreleased`:

```
- **<Kind>: <what the user notices>.** <At most one more sentence.>
```

- **Kind** is `New`, `Fix`, `Changed`, `Removed` or `Breaking`. `Breaking` is anything a user
must act on to upgrade; the `cut-release` skill reads `Breaking` and `New` to pick the version
bump, so the kind must be right. Docs-only changes are `Docs`.
- **The bold part is the whole change from the outside**: the command, flag, option, API,
MCP tool, error or behaviour the user meets, and what it does now. Name it exactly as the
user types or sees it.
- **The second sentence** is for the one thing they would trip on without it: a type or
option that was renamed, a default that moved, something they need to change on upgrade.
Or a link to the docs page that explains the feature. If there is nothing like that, stop
at the bold part.
- **Two sentences is the cap.** If a change needs more, the rest belongs in the docs and the
entry links there. A big feature gets one entry that says what you can now do and where to
read about it, not a restatement of the docs.

An entry never contains: a function, class, module or file name from the implementation,
which process or component did what, why the bug happened, what the fix touched, the type
that changed unless the user writes code against it, or the PR that shipped it.

## Test

Cover the bold part and ask: would a user of the CLI, the MCP server or one of the SDKs
notice this? If not, the change is not user-visible and gets no entry. Then cover everything
after the colon and ask of each word: does a user need it to decide whether to upgrade or to
upgrade safely? Cut every word that fails.

## Examples

Leaked:

```
- **Fix: the first Appduct command on a clean machine no longer fails with a bare `ENOENT`.**
Nothing created the state directory before the auto-spawn path wrote into it: `~/.appduct` is
created by `startDaemon`, but the spawn-lock and `daemon.log`'s fd are opened by the *parent*
process, before the daemon it spawns exists. So with no `~/.appduct` yet, every command that
auto-spawns a daemon failed with `ENOENT: ... open '~/.appduct/daemon.spawn.lock'` until
someone ran `appduct daemon run` in the foreground once. The auto-spawn path now creates the
directory (mode `0700`, same as the daemon would) before taking the lock.
```

Clean:

```
- **Fix: the first `appduct` command on a clean machine no longer fails with `ENOENT`.**
Commands that start the daemon for you now create `~/.appduct` themselves.
```

A feature:

```
- **New: tool groups.** A tool can declare a `group` such as `"cart"` or `"checkout/payment"`,
and `appduct tools --group <name>` and `appduct_list_tools` list one group; see
`docs/TOOLS.md`.
```

## Before you commit

1. Read only the bold parts down the section. Each one is a complete, true sentence on its own.
2. Every word after each colon passes the test above.
3. No entry is longer than two sentences.
4. Nothing under `Unreleased` describes a change a user could not notice.
4 changes: 2 additions & 2 deletions .claude/skills/writing-user-docs/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ agent reading the product skill. Anything they read to get something done is use
- `website/` content
- `skills/appduct/` (the skill shipped to users; not the repo's own `.claude/skills/`)
- CLI help text, error messages and MCP tool descriptions in `packages/appduct/src`
- `CHANGELOG.md` entries
- `CHANGELOG.md` entries, which have their own form in the `writing-changelog` skill

Not user-facing: `AGENTS.md`, `.claude/skills/`, `.agents/memory/`, `docs/ARCHITECTURE.md`,
`docs/PROTOCOL.md`, `docs/internal/`, code comments, PR and issue text.
Expand All @@ -37,7 +37,7 @@ contradict each other, which is worse than no docs.
| Setup, config or build variant | `skills/appduct/references/setup.md`; `website/src/content/docs/install`; `docs/BUILD-VARIANTS.md` |
| Security-relevant behaviour | `docs/SECURITY.md` |

Always: the changelog line, and `pnpm check:links` before the PR.
Always: the changelog entry (`writing-changelog` skill), and `pnpm check:links` before the PR.

The `review-pr` skill checks changes to the paths above against the rules below.

Expand Down
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pending

### Checklist

- [ ] `CHANGELOG.md` has a line under `Unreleased`, or the change is not user-visible
- [ ] `CHANGELOG.md` has an entry under `Unreleased` (`writing-changelog` skill), or the change is not user-visible
- [ ] User-facing docs updated for every surface the change touches (`writing-user-docs` skill), or the change is not user-visible
- [ ] No new import past a module's `index.ts`; no new direct `node:*` I/O outside an adapter
- [ ] Simplification checklist from the `architecture` skill applied, exceptions explained above
Expand Down
5 changes: 3 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pnpm playground:appduct -- <cli args> # this repo's CLI, from the
5. **Tests first.** Acceptance criteria from the issue, red tests committed before any
implementation, checkpoint commits that each lower the failing count.
6. **Changelog.** Every PR with a user-visible change adds or amends a line under
`## Unreleased` in [CHANGELOG.md](CHANGELOG.md).
`## Unreleased` in [CHANGELOG.md](CHANGELOG.md), written with the `writing-changelog` skill.
7. **Branches** are `issue-<N>-<slug>`, derived from the issue (see the implement-issue skill).
PRs reference the issue and follow the PR template.
8. **Nothing irreversible without a human**: no force push, no `gh pr merge`, no release, no
Expand Down Expand Up @@ -79,7 +79,8 @@ Load the skill before starting the matching task. They live in `.claude/skills/`
| Designing a feature too big for one PR, or sizing one | `design-feature` |
| Turning a request or a found bug into an issue (interviews first) | `file-issue` |
| Running the app on a simulator and driving it through the CLI | `e2e-device` |
| Writing or editing anything an Appduct user reads: READMEs, `docs/`, website, the shipped skill, CLI help, error messages, changelog | `writing-user-docs` |
| Writing or editing anything an Appduct user reads: READMEs, `docs/`, website, the shipped skill, CLI help, error messages | `writing-user-docs` |
| Adding, amending or reviewing an entry in `CHANGELOG.md` | `writing-changelog` |
| Cutting a release | `cut-release` |
| Curating agent memory (monthly, or when the inbox has notes) | `review-memory` |
| Taking an issue from `status:ready` to a reviewed, tested PR | `work-issue` (orchestrator) |
Expand Down
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ documented here. The three packages are versioned in lockstep (identical version
changelog covers all of them.

This file is maintained by hand; there is no automated changelog tooling. Every PR with a
user-visible change adds a line under `Unreleased`, and the release PR (see the `cut-release`
skill in `.claude/skills/`) turns that section into a versioned heading.
user-visible change adds a line under `Unreleased` in the form the `writing-changelog` skill in
`.claude/skills/` describes, and the release PR (see the `cut-release` skill there) turns that
section into a versioned heading.

## Unreleased

Expand Down
Loading