Skip to content
Merged
2 changes: 1 addition & 1 deletion packages/agents/content/_partials/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Several skill bodies — `collaborate`, `design-and-plan`, and `refine-plan` amo

## Directive grammar

Three include shapes are recognized. Each must occupy a full line, with optional leading and trailing whitespace. Inline directives inside prose or code spans are not expanded.
Three include shapes are recognized. Each must occupy a full line, with optional leading and trailing whitespace. That whitespace governs recognition alone; injected lines keep the partial's own indentation rather than the directive's, so a directive cannot sit inside a list item. Inline directives inside prose or code spans are not expanded.

| Shape | Syntax | Use |
| ------------- | ------------------------------------------------ | --------------------------------------------------------------------------------- |
Expand Down
32 changes: 8 additions & 24 deletions packages/agents/content/_partials/voice-checklist.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,10 @@
Before saving, audit your draft against the rules below.
Before saving, audit the draft against the doctrine.

These rules are what this checklist tests. They do **not** cover register (change-narrating voice — `introduces`, `now`, `no longer`) or jargon discipline (define-while-naming). Those judgments aren't checklist-able and need the worked examples — read the `## Voice` and `## Jargon at the lede` sections of [`lede-voice.md`](../_data/lede-voice.md) before drafting. For a documentation change, also read the doc-PR carve-out under Rule 1: the outcome is what readers of the doc will now do or know, not what the doc says.
- **Subject.** The opening names the change, not the state of the system afterwards. A sentence that could have been written before the diff existed is not reporting it.
- **Type.** The per-type section governing this work type was applied -- for `perf`, `sec`, `deprecate`, and `ci`, the host section named there.
- **Names.** Every package, command, flag, file, or rule the reader needs is named and backticked, not described around.
- **Highlights.** Led by the fact that matters most. A catalog of every delta is not a lede.
- **Claims.** Each sentence reports an effect of the diff, and no claim outruns what the diff supports.
- **Cuts.** No empty contrast, no assurance against a harm nobody suspected, no process narration, no second person.

**Rule 1: Each sentence must be one of the following:**

- **Outcome**: What the reader will experience, see, or be able to do.
- **Migration info**: Names of user-facing surface added, removed, or renamed; steps the reader must take.

Cut any sentence describing mechanism (internal data, code paths, refactor mechanics, output-format details, internal counts). Indirect outcomes (reliability, performance) are permitted only if specific.

**Rule 2: Identifiers permitted only for top-level user-configurable surface:**

- Allowed: Package names, CLI commands and flags, top-level config-file paths, public-API endpoints/methods.
- Banned: Schema field names, default values for configurable names, internal file paths, function/type/class/module names, internal subsystem names, internal version markers, output-format details (JSON keys, marker glyphs, header strings).
- Exception: User-facing surface that has been added, removed, or renamed may be named for migration (both removed identifiers and new defaults).

**Rule 3: Each sentence must add something the reader doesn't already have.**

Cut a sentence (or clause) that only restates what's already given: a self-evident corollary of the change just stated ("…so temporary files are no longer left behind"), a harm-avoided guarantee no one doubted ("unrelated settings survive untouched"), or a paraphrase of a prior sentence. The deletion test — "would cutting this change what the reader knows?" — applies across sentences, not only within one.

**Audit before save:**

1. For each sentence, classify it: Outcome or Migration. Rewrite anything that fits none.
2. For each identifier, confirm it's in the allowed list. Drop or rephrase anything that isn't.
3. Compare sentences to one another and to the change's own implication. Cut any that only restate a prior sentence or the obvious consequence of one.
This list tests a draft; it does not stand in for the doctrine. Read [`lede-voice.md`](../_data/lede-voice.md) in full before drafting.
1 change: 0 additions & 1 deletion packages/agents/content/collections/triage.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ members:
- aspect-code-reviewer
- aspect-silent-failure-reviewer
- aspect-test-reviewer
- changelog-writer
- code-simplification-reviewer
- orchestrated-architect
- orchestrated-coder
Expand Down
276 changes: 52 additions & 224 deletions packages/agents/content/skills/_data/lede-voice.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/agents/content/skills/commit/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Render via `describe-change.sh` — see `../_data/title-templates.md` for the fu

