From 595328b552e4c4ac9b6767f8a38ab46817baae48 Mon Sep 17 00:00:00 2001 From: Sarah French Date: Wed, 22 Jul 2026 14:55:14 +0100 Subject: [PATCH 1/6] docs: Add style guide for change files --- .changes/STYLE-GUIDE.md | 202 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 .changes/STYLE-GUIDE.md diff --git a/.changes/STYLE-GUIDE.md b/.changes/STYLE-GUIDE.md new file mode 100644 index 000000000000..135f2ee2c9c6 --- /dev/null +++ b/.changes/STYLE-GUIDE.md @@ -0,0 +1,202 @@ +# 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 + +`-.yaml` + +Multi-word kinds include a space: `BUG FIXES-20260401-152120.yaml`, `UPGRADE NOTES-20260330-145227.yaml`. + +--- + +## 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=` `` +- 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=` 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`)? From ae442006961bb5236107770ba9874fcbe9ab5cff Mon Sep 17 00:00:00 2001 From: Sarah French Date: Wed, 22 Jul 2026 14:55:42 +0100 Subject: [PATCH 2/6] skill: Add agent skill for creating a change file --- .agents/skills/write-change-file/SKILL.md | 103 ++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 .agents/skills/write-change-file/SKILL.md diff --git a/.agents/skills/write-change-file/SKILL.md b/.agents/skills/write-change-file/SKILL.md new file mode 100644 index 000000000000..f2c028c941db --- /dev/null +++ b/.agents/skills/write-change-file/SKILL.md @@ -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/-.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: +body: "" +time: +custom: + Issue: "" +``` + +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. From f30acac1cf51aed9cd7c96c7570ce3e7c0f738ee Mon Sep 17 00:00:00 2001 From: Sarah French Date: Wed, 22 Jul 2026 14:56:28 +0100 Subject: [PATCH 3/6] Add IBM Bob `.bob` directory, symlink `.bob/skills` to the generic `.agents` directory's `skills` directory. --- .bob/README.md | 1 + .bob/skills | 1 + 2 files changed, 2 insertions(+) create mode 100644 .bob/README.md create mode 120000 .bob/skills diff --git a/.bob/README.md b/.bob/README.md new file mode 100644 index 000000000000..c8152a19f5b2 --- /dev/null +++ b/.bob/README.md @@ -0,0 +1 @@ +The `.bob/skills` directory is a symlink to the generic `.agents/skills` directory. diff --git a/.bob/skills b/.bob/skills new file mode 120000 index 000000000000..2b7a412b8fa0 --- /dev/null +++ b/.bob/skills @@ -0,0 +1 @@ +../.agents/skills \ No newline at end of file From 3b5a107c86c282e3c87121e89c72a770d087825d Mon Sep 17 00:00:00 2001 From: Sarah French Date: Wed, 22 Jul 2026 15:00:21 +0100 Subject: [PATCH 4/6] Link to the new style guide from our general contributing guidelines --- .github/CONTRIBUTING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index c9cf79170e39..91695c93cee1 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -154,6 +154,8 @@ This is different if you are backporting your changes to an earlier release vers #### Create a change file using `changie` +For more in-depth guidance, or guidance to be consumed by an agent, see our separate [style guide doc](../.changes/STYLE-GUIDE.md). + If your change is user-facing you can use `npx changie new` to create a new changelog entry via your terminal. The command is interactive and you will need to: 1. Select which kind of change you're introducing. 2. Provide a short description. From 5052614eaeeb7d87c918492f19fbafdba4fdb1b8 Mon Sep 17 00:00:00 2001 From: Sarah French Date: Wed, 22 Jul 2026 15:09:55 +0100 Subject: [PATCH 5/6] Move some content from the contribution guide to the style guide. --- .changes/STYLE-GUIDE.md | 16 ++++++++++++++++ .github/CONTRIBUTING.md | 20 ++++---------------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/.changes/STYLE-GUIDE.md b/.changes/STYLE-GUIDE.md index 135f2ee2c9c6..b818adbd049c 100644 --- a/.changes/STYLE-GUIDE.md +++ b/.changes/STYLE-GUIDE.md @@ -36,6 +36,22 @@ Multi-word kinds include a space: `BUG FIXES-20260401-152120.yaml`, `UPGRADE NOT --- +## 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. diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 91695c93cee1..a544c85e436c 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -154,9 +154,11 @@ This is different if you are backporting your changes to an earlier release vers #### Create a change file using `changie` -For more in-depth guidance, or guidance to be consumed by an agent, see our separate [style guide doc](../.changes/STYLE-GUIDE.md). +For in-depth guidance, or guidance to be consumed by an agent, see our separate [style guide doc](../.changes/STYLE-GUIDE.md). -If your change is user-facing you can use `npx changie new` to create a new changelog entry via your terminal. The command is interactive and you will need to: +If there isn't an impact on the end user then there shouldn't be a changelog entry. + +If your change is user-facing, you can use the `changie` CLI tool (see [installation guide](https://changie.dev/guide/installation/)) to create a new changelog entry via your terminal. The command is interactive and you will need to: 1. Select which kind of change you're introducing. 2. Provide a short description. 3. Enter the number of your GitHub PR. @@ -167,22 +169,8 @@ Your description should be written from an end-user's perspective and not descri > Fixed an issue where terraform stacks validate was failing to resolve relative paths for modules -If there isn't an impact on the end user then there shouldn't be a changelog entry. - Dependency bumps or other changes, like Go version upgrades, should only be in the changelog if the change impacts the user or fixes a user-facing issue. For example, if a dependency bump resolves a CVE that impacts Terraform and users are exposed to risk there should be a changelog entry. If the dependency bump is moving the code away from a version of a dependency that's linked to a CVE that isn't impacting Terraform then no changelog entry is needed. -Make sure to select the correct kind of change: - - -| Change kind | When to use | -|------------------|-------------| -| NEW FEATURES | Use this if you've added new, separate functionality to Terraform. For example, introduction of ephemeral resources. | -| ENHANCEMENTS | Use this if you've improved 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 if you've fixed a user-facing issue. Examples include: crash fixes, improvements to error feedback, regression fixes. | -| NOTES | This is used 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 if you've introduced 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 if you've introduced 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. | - #### Backport a PR to a past release PRs can be backported to previous release version as part of preparing a patch release. For example, a fix for a bug could be merged into main but also backported to one or two previous minor versions. From 7fc9caf2445166cc3aee80c607f66ac33adc94bc Mon Sep 17 00:00:00 2001 From: Sarah French Date: Wed, 22 Jul 2026 15:20:42 +0100 Subject: [PATCH 6/6] Remove .bob directory; it's unnecessary --- .bob/README.md | 1 - .bob/skills | 1 - 2 files changed, 2 deletions(-) delete mode 100644 .bob/README.md delete mode 120000 .bob/skills diff --git a/.bob/README.md b/.bob/README.md deleted file mode 100644 index c8152a19f5b2..000000000000 --- a/.bob/README.md +++ /dev/null @@ -1 +0,0 @@ -The `.bob/skills` directory is a symlink to the generic `.agents/skills` directory. diff --git a/.bob/skills b/.bob/skills deleted file mode 120000 index 2b7a412b8fa0..000000000000 --- a/.bob/skills +++ /dev/null @@ -1 +0,0 @@ -../.agents/skills \ No newline at end of file