Repository: JoshuaKGoldberg/create-typescript-app (ts)

Issue:
🐛 Bug: Additional h2s are dropped from README.md during transition
### Bug Report Checklist

- [x] I have tried restarting my IDE and the issue persists.
- [x] I have pulled the latest `main` branch of the repository.
- [x] I have [searched for related issues](https://github.com/JoshuaKGoldberg/create-typescript-app/issues?q=is%3Aissue) and found none that matched my issue.

### Expected

Running `npx create-typescript-app` in an existing repo shouldn't remove any custom README.md content.

### Actual

As seen in https://github.com/JoshuaKGoldberg/text-table-fast/pull/362/files#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L181, an `## Acknowledgements` section was removed.

### Additional Info

🎁 

Pull request description:
fix: preserve additional README.md content in transition
## PR Checklist

- [x] Addresses an existing open issue: fixes #2088
- [x] That issue was marked as [`status: accepting prs`](https://github.com/JoshuaKGoldberg/create-typescript-app/issues?q=is%3Aopen+is%3Aissue+label%3A%22status%3A+accepting+prs%22)
- [x] Steps in [CONTRIBUTING.md](https://github.com/JoshuaKGoldberg/create-typescript-app/blob/main/.github/CONTRIBUTING.md) were taken

## Overview

Switches from two string docs options -`documentation` and `usage` to an object with:

* `development`
* `readme`:
  * `additional`
  * `usage`

`readme.additional` is a new field that takes in content from `README.md` after a contributors table, if it exists.

🎁 

Patch:
diff --git a/docs/Configuration Files.md b/docs/Configuration Files.md
index 542a747..c184283 100644
--- a/docs/Configuration Files.md
+++ b/docs/Configuration Files.md
@@ -22,7 +22,7 @@ These options are generally only programmatically used internally, but can still
 | Option              | Description                                                              | Default (If Available)                                    |
 | ------------------- | ------------------------------------------------------------------------ | --------------------------------------------------------- |
 | `contributors`      | AllContributors contributors to store in `.all-contributorsrc`           | Existing contributors in the file, or just your username  |
-| `documentation`     | any additional docs to add to `.github/DEVELOPMENT.md`                   | Extra content in `.github/DEVELOPMENT.md`                 |
+| `documentation`     | additional docs to add to `.github/DEVELOPMENT.md` and/or `README.md`    | Extra content in those two files                          |
 | `existingLabels`    | existing labels to switch to the standard template labels                | Existing labels on the repository from the GitHub API     |
 | `explainer`         | additional `README.md` sentence(s) describing the package                | Extra content in `README.md` after badges and description |
 | `guide`             | link to a contribution guide to place at the top of development docs     | Block quote on top of `.github/DEVELOPMENT.md`            |
@@ -30,7 +30,6 @@ These options are generally only programmatically used internally, but can still
 | `node`              | Node.js engine version(s) to pin and require a minimum of                | Values from `.nvmrc` and `package.json`'s `"engines"`     |
 | `packageData`       | additional properties to include in `package.json`                       | Existing values in `package.json`                         |
 | `rulesetId`         | GitHub branch ruleset ID for main branch protections                     | Existing ruleset on the `main` branch from the GitHub API |
-| `usage`             | Markdown docs to put in `README.md` under the `## Usage` heading         | Existing usage lines in `README.md`                       |
 | `workflowsVersions` | existing versions of GitHub Actions workflows used                       | Existing action versions in `.github/workflows/*.yml`     |
 
 For example, changing `node` versions to values different from what would be inferred:
diff --git a/src/base.ts b/src/base.ts
index 15ece47..9a7996a 100644
--- a/src/base.ts
+++ b/src/base.ts
@@ -9,6 +9,7 @@ import { readAllContributors } from "./options/readAllContributors.js";
 import { readAuthor } from "./options/readAuthor.js";
 import { readBin } from "./options/readBin.js";
 import { readDescription } from "./options/readDescription.js";
+import { readDevelopmentDocumentation } from "./options/readDevelopmentDocumentation.js";
 import { readDocumentation } from "./options/readDocumentation.js";
 import { readEmailFromCodeOfConduct } from "./options/readEmailFromCodeOfConduct.js";
 import { readEmailFromGit } from "./options/readEmailFromGit.js";
@@ -28,13 +29,14 @@ import { readOwner } from "./options/readOwner.js";
 import { readPackageAuthor } from "./options/readPackageAuthor.js";
 import { readPackageData } from "./options/readPackageData.js";
 import { readPnpm } from "./options/readPnpm.js";
+import { readReadmeAdditional } from "./options/readReadmeAdditional.js";
+import { readReadmeUsage } from "./options/readReadmeUsage.js";
 import { readRepository } from "./options/readRepository.js";
 import { readRulesetId } from "./options/readRulesetId.js";
 import { readTitle } from "./options/readTitle.js";
-import { readUsage } from "./options/readUsage.js";
 import { readWords } from "./options/readWords.js";
 import { readWorkflowsVersions } from "./options/readWorkflowsVersions.js";
-import { zContributor, zWorkflowsVersions } from "./schemas.js";
+import { zContributor, zDocumentation, zWorkflowsVersions } from "./schemas.js";
 
 export const base = createBase({
 	options: {
@@ -58,10 +60,9 @@ export const base = createBase({
 			.default("A very lovely package. Hooray!")
 			.describe("'Sentence case.' description of the repository"),
 		directory: z.string().describe("Directory to create the repository in"),
-		documentation: z
-			.string()
-			.optional()
-			.describe("any additional docs to add to .github/DEVELOPMENT.md"),
+		documentation: zDocumentation.describe(
+			"additional docs to add to .md files",
+		),
 		email: z
 			.union([
 				z.string(),
@@ -154,10 +155,6 @@ export const base = createBase({
 			.optional()
 			.describe("GitHub branch ruleset ID for main branch protections"),
 		title: z.string().describe("'Title Case' title for the repository"),
-		usage: z
-			.string()
-			.optional()
-			.describe("Markdown docs to put in README.md under the ## Usage heading"),
 		version: z
 			.string()
 			.optional()
@@ -190,8 +187,17 @@ export const base = createBase({
 			async () => await readDescription(getPackageData, getReadme),
 		);
 
+		const getDevelopmentDocumentation = lazyValue(
+			async () => await readDevelopmentDocumentation(take),
+		);
+
 		const getDocumentation = lazyValue(
-			async () => await readDocumentation(take),
+			async () =>
+				await readDocumentation(
+					getDevelopmentDocumentation,
+					getReadmeAdditional,
+					getReadmeUsage,
+				),
 		);
 
 		const getEmail = lazyValue(
@@ -263,6 +269,14 @@ export const base = createBase({
 			async () => await readFileSafe("README.md", ""),
 		);
 
+		const getReadmeAdditional = lazyValue(
+			async () => await readReadmeAdditional(getReadme),
+		);
+
+		const getReadmeUsage = lazyValue(
+			async () => await readReadmeUsage(getEmoji, getReadme, getRepository),
+		);
+
 		const getRepository = lazyValue(
 			async () => await readRepository(getGitDefaults, getPackageData, options),
 		);
@@ -275,10 +289,6 @@ export const base = createBase({
 			async () => await readTitle(getReadme, getRepository),
 		);
 
-		const getUsage = lazyValue(
-			async () => await readUsage(getEmoji, getReadme, getRepository),
-		);
-
 		const getVersion = lazyValue(async () => (await getPackageData()).version);
 
 		const getWords = lazyValue(async () => await readWords(take));
@@ -308,7 +318,6 @@ export const base = createBase({
 			repository: getRepository,
 			rulesetId: getRulesetId,
 			title: getTitle,
-			usage: getUsage,
 			version: getVersion,
 			words: getWords,
 			workflowsVersions: getWorkflowData,
diff --git a/src/blocks/blockDevelopmentDocs.ts b/src/blocks/blockDevelopmentDocs.ts
index 73232c2..75d2be0 100644
--- a/src/blocks/blockDevelopmentDocs.ts
+++ b/src/blocks/blockDevelopmentDocs.ts
@@ -87,7 +87,9 @@ export const blockDevelopmentDocs = base.createBlock({
 			...Object.entries(addons.sections)
 				.sort(([a], [b]) => a.localeCompare(b))
 				.flatMap(([heading, section]) => printSection(heading, section)),
-			...(options.documentation ? [options.documentation] : []),
+			...(options.documentation.development
+				? [options.documentation.development]
+				: []),
 		];
 
 		return {
diff --git a/src/blocks/blockREADME.ts b/src/blocks/blockREADME.ts
index b5ded0f..fd29bfd 100644
--- a/src/blocks/blockREADME.ts
+++ b/src/blocks/blockREADME.ts
@@ -54,13 +54,16 @@ ${formatBadges(badges)}
 ${[logo, explainer].filter(Boolean).join("")}
 ## Usage
 
-${options.usage}
+${options.documentation.readme.usage}
 
 ## Development
 
 See [\`.github/CONTRIBUTING.md\`](./.github/CONTRIBUTING.md), then [\`.github/DEVELOPMENT.md\`](./.github/DEVELOPMENT.md).
 Thanks! ${options.emoji}
-${sections.map((section) => `\n${section}`).join("")}
+${[...sections, options.documentation.readme.additional]
+	.filter(Boolean)
+	.map((section) => `\n${section}`)
+	.join("")}
 ${notices.length ? `\n${notices.map((notice) => notice.trim()).join("\n\n")}` : ""}`,
 			},
 		};
diff --git a/src/blocks/options.fakes.ts b/src/blocks/options.fakes.ts
index c660862..6acd668 100644
--- a/src/blocks/options.fakes.ts
+++ b/src/blocks/options.fakes.ts
@@ -4,6 +4,11 @@ export const optionsBase = {
 	access: "public",
 	description: "Test description",
 	directory: ".",
+	documentation: {
+		readme: {
+			usage: "Test usage.",
+		},
+	},
 	email: {
 		github: "github@email.com",
 		npm: "npm@email.com",
diff --git a/src/options/readDevelopmentDocumentation.ts b/src/options/readDevelopmentDocumentation.ts
new file mode 100644
index 0000000..0965859
--- /dev/null
+++ b/src/options/readDevelopmentDocumentation.ts
@@ -0,0 +1,37 @@
+import { TakeInput } from "bingo";
+import { inputFromFile } from "input-from-file";
+
+import { swallowError } from "../utils/swallowError.js";
+
+const knownHeadings = new Set([
+	"building",
+	"development",
+	"formatting",
+	"linting",
+	"testing",
+	"type checking",
+]);
+
+export async function readDevelopmentDocumentation(take: TakeInput) {
+	const existing = swallowError(
+		await take(inputFromFile, {
+			filePath: ".github/DEVELOPMENT.md",
+		}),
+	);
+	if (!existing) {
+		return undefined;
+	}
+
+	return existing
+		.split(/\n\n(?=##\s)/)
+		.filter((section) => !knownHeadings.has(parseHeading(section)))
+		.join("\n\n");
+}
+
+function parseHeading(section: string) {
+	return section
+		.split("\n")[0]
+		.replace(/^#+\s+/, "")
+		.trim()
+		.toLowerCase();
+}
diff --git a/src/options/readDocumentation.ts b/src/options/readDocumentation.ts
index e836b06..b3802fa 100644
--- a/src/options/readDocumentation.ts
+++ b/src/options/readDocumentation.ts
@@ -1,37 +1,21 @@
-import { TakeInput } from "bingo";
-import { inputFromFile } from "input-from-file";
+import { Documentation } from "../schemas.js";
 
-import { swallowError } from "../utils/swallowError.js";
+export async function readDocumentation(
+	getDevelopmentDocumentation: () => Promise<string | undefined>,
+	getReadmeAdditional: () => Promise<string | undefined>,
+	getReadmeUsage: () => Promise<string>,
+): Promise<Documentation> {
+	const [additional, development, usage] = await Promise.all([
+		getReadmeAdditional(),
+		getDevelopmentDocumentation(),
+		getReadmeUsage(),
+	]);
 
-const knownHeadings = new Set([
-	"building",
-	"development",
-	"formatting",
-	"linting",
-	"testing",
-	"type checking",
-]);
-
-export async function readDocumentation(take: TakeInput) {
-	const existing = swallowError(
-		await take(inputFromFile, {
-			filePath: ".github/DEVELOPMENT.md",
-		}),
-	);
-	if (!existing) {
-		return undefined;
-	}
-
-	return existing
-		.split(/\n\n(?=##\s)/)
-		.filter((section) => !knownHeadings.has(parseHeading(section)))
-		.join("\n\n");
-}
-
-function parseHeading(section: string) {
-	return section
-		.split("\n")[0]
-		.replace(/^#+\s+/, "")
-		.trim()
-		.toLowerCase();
+	return {
+		development,
+		readme: {
+			additional,
+			usage,
+		},
+	};
 }
diff --git a/src/options/readReadmeAdditional.ts b/src/options/readReadmeAdditional.ts
new file mode 100644
index 0000000..745a187
--- /dev/null
+++ b/src/options/readReadmeAdditional.ts
@@ -0,0 +1,25 @@
+const indicatorAfterContributors = /<!--\s*spellchecker:\s*enable\s*-->/;
+
+const indicatorBeforeTemplatedBy =
+	/> .* This package was templated with |<!-- You can remove this notice/;
+
+export async function readReadmeAdditional(getReadme: () => Promise<string>) {
+	const readme = await getReadme();
+	if (!readme) {
+		return undefined;
+	}
+
+	const indexAfterContributors = indicatorAfterContributors.exec(readme);
+	if (!indexAfterContributors) {
+		return undefined;
+	}
+
+	const templatedByMatch = indicatorBeforeTemplatedBy.exec(readme);
+
+	return readme
+		.slice(
+			indexAfterContributors.index + indexAfterContributors[0].length,
+			templatedByMatch?.index,
+		)
+		.trim();
+}
diff --git a/src/options/readUsage.ts b/src/options/readReadmeUsage.ts
similarity index 91%
rename from src/options/readUsage.ts
rename to src/options/readReadmeUsage.ts
index 33c5855..3efbc84 100644
--- a/src/options/readUsage.ts
+++ b/src/options/readReadmeUsage.ts
@@ -1,6 +1,6 @@
 import { readUsageFromReadme } from "./readUsageFromReadme.js";
 
-export async function readUsage(
+export async function readReadmeUsage(
 	getEmoji: () => Promise<string>,
 	getReadme: () => Promise<string>,
 	getRepository: () => Promise<string | undefined>,
diff --git a/src/schemas.ts b/src/schemas.ts
index 79da9ba..e8804bb 100644
--- a/src/schemas.ts
+++ b/src/schemas.ts
@@ -10,6 +10,20 @@ export const zContributor = z.object({
 
 export type Contributor = z.infer<typeof zContributor>;
 
+export const zReadme = z.object({
+	additional: z.string().optional(),
+	usage: z.string(),
+});
+
+export type Readme = z.infer<typeof zReadme>;
+
+export const zDocumentation = z.object({
+	development: z.string().optional(),
+	readme: zReadme,
+});
+
+export type Documentation = z.infer<typeof zDocumentation>;
+
 export const zWorkflowVersion = z.object({
 	hash: z.string().optional(),
 	pinned: z.boolean().optional(),


Test patch:
diff --git a/src/base.test.ts b/src/base.test.ts
index 7b40e82..45cf284 100644
--- a/src/base.test.ts
+++ b/src/base.test.ts
@@ -20,7 +20,13 @@ describe("base", () => {
 			).contributors,
 			description:
 				"Quickstart-friendly TypeScript template with comprehensive, configurable, opinionated tooling. 🎁",
-			documentation: "",
+			documentation: {
+				development: expect.any(String),
+				readme: {
+					additional: expect.any(String),
+					usage: expect.any(String),
+				},
+			},
 			email: {
 				github: "github@joshuakgoldberg.com",
 				npm: "npm@joshuakgoldberg.com",
@@ -51,7 +57,6 @@ describe("base", () => {
 			pnpm: expect.any(String),
 			repository: "create-typescript-app",
 			title: "Create TypeScript App",
-			usage: expect.any(String),
 			version: expect.any(String),
 			// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-require-imports
 			words: require("../cspell.json").words,
diff --git a/src/blocks/blockCSpell.test.ts b/src/blocks/blockCSpell.test.ts
index 68169fd..0a1be95 100644
--- a/src/blocks/blockCSpell.test.ts
+++ b/src/blocks/blockCSpell.test.ts
@@ -280,7 +280,7 @@ describe("blockCSpell", () => {
 			  "scripts": [
 			    {
 			      "commands": [
-			        "node path/to/cspell-populate-words/bin/index.mjs --words "access" --words "public" --words "description" --words "Test description" --words "directory" --words "." --words "email" --words "github" --words "github@email.com" --words "npm" --words "npm@email.com" --words "emoji" --words "💖" --words "owner" --words "test-owner" --words "preset" --words "minimal" --words "repository" --words "test-repository" --words "title" --words "Test Title"",
+			        "node path/to/cspell-populate-words/bin/index.mjs --words "access" --words "public" --words "description" --words "Test description" --words "directory" --words "." --words "documentation" --words "readme" --words "usage" --words "Test usage." --words "email" --words "github" --words "github@email.com" --words "npm" --words "npm@email.com" --words "emoji" --words "💖" --words "owner" --words "test-owner" --words "preset" --words "minimal" --words "repository" --words "test-repository" --words "title" --words "Test Title"",
 			      ],
 			      "phase": 3,
 			    },
diff --git a/src/blocks/blockDevelopmentDocs.test.ts b/src/blocks/blockDevelopmentDocs.test.ts
index fe43995..8b6ab0b 100644
--- a/src/blocks/blockDevelopmentDocs.test.ts
+++ b/src/blocks/blockDevelopmentDocs.test.ts
@@ -149,7 +149,10 @@ describe("blockDevelopmentDocs", () => {
 		const creation = testBlock(blockDevelopmentDocs, {
 			options: {
 				...optionsBase,
-				documentation: "More documentation.",
+				documentation: {
+					...optionsBase.documentation,
+					development: "More documentation.",
+				},
 			},
 		});
 
diff --git a/src/blocks/blockREADME.test.ts b/src/blocks/blockREADME.test.ts
index d38ea11..3cc7b48 100644
--- a/src/blocks/blockREADME.test.ts
+++ b/src/blocks/blockREADME.test.ts
@@ -4,16 +4,11 @@ import { describe, expect, test } from "vitest";
 import { blockREADME } from "./blockREADME.js";
 import { optionsBase } from "./options.fakes.js";
 
-const options = {
-	...optionsBase,
-	usage: "Use it.",
-};
-
 describe("blockREADME", () => {
 	test("description with one sentence", () => {
 		const creation = testBlock(blockREADME, {
 			options: {
-				...options,
+				...optionsBase,
 				description: "One sentence.",
 			},
 		});
@@ -31,7 +26,7 @@ describe("blockREADME", () => {
 
 			## Usage
 
-			Use it.
+			Test usage.
 
 			## Development
 
@@ -47,7 +42,7 @@ describe("blockREADME", () => {
 	test("description with two sentences", () => {
 		const creation = testBlock(blockREADME, {
 			options: {
-				...options,
+				...optionsBase,
 				description: "First sentence. Second sentence.",
 			},
 		});
@@ -68,6 +63,46 @@ describe("blockREADME", () => {
 
 			## Usage
 
+			Test usage.
+
+			## Development
+
+			See [\`.github/CONTRIBUTING.md\`](./.github/CONTRIBUTING.md), then [\`.github/DEVELOPMENT.md\`](./.github/DEVELOPMENT.md).
+			Thanks! 💖
+
+			",
+			  },
+			}
+		`);
+	});
+
+	test("options.documentation", () => {
+		const creation = testBlock(blockREADME, {
+			options: {
+				...optionsBase,
+				documentation: {
+					development: "Development docs.",
+					readme: {
+						additional: "Additional docs.",
+						usage: "Use it.",
+					},
+				},
+			},
+		});
+
+		expect(creation).toMatchInlineSnapshot(`
+			{
+			  "files": {
+			    "README.md": "<h1 align="center">Test Title</h1>
+
+			<p align="center">Test description</p>
+
+			<p align="center">
+				<img alt="💪 TypeScript: Strict" src="https://img.shields.io/badge/%F0%9F%92%AA_typescript-strict-21bb42.svg" />
+			</p>
+
+			## Usage
+
 			Use it.
 
 			## Development
@@ -75,6 +110,7 @@ describe("blockREADME", () => {
 			See [\`.github/CONTRIBUTING.md\`](./.github/CONTRIBUTING.md), then [\`.github/DEVELOPMENT.md\`](./.github/DEVELOPMENT.md).
 			Thanks! 💖
 
+			Additional docs.
 			",
 			  },
 			}
@@ -84,7 +120,7 @@ describe("blockREADME", () => {
 	test("options.explainer", () => {
 		const creation = testBlock(blockREADME, {
 			options: {
-				...options,
+				...optionsBase,
 				explainer: ["And a one.", "And a two."],
 			},
 		});
@@ -105,7 +141,7 @@ describe("blockREADME", () => {
 
 			## Usage
 
-			Use it.
+			Test usage.
 
 			## Development
 
@@ -121,7 +157,7 @@ describe("blockREADME", () => {
 	test("options.logo without sizing", () => {
 		const creation = testBlock(blockREADME, {
 			options: {
-				...options,
+				...optionsBase,
 				logo: {
 					alt: "My logo",
 					src: "img.jpg",
@@ -144,7 +180,7 @@ describe("blockREADME", () => {
 
 			## Usage
 
-			Use it.
+			Test usage.
 
 			## Development
 
@@ -160,7 +196,7 @@ describe("blockREADME", () => {
 	test("options.logo with sizing", () => {
 		const creation = testBlock(blockREADME, {
 			options: {
-				...options,
+				...optionsBase,
 				logo: {
 					alt: "My logo",
 					height: 100,
@@ -185,7 +221,7 @@ describe("blockREADME", () => {
 
 			## Usage
 
-			Use it.
+			Test usage.
 
 			## Development
 
@@ -201,7 +237,7 @@ describe("blockREADME", () => {
 	test("options.explainer and options.logo", () => {
 		const creation = testBlock(blockREADME, {
 			options: {
-				...options,
+				...optionsBase,
 				explainer: ["And a one.", "And a two."],
 				logo: {
 					alt: "My logo",
@@ -230,7 +266,7 @@ describe("blockREADME", () => {
 
 			## Usage
 
-			Use it.
+			Test usage.
 
 			## Development
 
@@ -244,9 +280,7 @@ describe("blockREADME", () => {
 	});
 
 	test("without addons", () => {
-		const creation = testBlock(blockREADME, {
-			options,
-		});
+		const creation = testBlock(blockREADME, { options: optionsBase });
 
 		expect(creation).toMatchInlineSnapshot(`
 			{
@@ -261,7 +295,7 @@ describe("blockREADME", () => {
 
 			## Usage
 
-			Use it.
+			Test usage.
 
 			## Development
 
@@ -295,7 +329,7 @@ describe("blockREADME", () => {
 				notices: ["> Hello, world! 💖"],
 				sections: [`## Other\n\nHello!`],
 			},
-			options,
+			options: optionsBase,
 		});
 
 		expect(creation).toMatchInlineSnapshot(`
@@ -314,7 +348,7 @@ describe("blockREADME", () => {
 
 			## Usage
 
-			Use it.
+			Test usage.
 
 			## Development
 
diff --git a/src/options/readDocumentation.test.ts b/src/options/readDevelopmentDocumentation.test.ts
similarity index 63%
rename from src/options/readDocumentation.test.ts
rename to src/options/readDevelopmentDocumentation.test.ts
index 08ad7c0..487f5d0 100644
--- a/src/options/readDocumentation.test.ts
+++ b/src/options/readDevelopmentDocumentation.test.ts
@@ -1,10 +1,10 @@
 import { describe, expect, it } from "vitest";
 
-import { readDocumentation } from "./readDocumentation.js";
+import { readDevelopmentDocumentation } from "./readDevelopmentDocumentation.js";
 
-describe(readDocumentation, () => {
+describe(readDevelopmentDocumentation, () => {
 	it("returns undefined when no .github/DEVELOPMENT.md exists", async () => {
-		const documentation = await readDocumentation(() =>
+		const documentation = await readDevelopmentDocumentation(() =>
 			Promise.resolve(undefined),
 		);
 
@@ -12,7 +12,7 @@ describe(readDocumentation, () => {
 	});
 
 	it("filters known headings when .github/DEVELOPMENT.md exists", async () => {
-		const documentation = await readDocumentation(() =>
+		const documentation = await readDevelopmentDocumentation(() =>
 			Promise.resolve(`# Development\nremoved\n\n## Unknown\n\nKept.\n`),
 		);
 
diff --git a/src/options/readReadmeAdditional.test.ts b/src/options/readReadmeAdditional.test.ts
new file mode 100644
index 0000000..2825c25
--- /dev/null
+++ b/src/options/readReadmeAdditional.test.ts
@@ -0,0 +1,73 @@
+import { describe, expect, it } from "vitest";
+
+import { readReadmeAdditional } from "./readReadmeAdditional.js";
+
+describe(readReadmeAdditional, () => {
+	it("returns undefined when there is no existing readme content", async () => {
+		const getReadme = () => Promise.resolve("");
+
+		const result = await readReadmeAdditional(getReadme);
+
+		expect(result).toBeUndefined();
+	});
+
+	it("returns undefined when there is no contributors indicator", async () => {
+		const getReadme = () => Promise.resolve(`# My Package`);
+
+		const result = await readReadmeAdditional(getReadme);
+
+		expect(result).toBeUndefined();
+	});
+
+	it("returns all content after contributors when there is no template notice", async () => {
+		const getReadme = () =>
+			Promise.resolve(`# My Package
+
+Usage.
+
+<!-- spellchecker:enable -->
+
+After.
+`);
+
+		const result = await readReadmeAdditional(getReadme);
+
+		expect(result).toBe("After.");
+	});
+
+	it("returns all content after contributors when there is a comment template notice", async () => {
+		const getReadme = () =>
+			Promise.resolve(`# My Package
+
+Usage.
+
+<!-- spellchecker:enable -->
+
+After.
+
+<!-- You can remove this notice if you don't want it 🙂 no worries! -->
+`);
+
+		const result = await readReadmeAdditional(getReadme);
+
+		expect(result).toBe("After.");
+	});
+
+	it("returns all content after contributors when there is a quote template notice", async () => {
+		const getReadme = () =>
+			Promise.resolve(`# My Package
+
+Usage.
+
+<!-- spellchecker:enable -->
+
+After.
+
+> 💝 This package was templated with ...
+`);
+
+		const result = await readReadmeAdditional(getReadme);
+
+		expect(result).toBe("After.");
+	});
+});
diff --git a/src/options/readUsage.test.ts b/src/options/readReadmeUsage.test.ts
similarity index 85%
rename from src/options/readUsage.test.ts
rename to src/options/readReadmeUsage.test.ts
index d5bc91c..086eb33 100644
--- a/src/options/readUsage.test.ts
+++ b/src/options/readReadmeUsage.test.ts
@@ -1,6 +1,6 @@
 import { describe, expect, it, vi } from "vitest";
 
-import { readUsage } from "./readUsage.js";
+import { readReadmeUsage } from "./readReadmeUsage.js";
 
 const mockReadUsageFromReadme = vi.fn();
 
@@ -10,13 +10,13 @@ vi.mock("./readUsageFromReadme.js", () => ({
 	},
 }));
 
-describe(readUsage, () => {
+describe(readReadmeUsage, () => {
 	it("returns the existing usage when readUsageFromReadme provides one", async () => {
 		const existing = "Use it.";
 
 		mockReadUsageFromReadme.mockReturnValueOnce(existing);
 
-		const usage = await readUsage(
+		const usage = await readReadmeUsage(
 			() => Promise.resolve("💖"),
 			() => Promise.resolve(""),
 			() => Promise.resolve(undefined),
@@ -28,7 +28,7 @@ describe(readUsage, () => {
 	it("returns sample usage when readUsageFromReadme doesn't provide usage", async () => {
 		mockReadUsageFromReadme.mockReturnValueOnce(undefined);
 
-		const usage = await readUsage(
+		const usage = await readReadmeUsage(
 			() => Promise.resolve("💖"),
 			() => Promise.resolve(""),
 			() => Promise.resolve("test-repository"),