-
Notifications
You must be signed in to change notification settings - Fork 10.6k
Add change file style guide and agent skill for making a change file. #38905
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
SarahFrench
wants to merge
6
commits into
main
Choose a base branch
from
add-change-file-styleguide-and-skill
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+326
−15
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
595328b
docs: Add style guide for change files
SarahFrench ae44200
skill: Add agent skill for creating a change file
SarahFrench f30acac
Add IBM Bob `.bob` directory, symlink `.bob/skills` to the generic `.…
SarahFrench 3b5a107
Link to the new style guide from our general contributing guidelines
SarahFrench 5052614
Move some content from the contribution guide to the style guide.
SarahFrench 7fc9caf
Remove .bob directory; it's unnecessary
SarahFrench File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| --- | ||
| name: write-change-file | ||
| description: Use when the user wants to create, write, or add a change file (changelog entry) for a Terraform PR or commit — guides producing a correctly formatted .changes/ YAML file. | ||
| --- | ||
|
|
||
| # Write a Change File | ||
|
|
||
| Follow the style guide at `.changes/STYLE-GUIDE.md` for all content rules, field definitions, and | ||
| examples. This skill covers the interactive steps to gather information and produce the file. | ||
|
|
||
| ## Step 0 — Is a change file even needed? | ||
|
|
||
| A changelog entry is only needed if a change is user-facing. | ||
|
|
||
| - Ask the user a yes/no question to confirm whether the change is user-facing. | ||
| - If the answer is no, stop creating a change file immediately and notify the user that one is not needed. | ||
|
|
||
| ## Step 1 — Gather required information | ||
|
|
||
| Collect anything not already provided in the user's request: | ||
|
|
||
| 1. **What changed?** Ask for a plain-language description of the change from a user's perspective. | ||
| 1. **What kind of change is it?** One of: `NEW FEATURES`, `ENHANCEMENTS`, `BUG FIXES`, `NOTES`, `UPGRADE NOTES`, `BREAKING CHANGES`. | ||
| 1. **What is the PR number?** (numeric only, e.g. `38397`). Note: the field is named `Issue` in the YAML for historical reasons, but it holds the PR number. | ||
|
|
||
| If the user provides a PR description, commit message, or diff, extract what you can from it and | ||
| only ask for what is still missing. | ||
|
|
||
| ## Step 2 — Draft the `body` field | ||
|
|
||
| Apply every rule in `.changes/STYLE-GUIDE.md` before writing the body. Key reminders: | ||
|
|
||
| - Present tense, active voice | ||
| - Lowercase area prefix + colon if scoped to a command (`init:`, `workspace:`, `test:`, etc.) | ||
| - Capitalise the first word after the prefix (or at sentence start) | ||
| - All identifiers — flags, block names, functions, attributes — in backticks | ||
| - `BUG FIXES`: describe the correct behaviour now, not the bug | ||
| - `UPGRADE NOTES`: end with a direct call to action ("Review...", "Verify...", "Update...") | ||
| - One sentence (two for `UPGRADE NOTES`) | ||
|
|
||
| ## Step 3 — Self-review the body | ||
|
|
||
| Check the draft against the quick checklist in `.changes/STYLE-GUIDE.md` before proceeding. Fix any | ||
| failures. | ||
|
|
||
| ## Step 4 — Create the file | ||
|
|
||
| The preferred approach is to use `changie new`, which handles filename generation, directory | ||
| placement, and field prompts automatically. Fall back to creating the file directly if `changie` | ||
| is not available. | ||
|
|
||
| ### Option A — Using `changie` (preferred) | ||
|
|
||
| If `changie` is not already installed, use one of these methods: | ||
|
|
||
| - **macOS (Homebrew):** `brew install changie` | ||
| - **Any platform (Go):** `go install github.com/miniscruff/changie@latest` | ||
| - **Other platforms:** See the [full installation guide](https://changie.dev/guide/installation/) | ||
|
|
||
| `changie` is configured via `.changie.yaml` and writes new entries to `.changes/v1.16/` | ||
| automatically. | ||
|
|
||
| Run the interactive command and respond to each prompt: | ||
|
|
||
| ``` | ||
| changie new | ||
| ``` | ||
|
|
||
| Prompts and how to answer them: | ||
|
|
||
| | Prompt | Answer | | ||
| | ----------- | ----------------------------------------- | | ||
| | `Kind` | Select the appropriate kind from the menu | | ||
| | `Body` | Paste the drafted body text from Step 2 | | ||
| | `PR Number` | Enter the numeric PR number | | ||
|
|
||
| `changie` generates the filename (including the timestamp) and writes the file. Confirm the | ||
| written path and show the user the `body` value for verification. | ||
|
|
||
| ### Option B — Creating the file directly | ||
|
|
||
| If `changie` is not available, create `.changes/v1.16/<KIND>-<YYYYMMDD-HHmmss>.yaml` manually | ||
| using the current local time for the timestamp. | ||
|
|
||
| Multi-word kinds include a space in the filename: `BUG FIXES-20260401-152120.yaml`. | ||
|
|
||
| File structure: | ||
|
|
||
| ```yaml | ||
| kind: <KIND> | ||
| body: "<body text>" | ||
| time: <RFC3339 timestamp with timezone offset> | ||
| custom: | ||
| Issue: "<PR number as string>" | ||
| ``` | ||
|
|
||
| Note: the `custom.Issue` key holds the PR number despite its name — this is a known quirk of the | ||
| project's changie configuration. | ||
|
|
||
| ## Step 5 — Confirm | ||
|
|
||
| Show the user the file path and the final `body` value so they can verify the wording before | ||
| committing. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,218 @@ | ||
| # Change File Style Guide | ||
|
|
||
| This guide governs the content of the `body` field in change files under `.changes/v*/`. | ||
| The body is rendered as a bullet point in `CHANGELOG.md`. | ||
|
|
||
| **Primary audience:** Terraform practitioners — people writing `.tf` files and running CLI commands day-to-day. Write for them, not for contributors or maintainers who know the internals. | ||
|
|
||
| --- | ||
|
|
||
| ## File structure | ||
|
|
||
| Each change file is a small YAML file placed in the version directory for the release it targets (e.g. `.changes/v1.16/`). | ||
|
|
||
| ```yaml | ||
| kind: ENHANCEMENTS | ||
| body: "workspace: The `workspace list` command can now produce machine-readable output when supplied with the `-json` flag" | ||
| time: 2026-04-17T11:06:28.651099+01:00 | ||
| custom: | ||
| Issue: "38397" | ||
| ``` | ||
|
|
||
| ### Fields | ||
|
|
||
| | Field | Value | | ||
| | -------------- | ---------------------------------------------------------------------------------------------------------------- | | ||
| | `kind` | One of: `NEW FEATURES`, `ENHANCEMENTS`, `BUG FIXES`, `NOTES`, `UPGRADE NOTES`, `BREAKING CHANGES`. | | ||
| | `body` | The user-facing description — see the rest of this guide | | ||
| | `time` | RFC3339 timestamp with timezone offset of when the file was created | | ||
| | `custom.Issue` | GitHub PR as a quoted string (e.g. `"38397"`). The field is called "Issue" for legacy reasons and is misleading! | | ||
|
|
||
| ### Filename format | ||
|
|
||
| `<KIND>-<YYYYMMDD-HHmmss>.yaml` | ||
|
|
||
| Multi-word kinds include a space: `BUG FIXES-20260401-152120.yaml`, `UPGRADE NOTES-20260330-145227.yaml`. | ||
|
|
||
| --- | ||
|
|
||
| ## Choosing the correct `kind` | ||
|
|
||
| Make sure to select the correct kind of change: | ||
|
|
||
|
|
||
| | Change kind | When to use | | ||
| |------------------|-------------| | ||
| | `NEW FEATURES` | Use this when adding new, separate functionality to Terraform. For example, introduction of ephemeral resources. | | ||
| | `ENHANCEMENTS` | Use this when improving existing functionality in Terraform. Examples include: adding a new field to a remote-state backend, or adding a new environment variable to use when configuring Terraform. | | ||
| | `BUG FIXES` | Use this when fixing a user-facing issue. Examples include: crash fixes, improvements to error feedback, regression fixes. | | ||
| | `NOTES` | Use this for changes that are unlikely to cause user-facing issues but might have edge cases. For example, changes to how the Terraform binary is built. | | ||
| | `UPGRADE NOTES` | Use this when introducing a change that forces users to take action when upgrading, or changes Terraform's behaviour notably. For example, deprecating a field on a remote-state backend or changing the output of Terraform operations. | | ||
| | `BREAKING CHANGES` | Use this when introducing a change that could make a valid Terraform configuration stop working after a user upgrades Terraform versions. This might be paired with an upgrade note change file. Examples include: removing a field on a remote-state backend, changing a builtin function's behavior, making validation stricter. | | ||
|
|
||
| --- | ||
|
|
||
| ## Core principles for `body` | ||
|
|
||
| 1. **User-focused, not implementation-focused.** Describe what the user can now do, or what they will now experience. Do not describe what changed internally. | ||
| 2. **Present tense, active voice.** Write as if describing the world as it is after the release, not what the team did to produce it. | ||
| 3. **One sentence.** Concise but complete. Only expand to two sentences for `UPGRADE NOTES` (change + call to action). | ||
|
|
||
| --- | ||
|
|
||
| ## Area prefix | ||
|
|
||
| When the change is scoped to a specific command, feature area, or subsystem, lead with a **lowercase** prefix followed by a colon and a space. | ||
|
|
||
| ``` | ||
| init: The `-upgrade` flag now ... | ||
| workspace: The `workspace list` command now ... | ||
| test: Terraform now raises a warning when ... | ||
| stacks: Output values are now included in ... | ||
| console: The `terraform console` command now ... | ||
| graph: The `terraform graph` command can now ... | ||
| state show: The `state show` command can now ... | ||
| cloud: ... | ||
| policy: ... | ||
| ``` | ||
|
|
||
| Omit the prefix only when the change is genuinely cross-cutting (affects all commands, or the core language itself). | ||
|
|
||
| **Capitalise the first word after the prefix:** | ||
|
|
||
| ``` | ||
| ✅ init: Errors due to incompatible flags are now raised earlier | ||
| ❌ init: errors due to incompatible flags are now raised earlier | ||
| ``` | ||
|
|
||
| **When there is no prefix, capitalise the first word of the body:** | ||
|
|
||
| ``` | ||
| ✅ `import` blocks now correctly respect provider local names | ||
| ❌ import blocks no longer ignore provider local names | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Verb tense and voice | ||
|
|
||
| Always use **present tense, active voice**. The subject is almost always Terraform, a specific command, or a language construct. | ||
|
|
||
| | ❌ Avoid | ✅ Prefer | | ||
| | -------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | | ||
| | `add support for import blocks inside modules` | `init: Import blocks inside modules are now supported` | | ||
| | `Fixed crash when configuration has an invalid action_trigger` | `stacks: Terraform no longer panics when a configuration contains an invalid \`action_trigger\` block` | | ||
| | `A -json flag was added to state show` | `state show: The \`state show\` command can now produce machine-readable output with the \`-json\` flag` | | ||
|
|
||
| --- | ||
|
|
||
| ## Technical identifiers | ||
|
|
||
| Always wrap the following in backticks: | ||
|
|
||
| - CLI commands and subcommands: `` `terraform plan` ``, `` `workspace list` `` | ||
| - Flags and options: `` `-json` ``, `` `-scope=<module address>` `` | ||
| - Block types and labels: `` `lifecycle` ``, `` `removed` ``, `` `action_trigger` `` | ||
| - Attribute and argument names: `` `skip_cleanup` ``, `` `bastion_host_key` ``, `` `for_each` `` | ||
| - Function names: `` `contains()` ``, `` `merge()` `` | ||
| - Special values: `` `null` `` | ||
|
|
||
| Do **not** use quotes in place of backticks: | ||
|
|
||
| ``` | ||
| ❌ The "workspace list" command now ... | ||
| ✅ The `workspace list` command now ... | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Per-category guidance | ||
|
|
||
| ### NEW FEATURES | ||
|
|
||
| Describe what the user can now do that they couldn't before. Name the HCL syntax, block, flag, or concept they interact with. | ||
|
|
||
| ``` | ||
| ✅ `import` blocks inside modules are now supported | ||
| ✅ `terraform_data`: The new `store` block can hold ephemeral and sensitive values across plan and apply | ||
| ``` | ||
|
|
||
| ### ENHANCEMENTS | ||
|
|
||
| Describe the improvement to existing behaviour. Lead with the area prefix where applicable. Focus on the new capability unlocked, not the mechanism added internally. | ||
|
|
||
| ``` | ||
| ✅ console: The `terraform console` command now accepts an optional `-scope=<module address>` flag, | ||
| which can be used to evaluate expressions within the scope of a specific module instance | ||
| ✅ graph: The `terraform graph` command can now output graphs in Mermaid format using the `-format=mermaid` flag | ||
|
|
||
| ❌ graph: add -format flag for Mermaid output | ||
| ❌ console: implement -scope flag | ||
| ``` | ||
|
|
||
| ### BUG FIXES | ||
|
|
||
| Describe the **correct behaviour now in place**, not the bug that existed. Use "now correctly", "no longer", "now raises" as natural anchors. | ||
|
|
||
| ``` | ||
| ✅ init: Terraform no longer removes locks from the dependency lock file for providers configured as `dev_override` | ||
| ✅ workspace: Terraform now raises an error if an invalid workspace name becomes selected due to out-of-band changes | ||
| ✅ `import` blocks now correctly respect provider local names | ||
|
|
||
| ❌ Fix a panic when the plan contained a no-op change for a deposed object | ||
| ❌ Fixed crash when configuration has invalid action_trigger | ||
| ``` | ||
|
|
||
| When the bug only manifests under specific conditions, include enough context for users to recognise whether they were affected — but keep it to one sentence: | ||
|
|
||
| ``` | ||
| ✅ `terraform apply` no longer panics when the plan contains a no-op change for a deposed resource | ||
| that has `lifecycle.precondition` or `lifecycle.postcondition` blocks | ||
| ``` | ||
|
|
||
| ### NOTES | ||
|
|
||
| Use for non-breaking behavioural changes or clarifications that don't fit neatly into `ENHANCEMENTS` or `BUG FIXES`. Same tense and voice rules apply. | ||
|
|
||
| ### UPGRADE NOTES | ||
|
|
||
| Describe the breaking or potentially breaking change, then include an explicit **call to action** — what the user must review, verify, or change before or after upgrading. | ||
|
|
||
| Use direct imperative language addressed to the user ("Review...", "Update...", "Verify..."), not passive constructions ("should be verified", "may need to be updated"). | ||
|
|
||
| ``` | ||
| ✅ `bastion_host_key` is now correctly applied by provisioners. Review your provisioner configurations | ||
| to verify the configured key is correct before upgrading. | ||
|
|
||
| ❌ Provisioner bastion_host_key is now correctly applied. Existing usage of bastion_host_key should | ||
| verify the configured key is correct. | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Anti-patterns | ||
|
|
||
| | Anti-pattern | Why | Fix | | ||
| | ------------------------------------------------------------------------------------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------- | | ||
| | Internal framing: `"add output values to plan component instance change description"` | Describes what the developer did, not what the user experiences | `"stacks: Plan output now includes output values for component instance changes"` | | ||
| | Commit-message style: `"Fix crash"`, `"Add support for"` | Reads as a commit, not a user-facing note | `"Terraform no longer crashes when..."`, `"X is now supported"` | | ||
| | No area prefix when the change is command-specific | Hard to scan in the rendered CHANGELOG | Add the relevant prefix: `"init: ..."`, `"test: ..."` | | ||
| | Identifiers without backticks: `"The -json flag"` | Inconsistent; harder to parse | ``"The `-json` flag"`` | | ||
| | Lowercase sentence start: `"import blocks no longer..."` | Reads as a fragment | ``"`import` blocks now correctly..."`` | | ||
| | Passive voice: `"Errors are now raised earlier"` | Hides the subject | `"Terraform now raises errors earlier"` | | ||
| | Over-long body explaining the full feature | The CHANGELOG is a summary; the issue link provides detail | One sentence max; link the issue | | ||
|
|
||
| --- | ||
|
|
||
| ## Quick checklist | ||
|
|
||
| Before committing a change file: | ||
|
|
||
| - [ ] Body is written from the user's perspective (impact, not implementation)? | ||
| - [ ] Present tense, active voice? | ||
| - [ ] Correct lowercase area prefix (with colon and space) if scoped to a command? | ||
| - [ ] First word after the prefix (or at the sentence start) is capitalised? | ||
| - [ ] All CLI flags, block names, function names, and identifiers are in backticks? | ||
| - [ ] `BUG FIXES`: describes the correct behaviour now in place, not the old bug? | ||
| - [ ] `UPGRADE NOTES`: includes a direct call to action using imperative language? | ||
| - [ ] One sentence (two for `UPGRADE NOTES`)? |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm toying with the idea to say this instead:
I believe our contribution guide currently assumes an audience of people first, and also agents second. Therefore we'd need calls to action for the separate groups.