- **72 characters max** (hard limit).
- **Imperative, task-oriented voice.** "Add…", "Fix…", "Prevent…", "Enable…" — describing what the coder did. The title appears next to the PR number in release notes; it reads as the task. Distinct from the lede voice, which is declarative ("Adds…", "Fixes…").
- For content discipline (outcome-not-mechanism, code-change-not-prompt, no ephemeral references, only what's in the diff), see the "Title application" section in [`lede-voice.md`](../_data/lede-voice.md).
- For content discipline (the code change rather than what prompted it, no ephemeral references, only what's in the diff), see [Titles](../_data/lede-voice.md#titles).
- Mark breaking changes by appending `!` to the work type: `agents|feat!: Remove deprecated API`. See [Breaking changes](#breaking-changes) below for which types are eligible.

## Ticket ID
Expand Down
2 changes: 1 addition & 1 deletion packages/agents/content/skills/merge-pr/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ git log {default_branch}..HEAD --format=%B
git diff {default_branch}...HEAD --stat
```

Describe the accomplishment from the reader's standpoint. One short paragraph is usually enough; add a follow-up paragraph only when the change is substantial.
Report what the change did. One short paragraph is usually enough; add a follow-up paragraph only when the change is substantial.

<!-- include: ../../_partials/voice-checklist.md / -->

Expand Down
29 changes: 7 additions & 22 deletions packages/agents/content/skills/summarize-change/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,30 +24,15 @@ Check commit messages for additional context.
3. **Compose title**: `{ticket_ref} {title}` (or just `{title}` when `ticket_ref` is null)
- The ticket reference appears in the change summary title (for identification) but must never appear in commit titles (per `commit` skill)

4. **Compose `## Why` and `## Details`** per the output format below. These sections you compose directly. The lede (`## What`) comes from a separate dispatch in step 6, so the factual substance must exist first.
4. **Compose `## Why` and `## Details`** per the output format below. The lede (`## What`) is composed last, in step 5, so the factual substance must exist first.

5. **Resolve tier**: From [work-types.json](../_data/work-types.json), look up the `tier` (`public`, `internal`, or `process`) corresponding to the resolved `type`. If `type` could not be inferred, default the tier to `internal`.
5. **Compose `## What`**: Read `{harness_home_dir}/skills/_data/lede-voice.md` in full before drafting; the doctrine evolves, so the only safe assumption is what the file says now. Write the lede from the branch diff and the sections composed in step 4, applying the per-type section for the change's work type (inferred per [Consumer-field inference](#consumer-field-inference)). The lede is composed last and placed first.

6. **Compose `## What` via `changelog-writer`**: Dispatch the `{subagent:changelog-writer}` subagent via the {tool:Task} tool in `write` mode. Pass a prompt of this shape:
6. **Save** per the [Saving](#saving) section.

```
mode: write
type: {resolved type}
tier: {tier from step 5}
scope: {resolved scope, if available}
outcome: |
{What the reader will experience, do, or know differently — the mechanism-free reader-facing delta, not a diff enumeration and not a draft lede. Derived from the substance composed in step 4.}
context: |
{Optional supporting facts the subagent may need for accuracy.}
```
**Audit before saving.** The `## What` composed in step 5 takes this audit before step 6 writes the artifact.

Lead with the outcome before naming files: `outcome` is the reader-facing delta the lede must carry, and it must be mechanism-free — state what changes for the reader, not how it was built. Do not pre-draft the lede here; implementation detail packed into `outcome` is laundering, and the subagent is required to cut it regardless. For a change to agent guidance, frame `outcome` as the instruction ("agents are now instructed to X"), not the resulting behavior ("the agent now does X"); see the agent-guidance carve-out in `lede-voice.md`. `context` is supplementary material the subagent may draw on for accuracy.

Use the subagent's returned text as the content of the `## What` section. The subagent owns voice; you own the outcome. If the subagent returns an error message (missing-field or similar), correct the dispatch inputs and retry.

Verbatim governs voice ownership, not quality acceptance — and not a prohibition on pruning. You are the last reader before the lede ships, so you are permitted, and expected, to cut cruft you can see: a mechanism-shaped sentence, a banned identifier, generic puffery. This is a backstop, not your main role — the subagent is the party obligated to return a clean draft (see its mandate), so you should rarely have much to remove. Pruning is delete-only: strike the offending clause or sentence and leave the rest untouched. What you may not do is rewrite for voice or register; if the draft needs rephrasing rather than trimming, re-articulate `outcome` and redispatch rather than editing the prose yourself.

7. **Save** per the [Saving](#saving) section.
<!-- include: ../../_partials/voice-checklist.md / -->

If expected information is missing, stop and ask the developer.

Expand All @@ -62,7 +47,7 @@ The body following the frontmatter has this structure:

## What

{Content returned by the `changelog-writer` dispatch in Process step 6. Prune any cruft you can see (delete-only); for voice or register problems, re-articulate `outcome` and redispatch rather than rewriting the prose (see step 6).}
{The lede, composed in Process step 5 under the doctrine.}

## Why

Expand Down Expand Up @@ -97,7 +82,7 @@ Good: "Heavy-upload sessions were intermittently failing as users hit the upstre
## Guidance

- When `ticket_ref` is null (no ticket on the branch), omit the `{ticket_ref} ` portion of the heading and the title so they read naturally without it.
- The change summary follows **newspaper style** — progressive disclosure from most to least essential: `## What` is the headline (outcome in plain language), `## Why` is the context (motivation and background), `## Details` is the full story (implementation mechanics)
- The change summary follows **newspaper style** — progressive disclosure from most to least essential: `## What` is the lede, `## Why` is the context (motivation and background), `## Details` is the full story (implementation mechanics)
- Ignore auto-formatter and lint-fix changes
- Omit inapplicable Details subsections
- Subsection headings use `{emoji} {label}` from the matching [work-types.json](../_data/work-types.json) `types[]` entry. For any subsection not enumerated in the example template above, look up the entry by work-type key and use its `emoji` and `label`.
Expand Down
68 changes: 0 additions & 68 deletions packages/agents/content/subagents/changelog-writer.md

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,10 @@ describe('library invocation edges', () => {
expect(closure.skills).toContain('capture-event');
});

it('pulls create-pr delegates and the changelog-writer they reach', async () => {
it('pulls create-pr delegates', async () => {
const closure = await resolveClosure({ skill: ['create-pr'] }, libraryResolver(contentDir));

expect(closure.skills).toEqual(expect.arrayContaining(['create-gh-pr', 'create-bitbucket-pr', 'summarize-change']));
expect(closure.subagents).toContain('changelog-writer');
});

it('pulls orchestrate dispatched subagents declared in frontmatter', async () => {
Expand Down