+
+
diff --git a/site/faq.md b/site/faq.md
new file mode 100644
index 000000000..9aa009160
--- /dev/null
+++ b/site/faq.md
@@ -0,0 +1,75 @@
+# Frequently Asked Questions
+
+Check the [guide](./guide/getting-started.md) to learn more about Changesets.
+
+## What is a changeset?
+
+A changeset is a Markdown file with YAML frontmatter. The contents of the Markdown is the change summary which will be written to the changelog and the YAML frontmatter describes the packages that have changed and their respective [semver](https://semver.org) bump types.
+
+They typically look like this:
+
+```md
+---
+"pkg-a": minor
+"pkg-b": patch
+---
+
+Summary of the change
+```
+
+## Do I need a changeset for every change?
+
+No! Since a changeset describes how a change should be released, changes that don't require a release do not need a changeset.
+
+## How do I add a changeset?
+
+Run the CLI to generate a changeset:
+
+::: code-group
+
+```bash [pnpm]
+$ pnpm changeset
+```
+
+```bash [npm]
+$ npx @changesets/cli
+```
+
+```bash [yarn]
+$ yarn changeset
+```
+
+:::
+
+And follow the prompts:
+
+1. If the project has multiple packages, select the packages you want to include.
+ - Use ↑ and ↓ to navigate to packages
+ - Press space to select a package.
+ - Press enter when all desired packages are selected.
+2. Select the appropriate [semver](https://semver.org) bump type for each selected package.
+3. Provide a message to go alongside the changeset. This will be written into the changelog when the next release occurs.
+
+ While not every changeset is going to need a huge amount of detail, a good idea of what should be in a changeset is:
+ - WHAT the change is
+ - WHY the change was made
+ - HOW a consumer should update their code
+
+A new changeset file will be created in the `.changeset` folder. Once you are happy with the changeset, commit the file to your branch.
+
+## Can I add more than one changeset in a PR?
+
+Yes! Changesets are designed to stack, so there's no problem with adding multiple. You might want to add more than one changeset when:
+
+- You want to release multiple packages with different changelog entries
+- You have made multiple changes to a package that should each be called out separately
+
+## Can I manually edit a changeset?
+
+Yes! You can edit the file name, Markdown summary, and YAML frontmatter package names and bump types after they're created or committed. The file name uses random human readable names by default to avoid collisions, but there's no harm in renaming them.
+
+You can also delete them if you feel the changeset is not needed for a previous change as long as it has not been released yet.
+
+## Are changesets removed?
+
+When `changeset version` is run, all changeset files are removed. This is so we only ever use a changeset once. This makes the `.changeset` folder a very bad place to store any other information.
diff --git a/site/guide/automating.md b/site/guide/automating.md
new file mode 100644
index 000000000..12d07eef3
--- /dev/null
+++ b/site/guide/automating.md
@@ -0,0 +1,69 @@
+# Automating Changesets
+
+While Changesets is designed to work with a fully manual process, it also provides tools to help automate these releases. These can be broken into two major decisions:
+
+1. How do I ensure pull requests have changesets?
+2. How do I run the version and publish commands?
+
+Here is a quick-start recommended workflow and more customization details.
+
+## Recommended Automation Flow
+
+1. Install the [Changesets GitHub Bot](https://github.com/apps/changeset-bot) into your repository.
+2. Add the [Changesets GitHub Action](https://github.com/changesets/action) to your repository.
+
+## How do I ensure pull requests have changesets?
+
+Changesets are committed to files, so a diligent reviewer can always technically tell if a changeset is absent and request one to be added. As humans though, a file not being there is easy to miss.
+
+We recommend adding some way to detect the presence or absence of changesets on a pull request so you don't have to, as well as highlight it directly to the pull request author.
+
+This has two main approaches.
+
+### Non-blocking
+
+In this approach, a pull request may be merged if no changeset is present, and a missing changeset does not cause a failure in CI. Our [Changesets GitHub Bot](https://github.com/apps/changeset-bot) is the best way to prompt for changesets without making them blocking.
+
+It comments on PRs of whether changesets are present and gives you link to add your own changeset as a maintainer to smooth over merging pull requests without waiting for the contributor to add a changeset.
+
+### Blocking
+
+As not every change requires a release, we **do not recommend** blocking contributions in the absence of a changeset. However, if you prefer a consistent process that always requires a changeset, you can add a step in your CI setup that runs:
+
+::: code-group
+
+```bash [pnpm]
+$ pnpm changeset status --since main
+```
+
+```bash [npm]
+$ npx @changesets/cli status --since main
+```
+
+```bash [yarn]
+$ yarn changeset status --since main
+```
+
+:::
+
+This will exit with code `1` if there are changed packages but no new changesets since main. It will not fail if there are no changed packages.
+
+If you want to merge a change without doing any releases (such as when you only change tests or build tools), you can run `changeset --empty` to add a special changeset that does not release anything.
+
+## How do I run the version and publish commands?
+
+You can set up the [Changesets GitHub Action](https://github.com/changesets/action) to automate this process:
+
+- It creates a `version` PR, then keeps it up to date, recreating it when merged.
+- Optionally, if publishing is set up, it automatically publishes the release whenever the PR is merged.
+
+If you do not want to use this action, the manual workflow we recommend is:
+
+1. A release coordinator (RC) calls to stop any merging to the base branch
+2. The RC pulls down the base branch, runs `changeset version`, then makes a new PR with the versioning changes
+3. The versioning changes are merged back into the base branch
+4. The RC pulls the base branch again and runs `changeset publish`
+5. The RC runs `git push --follow-tags` to push the release tags back
+6. The RC unblocks merging to the base branch
+
+This is a lot of steps and is quite finicky (we have to pull from the base branch twice). Feel free to finesse it to your own circumstances.
diff --git a/site/guide/backporting-changes.md b/site/guide/backporting-changes.md
new file mode 100644
index 000000000..c4d8e5ddd
--- /dev/null
+++ b/site/guide/backporting-changes.md
@@ -0,0 +1,45 @@
+# Backporting Changes
+
+Sometimes, you may need to backport changes to a previous versions for important bug fixes or security patches. Changesets can also be configured to make this process easier.
+
+## Setting Up
+
+Releases for previous versions require a separate branch for the version. For example, to backport to `1.x` versions, you can create a `v1` branch based on the git tag of the last `1.x` release.
+
+```bash
+$ git checkout -b v1 v1.2.3
+```
+
+Then, update the [`baseBranch`](./config.md#baseBranch) option with the branch name. This allows the [`add`](./cli.md#add) command to properly detect the changed packages.
+
+```json [.changeset/config.json]
+{
+ "baseBranch": "v1"
+}
+```
+
+If you have set up CI to [automatically run version and publish](./automating.md#how-do-i-run-the-version-and-publish-commands), make sure to allow running the workflow for this branch too.
+
+Also ensure the `publish` command is passed a custom `--tag` as we do not want backport releases to be tagged as `latest` on npm.
+
+```bash
+$ changeset publish --tag previous
+```
+
+::: danger Remember to set a tag
+This is **REALLY IMPORTANT** because if you do not include a tag, installing your package will default to the backport version, which is not what you want.
+:::
+
+Commit the changes and push the branch to your remote.
+
+```bash
+$ git add .
+$ git commit -m "Set up backport branch"
+$ git push -u origin v1
+```
+
+## Releasing Backport Versions
+
+When you want to release a backport version, you can run the [`version`](./cli.md#version) and [`publish`](./cli.md#publish) commands as usual. See the [Versioning and Publishing](./versioning-and-publishing.md) guide for the usual flow.
+
+As mentioned above, remember to pass a custom `--tag` if you're running the `publish` command manually.
diff --git a/site/guide/beyond-npm.md b/site/guide/beyond-npm.md
new file mode 100644
index 000000000..402bf89f2
--- /dev/null
+++ b/site/guide/beyond-npm.md
@@ -0,0 +1,37 @@
+# Beyond npm
+
+When using Changesets, you are not limited to only publishing to npm. Changesets can also be used to manage private packages such as applications or non-npm packages (i.e. dotnet NuGet packages, ruby gems, docker images, etc).
+
+The only requirement is that the project has a `package.json` file to manage the versions and dependencies within the repo. It should have at least `name`, `private` and `version` set:
+
+```json [packages/my-project/package.json]
+{
+ "name": "my-project",
+ "private": true,
+ "version": "0.0.1"
+}
+```
+
+And set [`privatePackages.version`](./config.md#privatepackages-version) to `true` in your `.changesets/config.json` file to enable versioning for these private packages. The packages can also be tagged during `changeset publish` by setting [`privatePackages.tag`](./config.md#privatepackages-tag) to `true`.
+
+## Private Dependencies
+
+Private packages can depend on other private packages that are ignored by the [`ignore`](./config.md#ignore) option. Since they aren't published to npm, it is safe for them to depend on ignored packages.
+
+For example, if you have an app `A` that depends on a private library `B`, you can ignore `B` while still versioning `A`:
+
+```json
+{
+ "ignore": ["B"]
+}
+```
+
+This works because `A` is private and will never be published to npm with a stale reference to `B`.
+
+## Automated Releases
+
+If [`privatePackages.tag`](./config.md#privatepackagestag) is enabled, you can also automate releases for private packages by following the [Automating Changesets](./automating.md) guide.
+
+When calling `changeset publish` from the GitHub Action, it will create the git tags and GitHub releases for the private packages. They will not be published to npm.
+
+You can also create custom workflows that trigger on tags/releases being created to publish the private packages to other environments.
diff --git a/site/guide/cli.data.ts b/site/guide/cli.data.ts
new file mode 100644
index 000000000..baf982e77
--- /dev/null
+++ b/site/guide/cli.data.ts
@@ -0,0 +1,170 @@
+import {
+ createMarkdownRenderer,
+ defineLoader,
+ type MarkdownRenderer,
+ type SiteConfig,
+} from "vitepress";
+import { cli } from "../../packages/cli/src/cli.ts";
+
+export interface Data {
+ mainHelpMessage: string;
+ initHelpMessage: string;
+ addHelpMessage: string;
+ versionHelpMessage: string;
+ publishHelpMessage: string;
+ publishPlanHelpMessage: string;
+ packHelpMessage: string;
+ gitTagHelpMessage: string;
+ preHelpMessage: string;
+}
+
+declare const data: Data;
+export { data };
+
+const helpMessageTasks: Record<
+ keyof Data,
+ {
+ flags: string[];
+ sections: string[];
+ processMessage?: (message: string) => string;
+ }
+> = {
+ mainHelpMessage: {
+ flags: ["--help"],
+ sections: ["Usage", "Commands"],
+ },
+ initHelpMessage: {
+ flags: ["init", "--help"],
+ sections: ["Usage", "Options", "Examples"],
+ },
+ addHelpMessage: {
+ flags: ["add", "--help"],
+ sections: ["Options", "Examples"],
+ processMessage: (log) =>
+ `\
+Usage:
+ $ changeset [options]
+ $ changeset add [options]
+
+${log}`,
+ },
+ versionHelpMessage: {
+ flags: ["version", "--help"],
+ sections: ["Usage", "Options", "Examples"],
+ },
+ publishHelpMessage: {
+ flags: ["publish", "--help"],
+ sections: ["Usage", "Options", "Examples"],
+ },
+ publishPlanHelpMessage: {
+ flags: ["publish-plan", "--help"],
+ sections: ["Usage", "Options", "Examples"],
+ },
+ packHelpMessage: {
+ flags: ["pack", "--help"],
+ sections: ["Usage", "Options", "Examples"],
+ },
+ gitTagHelpMessage: {
+ flags: ["tag", "--help"],
+ sections: ["Usage", "Options", "Examples"],
+ },
+ preHelpMessage: {
+ flags: ["pre", "--help"],
+ sections: ["Usage", "Options", "Examples"],
+ },
+};
+
+export default defineLoader({
+ async load(): Promise {
+ const data: Data = {
+ mainHelpMessage: "",
+ initHelpMessage: "",
+ addHelpMessage: "",
+ versionHelpMessage: "",
+ publishHelpMessage: "",
+ publishPlanHelpMessage: "",
+ packHelpMessage: "",
+ gitTagHelpMessage: "",
+ preHelpMessage: "",
+ };
+
+ const config: SiteConfig = (globalThis as any).VITEPRESS_CONFIG;
+ const renderer = await createMarkdownRenderer(
+ config.srcDir,
+ config.markdown,
+ config.site.base,
+ config.logger,
+ );
+
+ let logs: string[] = [];
+ const _info = console.info;
+ console.info = (...args) => {
+ logs.push(args.join(" "));
+ };
+
+ for (const [key, task] of Object.entries(helpMessageTasks)) {
+ logs = [];
+ cli.parse(["node", "changeset", ...task.flags], { run: false });
+ cli.runMatchedCommand();
+ data[key as keyof Data] = logs.join("\n");
+ }
+
+ console.info = _info;
+
+ await Promise.all(
+ Object.keys(data).map(async (key) => {
+ const message = data[key as keyof Data];
+ const task = helpMessageTasks[key as keyof Data];
+
+ let newMessage = getMessageSections(message, task.sections);
+ newMessage = task.processMessage?.(newMessage) ?? newMessage;
+
+ data[key as keyof Data] = await renderHelpMessage(renderer, newMessage);
+ }),
+ );
+
+ return data;
+ },
+});
+
+function getMessageSections(message: string, sections: string[]) {
+ const newLines: string[] = [];
+ let inSection: string | false = false;
+ for (const line of [...message.split("\n"), ""]) {
+ if (!inSection) {
+ // Start section when a line matches one of the section headers
+ if (sections.some((section) => line.startsWith(section + ":"))) {
+ inSection = line;
+ newLines.push(line);
+ }
+ } else {
+ // If empty line, we reach the end of the section
+ if (line.trim() === "") {
+ // If the last line is the same as the section header, it means the section has no content,
+ // so remove it
+ if (newLines.at(-1) === inSection) {
+ newLines.pop();
+ } else {
+ newLines.push(line);
+ }
+ inSection = false;
+ } else if (
+ // Skip known irrelevant lines
+ !line.includes("-v, --version") &&
+ !line.includes("-h, --help")
+ ) {
+ newLines.push(line);
+ }
+ }
+ }
+ return newLines.join("\n");
+}
+
+async function renderHelpMessage(renderer: MarkdownRenderer, message: string) {
+ const md = "```bash\n" + message + "\n```";
+ const html = (await renderer.renderAsync(md))
+ // VitePress auto-dedents lines that starts with `$`. We want to keep it indented and selectable.
+ .replace(/user-select:none;-webkit-user-select:none">\$/g, '"> $');
+
+ return html;
+}
diff --git a/site/guide/cli.md b/site/guide/cli.md
new file mode 100644
index 000000000..b48741656
--- /dev/null
+++ b/site/guide/cli.md
@@ -0,0 +1,179 @@
+
+
+# Command Line Interface
+
+The Changesets CLI is the main way of interacting with changesets. It provides a set of commands that allow you to manage your changesets, version your packages, and publish them.
+
+
+
+## init
+
+
+
+This command sets up the `.changeset` folder. It generates a readme and creates a config file through an interactive prompt. You should run this command once when you are setting up Changesets.
+
+## add
+
+
+
+This is the main command to interact with the changesets.
+
+It will ask you a series of questions, first about what packages you want to release, then what semver bump type for each package, then it will ask for a summary of the changes. The final step will show the changeset it will generate and confirm that you want to add it.
+
+Once confirmed, the changeset will be written in the `.changeset` folder. If the [`commit`](./config.md#commit) option is enabled, the changeset will be automatically committed to git.
+
+### Empty changesets
+
+If you have [CI that blocks merges](./automating.md#blocking) without a changeset, pass `--empty` to create an empty changeset.
+
+### Changing the base branch
+
+When prompting for packages to release, Changesets will detect and suggest the changed packages since the last commit on [`baseBranch`](./config.md#basebranch). If you want to use a different base branch, tag, or git ref, you can change it with the `--since [branch]` option.
+
+```bash
+$ changeset --since next
+```
+
+## version
+
+
+
+- **Related:** [Versioning and Publishing](./versioning-and-publishing.md#versioning)
+
+This is one of two commands responsible for releasing packages. The `version` command takes changesets that have been made and updates versions and dependencies of packages, as well as writing changelogs. It is responsible for all file changes before publishing to npm.
+
+::: tip Commit the version changes
+We recommend making sure changes made from this command are committed before you run publish:
+
+```bash
+$ git add .
+$ git commit -m "Version packages"
+```
+
+:::
+
+### Ignoring packages
+
+The `--ignore` flag allows you to skip packages from being published. This allows you to run partial publishes of the repository. This extends the [`ignore`](./config.md#ignore) option with the same documented caveats.
+
+```bash
+$ changeset version --ignore pkg-a --ignore pkg-b
+```
+
+### Snapshot releases
+
+You can use the `--snapshot` flag to create a [snapshot release](./snapshot-releases.md), meant for testing purposes only. The suffix for snapshot releases can be customized with `--snapshot-prerelease-template `, which works the same way as the [`snapshot.prereleaseTemplate`](./config.md#snapshotprereleasetemplate) option.
+
+It is highly recommended to read the [Snapshot Releases](./snapshot-releases.md) guide before using this flag.
+
+```bash
+$ changeset version --snapshot 'pr#123'
+```
+
+## publish
+
+
+
+- **Related:** [Versioning and Publishing](./versioning-and-publishing.md#publishing), [`pack` command](#pack)
+
+This command publishes changes to npm and creates git tags. It works by going into each package, checking if the version it has in its `package.json` is published on npm, and if it's not, run `npm publish` (or with the detected package-manager-specific publish command).
+
+Because this command assumes that the last commit is the version commit, you should not commit any changes between calling `version` and `publish`. These commands are separate to enable you to check if the release changes are accurate.
+
+Git tags for each package are also created by default. This allows users to easily find the code for a specific release. The tags created are in the format of `pkg-name@X.X.X`, or in single-package repos, it is `vX.X.X`. Pass `--no-git-tag` to disable this.
+
+Make sure to push the tags to your git remote after creating them:
+
+```bash
+$ git push --follow-tags
+```
+
+::: warning Accidental publishes
+As the `publish` command automatically publishes versions that are not yet published, it's possible to accidentally publish a new package that has not been versioned before.
+
+For example, when [Automating Changesets](./automating.md) (where it calls `publish` if there are no changesets to create a version PR) or automated [Snapshot Releases](./snapshot-releases.md), it may unintentionally publish the new package. To prevent this, make sure to set `"private": true` in the `package.json` of packages that should not be published.
+:::
+
+### OTP
+
+When publishing locally, you may be prompted for a one-time password (OTP) if your have two-factor authentication enabled on npm. You can provide this OTP directly with the `--otp ` flag to avoid the prompt.
+
+```bash
+$ changeset publish --otp 123456
+```
+
+### NPM dist-tags
+
+Published versions are tagged on npm with `latest` by default. You may want to change the [dist-tag](https://docs.npmjs.com/adding-dist-tags-to-packages) when publishing [snapshot releases](./snapshot-releases.md) to prevent them from being installed by default. Pass `--tag ` to publish with a different dist-tag.
+
+```bash
+$ changeset publish --tag beta
+```
+
+## publish-plan
+
+
+
+- **Related:** [Versioning and Publishing](./versioning-and-publishing.md#publishing), [`pack` command](#pack), [`publish` command](#publish)
+
+Show packages that are ready to publish or tag. If `--output` is passed, the JSON will be written to the file which can be used later by the `pack` and `publish` commands. `--output` is marked experimental as the format may change between patches, however the output will always work if passed to the same version of `pack` and `publish` commands.
+
+This is useful for CI pipelines that want to split the version and publish steps to check if there are packages to publish.
+
+## pack
+
+
+
+- **Related:** [Versioning and Publishing](./versioning-and-publishing.md#publishing), [`publish` command](#publish)
+
+Pack publishable packages into tarballs. The `--out-dir` flag is required to write the output to the directory, which the same directory can be passed to `publish --from-pack-dir` so the `publish` command picks up the tarballs and publishes them.
+
+This is useful for CI pipelines that want to split the build and publish steps.
+
+## status
+
+
+
+The status command provides information about the changesets that currently exist. If there are changes to packages but no changesets are present, it exits with code `1`.
+
+### JSON output
+
+Pass `--output ` write the status output as a JSON file so it can be consumed by other tools.
+
+```bash
+$ changeset status --output status.json
+```
+
+### Status since a specific branch
+
+You can use `--since ` with a different branch, tag, or git ref to only display the information about changesets since that point.
+
+```bash
+$ changeset status --since next
+```
+
+::: warning
+`status` will fail if you are in the middle of running `version` or `publish`. If you want to get changeset status at the time of a version increase and publish, you need to run it immediately before running `version`.
+:::
+
+## git-tag
+
+
+
+The `git-tag` command creates git tags for the current version of all packages. The tags created are equivalent to those created by the [`publish`](#publish) command, but the `git-tag` command does not publish anything to npm.
+
+This is helpful in situations where a different tool is used to publish packages instead of Changesets. The tags created are in the format `pkg-name@X.X.X`, or in single-package repos, it is `vX.X.X`. It is expected to run the `version` command first so the created tags are up to date.
+
+## pre
+
+
+
+The `pre` command is used to enter or exit [prerelease mode](./prereleases.md). It does not do any versioning but prepares Changesets in a state for prereleases.
+
+When you want to do a prerelease, run `pre enter ` to enter prerelease mode with the given tag, then do the normal release process as usual. When you're ready for a stable release, run `pre exit` and do the normal release process again.
+
+::: warning Prereleases are complicated
+Many of the safety rails that Changesets helps you with are taken off in prerelease mode. You may also prefer using [snapshot releases](./snapshot-releases.md) for a slightly less involved process. It is highly recommended to read through the [prereleases](./prereleases.md) documentation before using this command.
+:::
diff --git a/site/guide/config.md b/site/guide/config.md
new file mode 100644
index 000000000..f1d364879
--- /dev/null
+++ b/site/guide/config.md
@@ -0,0 +1,284 @@
+# Configuration File
+
+Changesets keeps its configuration in `.changeset/config.json`. The default config is:
+
+```json [.changeset/config.json]
+{
+ "changelog": "@changesets/cli/changelog",
+ "commit": false,
+ "fixed": [],
+ "linked": [],
+ "access": "restricted",
+ "baseBranch": "main",
+ "changedFilePatterns": ["**"],
+ "format": "auto",
+ "privatePackages": { "version": false, "tag": false },
+ "updateInternalDependencies": "patch",
+ "ignore": [],
+ "bumpVersionsWithWorkspaceProtocolOnly": false
+}
+```
+
+## changelog
+
+- **Type:** `false | string | [string, Record]`
+- **Default:** `"@changesets/cli/changelog"`
+
+Set how the changelog for packages should be generated. The default changelog generator is `@changesets/cli/changelog` (an alias to `@changesets/changelog-git`) which adds related commit links to each changeset entry in the changelog. If it is set to `false`, no changelogs will be generated.
+
+You can also specify a custom changelog generator by providing a string or a tuple with the module path and options. The module can be an npm package or a relative file path. Check out the [Customize Changelog Format](./customize-changelog-format.md) guide to learn how to write your own changelog generator.
+
+If a tuple (`[string, Record]`) is set, you can pass options in the second item of the tuple to configure the changelog generator. For example, if you are using `@changesets/changelog-github`, you can pass the `repo` options like this:
+
+```json [.changeset/config.json]
+{
+ "changelog": ["@changesets/changelog-github", { "repo": "owner/repo" }]
+}
+```
+
+Consult the documentation for the changelog generator you're using for more information on the options you can pass to it.
+
+Read more about the [`@changesets/changelog-github` package](/packages/changelog-github).
+
+## commit
+
+- **Type:** `boolean | string | [string, Record]`
+- **Default:** `false`
+
+Enable this option to automatically commit the changes when running the `changeset add` and `changeset version` commands. If set to `true`, the default commit message generator (`["@changesets/cli/commit", { "skipCI": "version" }]`) will be used.
+
+This option works similarly to the [`changelog`](#changelog) option. Check out the [Customize Commit Format](./customize-commit-format.md) guide to learn how to write your own commit message generator.
+
+## fixed
+
+- **Type:** `string[][]`
+- **Default:** `[]`
+- **Related:** [Fixed Packages](./fixed-packages.md)
+- **Note:** Only applicable in monorepos.
+
+Declare that packages should be version-bumped and published together. Supports [picomatch patterns](https://github.com/micromatch/picomatch) to match packages.
+
+For example, if you have `pkg-a@1.0.0` and `pkg-b@1.0.0`, when one gets bumped to `1.1.0`, the other is also bumped to `1.1.0` regardless if it has any change or not. To achieve this, you can configure like so:
+
+```json [.changeset/config.json]
+{
+ "fixed": [["pkg-a", "pkg-b"], ["@scope/*"]]
+}
+```
+
+Learn more about the implementation and implications in the [Fixed Packages](./fixed-packages.md) guide.
+
+## linked
+
+- **Type:** `string[][]`
+- **Default:** `[]`
+- **Related:** [Linked Packages](./linked-packages.md)
+- **Note:** Only applicable in monorepos.
+
+Declare that packages should "share" a version together. Supports [picomatch patterns](https://github.com/micromatch/picomatch) to match packages.
+
+For example, if you have `pkg-a@1.0.0` and `pkg-b@1.1.0`, if `pkg-a` is minor-bumped, it uses the shared highest version in the group which is `1.1.0` and bumps to `1.2.0`. `pkg-b` will not be explicitly bumped. To achieve this, you can configure like so:
+
+```json [.changeset/config.json]
+{
+ "linked": [["pkg-a", "pkg-b"], ["@scope/*"]]
+}
+```
+
+Learn more about the implementation and implications in the [Linked Packages](./linked-packages.md) guide.
+
+::: warning This does not do what some other tools do
+
+If you want to ensure the packages are always published with the same version, use the [`fixed`](#fixed) option instead.
+
+:::
+
+## access
+
+- **Type:** `"restricted" | "public"`
+- **Default:** `"restricted"`
+
+Sets how packages are published. If `access: "restricted"`, packages will be published as private, requiring log in to an npm account with access to install. If `access: "public"`, the packages will be made available on the public registry.
+
+By default, npm publishes scoped npm packages as `restricted`, so to ensure you do not accidentally publish code publicly, we default to `restricted`. For most cases you will want to set this to `public`.
+
+This can be overridden in specific packages by setting `"publishConfig": { "access": "..." }` in a package's `package.json`.
+
+If you want to prevent a package from being published to npm, set `"private": true` in that package's `package.json`
+
+## baseBranch
+
+- **Type:** `string`
+- **Default:** `"main"`
+
+The branch to which Changesets will make comparisons to detect what has changed since the last commit of the base branch. This should generally be set to the default branch you merge changes into, e.g. `main` or `master`.
+
+Commands that use this information accept a `--since` option which can be used to override this.
+
+Locally, make sure the base branch exists and is up to date so Changesets can make accurate comparisons.
+
+## changedFilePatterns
+
+- **Type:** `string[]`
+- **Default:** `["**"]`
+
+The [picomatch patterns](https://github.com/micromatch/picomatch) for changed files that should mark a package as changed. Useful to fine-tune what counts as a change (e.g. only source files, ignoring test files, etc).
+
+Example:
+
+```json [.changeset/config.json]
+{
+ "changedFilePatterns": ["src/**", "lib/**"]
+}
+```
+
+## format
+
+- **Type:** `"auto" | "prettier" | "oxfmt" | "deno" | "dprint" | false`
+- **Default:** `"auto"`
+
+The code formatter to use for generated changeset files and changelogs. If set to `false`, no formatting will be applied.
+
+In `"auto"` mode, Changesets uses [@changesets/format](https://github.com/changesets/format) to automatically detect the preferred code formatter used in the project and applies it to generated files. You can explicitly set the formatter if you have multiple formatters set up in your project.
+
+## privatePackages
+
+- **Type:** `{ version?: boolean; tag?: boolean } | boolean`
+- **Related:** [Beyond npm](./beyond-npm.md)
+
+Controls how private packages should be versioned and tagged. By default, Changesets will not version or tag private packages. Set `true` to version and tag private packages, or use the object form to configure each behavior separately.
+
+### privatePackages.version
+
+- **Type:** `boolean`
+- **Default:** `false`
+
+Whether to update the version of private packages when running `changeset version`.
+
+### privatePackages.tag
+
+- **Type:** `boolean`
+- **Default:** `false`
+
+Whether to create a tag for private packages when running `changeset publish`.
+
+## updateInternalDependencies
+
+- **Type:** `"patch" | "minor"`
+- **Default:** `"patch"`
+- **Note:** Only applicable in monorepos.
+
+Controls how internal dependencies should be updated when the depended-upon package is updated. To make this more understandable, here is an example:
+
+Say we have two packages, one depending on the other:
+
+```
+pkg-a @ version 1.0.0
+pkg-b @ version 1.0.0
+ depends on pkg-a at range ^1.0.0
+```
+
+And we are publishing a patch of both `pkg-a` and `pkg-b`. If the option is set to `patch`, we will update the pkg-a dependency range so we will now have:
+
+```
+pkg-a @ version 1.0.1
+pkg-b @ version 1.0.1
+ depends on pkg-a at range ^1.0.1 <-- updated
+```
+
+However, if the option is set to `minor`, the range will only be updated when there is a minor change:
+
+```
+pkg-a @ version 1.0.1
+pkg-b @ version 1.0.1
+ depends on pkg-a at range ^1.0.0 <-- not updated
+```
+
+Using `minor` allows consumers to more actively control their own deduplication of packages, and will allow them to install fewer versions if you have many interconnected packages. Using `patch` will mean consumers will more often be using updated code, but may cause problems with deduplication.
+
+Changesets will always update the dependency range if it would leave the old semver range.
+
+::: warning
+
+The dependency range will only be updated if the package (that contains the dependency) is being released. For example, if `pkg-b` depends on `pkg-a`, and only `pkg-a` is released, the dependency range in `pkg-b` will not be updated.
+
+:::
+
+## ignore
+
+- **Type:** `string[]`
+- **Default:** `[]`
+- **Note:** Only applicable in monorepos.
+
+Specify the packages that will not be published, even if they are referenced in changesets. Instead, those changesets will be skipped until they are removed from this array. Supports [picomatch patterns](https://github.com/micromatch/picomatch) to match packages.
+
+::: warning For temporary use only
+
+This feature is designed for temporary use to allow changes to be merged without publishing them. If you want to stop a package from being published at all, set `"private": true` in its `package.json`.
+
+:::
+
+There are two caveats to this:
+
+1. If the package is mentioned in a changeset that also includes a package that is not ignored, publishing will fail.
+2. If the package requires one of its dependencies to be updated as part of a publish, publishing will also fail.
+
+These restrictions exist to ensure your repository or published code do not end up in a broken state.
+
+## bumpVersionsWithWorkspaceProtocolOnly
+
+- **Type:** `boolean`
+- **Default:** `false`
+- **Note:** Only applicable in monorepos.
+
+Whether to only bump dependency ranges that use the `workspace:` protocol of packages that are part of the workspace.
+
+## snapshot
+
+- **Type:** `{ useCalculatedVersion?: boolean; prereleaseTemplate?: string }`
+
+Configure snapshot releases when using `changesets version --snapshot`.
+
+### snapshot.useCalculatedVersion
+
+- **Type:** `boolean`
+- **Default:** `false`
+
+Snapshot version uses `0.0.0` as the base version, e.g. `0.0.0-tag-20211213000730`, so it does not hinder with other version releases. For example, if you have a prerelease at `1.0.0-beta.0`, and then you had a snapshot prerelease at `1.0.0-tag-20211213000730`, and a consumer is using the range `^1.0.0-beta.0` would resolve to the snapshot version which is likely not expected. Using `0.0.0` solves this problem.
+
+If this problem doesn't affect you, set this to `true` to use the calculated version based on the changeset files.
+
+### snapshot.prereleaseTemplate
+
+- **Type:** `string`
+- **Default:** `"{tag}-{datetime}"` (or `"{datetime}"` if the tag is empty)
+
+Configures the suffix for the snapshot release using a template with placeholders:
+
+- `{tag}` - the name of the snapshot tag, as specified in `--snapshot something`
+- `{commit}` - the git commit SHA (40 characters)
+- `{commit-short}` - like `{commit}` but only the first 7 characters
+- `{timestamp}` - the Unix timestamp of the time of the release, i.e. the value of `Date.now()`
+- `{datetime}` - the date and time of the release, e.g. `20211213000730` (YYYYMMDDHHMMSS, 14 characters)
+
+::: warning
+If you are using `--snapshot` with empty tag name, you cannot use `{tag}` as a placeholder. This will result in an error.
+:::
+
+## \_\_\_experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH
+
+Experimental options that may change in patch versions. Use these with caution and pay attention to the release notes for any changes.
+
+### \_\_\_experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH.updateInternalDependents
+
+- **Type:** `"out-of-range" | "always"`
+- **Default:** `"out-of-range"`
+
+Add dependent packages to the release (if they are not already a part of it) with patch bumps.
+
+### \_\_\_experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH.onlyUpdatePeerDependentsWhenOutOfRange
+
+- **Type:** `boolean`
+- **Default:** `false`
+
+When set to `true`, Changesets will only bump peer dependents when `peerDependencies` are leaving the range.
diff --git a/site/guide/customize-changelog-format.md b/site/guide/customize-changelog-format.md
new file mode 100644
index 000000000..ef9c38840
--- /dev/null
+++ b/site/guide/customize-changelog-format.md
@@ -0,0 +1,102 @@
+# Customize Changelog Format
+
+Changesets uses a default changelog generator (`@changesets/cli/changelog`) that displays relatively basic information, however, this can be customized with the [`changelog`](./config.md#changelog) option.
+
+::: info
+Many of the APIs below may look similar to a [custom commit generator](./customize-commit-format.md).
+:::
+
+## Writing a Custom Changelog Generator
+
+The changelog formatting can be customized with two functions: `getReleaseLine` and `getDependencyReleaseLine`. They must be default exported as an object containing the functions. For example:
+
+::: code-group
+
+```ts [TypeScript]
+// Install `@changesets/types` to get the `ChangelogFunctions` type
+import type { ChangelogFunctions } from "@changesets/types";
+
+const functions: ChangelogFunctions = {
+ getReleaseLine() {}
+ getDependencyReleaseLine(){}
+};
+
+export default functions;
+```
+
+```js [JavaScript]
+const functions = {
+ getReleaseLine() {},
+ getDependencyReleaseLine() {},
+};
+
+export default functions;
+```
+
+:::
+
+These functions are run during the [`version`](./cli.md#version) command and are expected to return a string (or a promise with a string).
+
+```ts
+type VersionType = "major" | "minor" | "patch";
+
+type NewChangesetWithCommit = {
+ // The file name of the changeset, e.g. "cool-places-hug"
+ id: string;
+ // The Markdown summary of the changeset
+ summary: string;
+ // The package names to be released and their respective semver bump types
+ releases: Array<{ name: string; type: VersionType }>;
+ // The commit hash that introduced the changeset
+ commit?: string;
+};
+
+type GetReleaseLine = (
+ // The changeset for this release
+ changeset: NewChangesetWithCommit,
+ // The type of change for this release: "major", "minor", or "patch"
+ type: VersionType,
+ // Options passed to the second item of the tuple
+ changelogOpts?: Record,
+) => string | Promise;
+
+type GetDependencyReleaseLine = (
+ // The changesets that causes a dependency update
+ changesets: NewChangesetWithCommit[],
+ // The dependencies that are being updated
+ dependenciesUpdated: ModCompWithPackage[],
+ // Options passed to the second item of the tuple
+ changelogOpts?: Record,
+) => string | Promise;
+
+type ChangelogFunctions = {
+ getReleaseLine: GetReleaseLine;
+ getDependencyReleaseLine: GetDependencyReleaseLine;
+};
+```
+
+## Using a Custom Changelog Generator
+
+To use a custom changelog generator, you can specify the path to the file (relative to the config file) or the module if it's packaged as a dependency, using the [`changelog`](./config.md#changelog) option:
+
+```json [.changeset/config.json]
+{
+ "changelog": "./changelog-generator.ts"
+}
+```
+
+```json [.changeset/config.json]
+{
+ "changelog": "changelog-generator-pkg"
+}
+```
+
+You can also specify options to be passed to the changelog functions' `changelogOpts` parameter:
+
+```json [.changeset/config.json]
+{
+ "changelog": ["./changelog-generator.ts", { "showCommit": false }]
+}
+```
+
+You can also use our official [GitHub Changelog](/packages/changelog-github).
diff --git a/site/guide/customize-commit-format.md b/site/guide/customize-commit-format.md
new file mode 100644
index 000000000..16f1c41c5
--- /dev/null
+++ b/site/guide/customize-commit-format.md
@@ -0,0 +1,111 @@
+# Customize Commit Format
+
+If the [`commit`](./config.md#commit) option is enabled, Changesets will automatically commit changes made during the [`add`](./cli.md#add) and [`version`](./cli.md#version) commands.
+
+The default commit message generator (`@changesets/cli/commit`) uses the following format:
+
+- For `add` command:
+
+ ```
+ docs(changeset): {summary}
+ ```
+
+- For `version` command:
+
+ ```
+ RELEASING: Releasing {numPackagesReleased} package(s)
+
+ Releases:
+ {releasesLines}
+ ```
+
+These can be customized with a custom commit generator.
+
+::: info
+Many of the APIs below may look similar to a [custom changelog generator](./customize-changelog-format.md).
+:::
+
+## Writing a Custom Commit Generator
+
+The commit message formatting can be customized with two optional functions: `getAddMessage` and `getVersionMessage`. If one function is not provided, the default generator will be used for that command.
+
+The functions must be default exported as an object containing them. For example:
+
+::: code-group
+
+```ts [TypeScript]
+// Install `@changesets/types` to get the `CommitFunctions` type
+import type { CommitFunctions } from "@changesets/types";
+
+const functions: CommitFunctions = {
+ getAddMessage() {},
+ getVersionMessage() {},
+};
+
+export default functions;
+```
+
+```js [JavaScript]
+const functions = {
+ getAddMessage() {},
+ getVersionMessage() {},
+};
+
+export default functions;
+```
+
+:::
+
+These functions are run when committing changes during the `add` and `version` commands and are expected to return a string (or a promise with a string).
+
+```ts
+type Changeset = {
+ // The Markdown summary of the changeset
+ summary: string;
+ // The package names to be released and their respective semver bump types
+ releases: Array<{ name: string; type: VersionType }>;
+};
+
+type GetAddMessage = (
+ // The changeset for this release
+ changeset: Changeset,
+ // Options passed to the second item of the tuple
+ commitOpts?: Record,
+) => string | Promise;
+
+type GetVersionMessage = (
+ // The releases information for this version commit
+ releasePlan: ReleasePlan,
+ // Options passed to the second item of the tuple
+ commitOpts?: Record,
+) => string | Promise;
+
+type CommitFunctions = {
+ getAddMessage?: GetAddMessage;
+ getVersionMessage?: GetVersionMessage;
+};
+```
+
+## Using a Custom Commit Generator
+
+To use a custom commit generator, you can specify the path to the file (relative to the config file) or the module if it's packaged as a dependency, using the [`commit`](./config.md#commit) option:
+
+```json [.changeset/config.json]
+{
+ "commit": "./commit-generator.ts"
+}
+```
+
+```json [.changeset/config.json]
+{
+ "commit": "commit-generator-pkg"
+}
+```
+
+You can also specify options to be passed to the commit functions' `commitOpts` parameter:
+
+```json [.changeset/config.json]
+{
+ "commit": ["./commit-generator.ts", { "showCommit": false }]
+}
+```
diff --git a/site/guide/fixed-packages.md b/site/guide/fixed-packages.md
new file mode 100644
index 000000000..03952ad73
--- /dev/null
+++ b/site/guide/fixed-packages.md
@@ -0,0 +1,35 @@
+# Fixed Packages
+
+Fixed packages allow you to specify a group or groups of packages that should be versioned and published together. They can be configured with the [`fixed`](./config.md#fixed) option.
+
+::: info Compared to [linked packages](./linked-packages.md)
+With fixed packages, all packages in the group will be version-bumped and published together even when there are no changes done to some of the the member packages, which means all packages will always have the same version.
+:::
+
+## Examples
+
+### General Example
+
+Let's say we have three packages, `pkg-a`, `pkg-b`, and `pkg-c`. `pkg-a` and `pkg-b` are fixed but `pkg-c` is not so the config looks like this:
+
+```json [.changeset/config.json]
+{
+ "fixed": [["pkg-a", "pkg-b"]]
+}
+```
+
+- `pkg-a` is at `1.0.0`
+- `pkg-b` is at `1.0.0`
+- `pkg-c` is at `1.0.0`
+
+We have a changeset with a patch for `pkg-a`, minor for `pkg-b` and major for `pkg-c`, and we do a release, the resulting versions will be:
+
+- `pkg-a` is at `1.1.0`
+- `pkg-b` is at `1.1.0`
+- `pkg-c` is at `2.0.0`
+
+We now have another changeset with a minor for `pkg-a`, and we do a release, the resulting versions will be:
+
+- `pkg-a` is at `1.2.0`
+- `pkg-b` is at `1.2.0`
+- `pkg-c` is at `2.0.0`
diff --git a/site/guide/getting-started.md b/site/guide/getting-started.md
new file mode 100644
index 000000000..e02fa0675
--- /dev/null
+++ b/site/guide/getting-started.md
@@ -0,0 +1,122 @@
+# Getting Started
+
+## What is Changesets?
+
+Changesets has several meanings that are used interchangeably:
+
+1. It is a tool to manage package versions and changelog generation in a project, designed to work in [monorepos](https://monorepo.tools) as well as single package repos.
+
+2. It is [a workflow](#usage) that allows contributors to describe what their changes are and how they should be released.
+
+3. It also represents a group of [changeset files](#what-is-a-changeset), which are Markdown files that each describe a change.
+
+::: tip New to Changesets?
+If you are contributing to a project that uses Changesets, check out the [frequently asked questions](../faq.md) for a quick introduction to working with changesets.
+:::
+
+## Why Changesets?
+
+Changesets is designed to help manage and describe changes, all the way through to publishing. It lets contributors declare how their changes should be released, and it'll handle updating package versions, changelogs, and publishing based on the provided changesets.
+
+Changesets has a focus on solving these problems for monorepos, keeping packages that rely on each other up to date, as well as making it easy to make changes to groups of packages. Conceptually, the workflow is also beneficial for single package repos.
+
+Read more about the motivation in the [Why Changesets](./why.md) page.
+
+## What is a changeset?
+
+A changeset is a Markdown file with YAML frontmatter. The contents of the Markdown is the change summary which will be written to the changelog and the YAML frontmatter describes the packages that have changed and their respective [semver](https://semver.org) bump types.
+
+They typically look like this:
+
+```md
+---
+"pkg-a": minor
+"pkg-b": patch
+---
+
+Summary of the change
+```
+
+These files are the foundation of the Changesets workflow.
+
+## Install Requirements
+
+Changesets requires [Node.js](https://nodejs.org) `^22.11 || ^24 || >=26` and supports these package managers:
+
+- [pnpm](https://pnpm.io) `>=10.0.0`
+- [npm](https://www.npmjs.com) `>=10.9.0`
+- [yarn](https://yarnpkg.com) `>=4.5.2`
+
+Lower versions may still work but are not guaranteed nor tested.
+
+::: tip Selecting a package manager
+We recommend using pnpm as it has safer security defaults and better monorepo support. However, we also support other package managers if you prefer them.
+:::
+
+## Setting Up
+
+Install the Changesets CLI:
+
+::: code-group
+
+```bash [pnpm]
+$ pnpm add -D @changesets/cli
+```
+
+```bash [npm]
+$ npm install -D @changesets/cli
+```
+
+```bash [yarn]
+$ yarn add -D @changesets/cli
+```
+
+:::
+
+And run `init` to set up the `.changeset` folder in your project:
+
+::: code-group
+
+```bash [pnpm]
+$ pnpm changeset init
+```
+
+```bash [npm]
+$ npx @changesets/cli init
+```
+
+```bash [yarn]
+$ yarn changeset init
+```
+
+:::
+
+Your project is now using Changesets!
+
+## Usage
+
+Whenever you make a change, e.g. via a git commit or a PR, create a changeset alongside with the CLI:
+
+::: code-group
+
+```bash [pnpm]
+$ pnpm changeset
+```
+
+```bash [npm]
+$ npx @changesets/cli
+```
+
+```bash [yarn]
+$ yarn changeset
+```
+
+:::
+
+::: tip Not every change requires a changeset
+Since a changeset describes how a change should be released, changes that don't require a release do not need a changeset. As such, we **do not recommend** blocking contributions in the absence of a changeset.
+:::
+
+Once you have accumulated some changesets, check out the [Versioning and Publishing](./versioning-and-publishing.md) guide to learn how to release your changes.
+
+See also the [CLI reference](./cli.md) to learn more about the available CLI commands.
diff --git a/site/guide/linked-packages.md b/site/guide/linked-packages.md
new file mode 100644
index 000000000..a4d91c7ff
--- /dev/null
+++ b/site/guide/linked-packages.md
@@ -0,0 +1,73 @@
+# Linked Packages
+
+Linked packages allow you to specify a group or groups of packages that should be versioned together. They can be configured with the [`linked`](./config.md#linked) option. There are some complex cases, so some examples are shown below to demonstrate various cases.
+
+- Linked packages will only be bumped when there is a changeset for them. This can mean because you explicitly choose to add a changeset for it or because it's a dependent of something being released.
+- Packages that have changesets and are in a set of linked packages will **always** be versioned based on the highest current version in the set of linked packages and the highest bump type from changesets in the set of linked packages.
+
+::: info Compared to [fixed packages](./fixed-packages.md)
+With linked packages, there is no guarantee that all packages in the group will be version-bumped and published, only those with changesets will be.
+:::
+
+## Examples
+
+### General Example
+
+We have three packages, `pkg-a`, `pkg-b`, and `pkg-c`. `pkg-a` and `pkg-b` are linked, but `pkg-c` is not so the config looks like this:
+
+```json [.changeset/config.json]
+{
+ "linked": [["pkg-a", "pkg-b"]]
+}
+```
+
+- `pkg-a` is at `1.0.0`
+- `pkg-b` is at `1.0.0`
+- `pkg-c` is at `1.0.0`
+
+We have a changeset with a patch for `pkg-a`, minor for `pkg-b` and major for `pkg-c`, and we do a release, the resulting versions will be:
+
+- `pkg-a` is at `1.1.0`
+- `pkg-b` is at `1.1.0`
+- `pkg-c` is at `2.0.0`
+
+We now have another changeset with a minor for `pkg-a`, and we do a release, the resulting versions will be:
+
+- `pkg-a` is at `1.2.0`
+- `pkg-b` is at `1.1.0`
+- `pkg-c` is at `2.0.0`
+
+We now have another changeset with a minor for `pkg-b`, and we do a release, the resulting versions will be:
+
+- `pkg-a` is at `1.2.0`
+- `pkg-b` is at `1.3.0`
+- `pkg-c` is at `2.0.0`
+
+We now have another changeset with patches for all three packages, and we do a release, the resulting versions will be:
+
+- `pkg-a` is at `1.3.1`
+- `pkg-b` is at `1.3.1`
+- `pkg-c` is at `2.0.1`
+
+### With dependencies
+
+We have two packages, `pkg-a` and `pkg-b` which are linked. `pkg-a` has a dependency on `pkg-b`.
+
+```json [.changeset/config.json]
+{
+ "linked": [["pkg-a", "pkg-b"]]
+}
+```
+
+- `pkg-a` is at `1.0.0`
+- `pkg-b` is at `1.0.0`
+
+We have a changeset with a major for `pkg-b`, and we do a release, the resulting versions will be:
+
+- `pkg-a` is at `2.0.0`
+- `pkg-b` is at `2.0.0`
+
+We now have another changeset with a major for `pkg-a`, and we do a release, the resulting versions will be:
+
+- `pkg-a` is at `3.0.0`
+- `pkg-b` is at `2.0.0`
diff --git a/site/guide/migration.md b/site/guide/migration.md
new file mode 100644
index 000000000..d811abb49
--- /dev/null
+++ b/site/guide/migration.md
@@ -0,0 +1,11 @@
+# Migration from v2
+
+## New required Node.js and package manager versions
+
+Changesets v3 requires [Node.js](https://nodejs.org) `^22.11 || ^24 || >=26` and supports these package managers:
+
+- [pnpm](https://pnpm.io) `>=10.0.0`
+- [npm](https://www.npmjs.com) `>=10.9.0`
+- [yarn](https://yarnpkg.com) `>=4.5.2`
+
+Lower versions may still work but are not guaranteed nor tested.
diff --git a/site/guide/prereleases.md b/site/guide/prereleases.md
new file mode 100644
index 000000000..1a19b7603
--- /dev/null
+++ b/site/guide/prereleases.md
@@ -0,0 +1,151 @@
+# Prereleases
+
+::: warning Please read through the guide before using prereleases
+Prereleases are very complicated! Using them requires a thorough understanding of all parts of npm publishes. Mistakes can lead to repository and publish states that are very hard to fix.
+:::
+
+Prereleases allow you to release alpha/beta versions of your packages before you do a stable release, e.g. publishing versions like `1.0.0-beta.0` before you publish `1.0.0`. This allows you to make frequent breaking changes and get feedback before you do a stable release.
+
+Changesets can be configured to enter prerelease mode which will publish all packages as prerelease versions. When you're ready to do a stable release, you can exit prerelease mode and publish everything as stable versions. Note that you cannot enter prerelease mode for only a subset of packages.
+
+It is also recommended to **run prereleases on a different branch** than the default branch, so that you can continue making changes to your stable version for important bug and security fixes. Alternatively, make a copy of the default branch, e.g. `v1`, before entering prerelease for `v2`. See the [Backporting Changes](./backporting-changes.md) guide for more information for making changes to older versions.
+
+## Enter Prerelease Mode
+
+::: tip Make one last stable release
+Before entering prerelease mode, consider making another stable release to clear the existing changesets. Otherwise, they will be included in the first prerelease.
+:::
+
+Run [`pre enter `](./cli.md#pre) to enter prerelease mode with the given tag. The tag will be used in the versions, e.g. if the tag is `beta`, the versions will look like `1.0.0-beta.0`, and for the npm [dist-tag](https://docs.npmjs.com/adding-dist-tags-to-packages) when you publish.
+
+::: code-group
+
+```bash [pnpm]
+$ pnpm changeset pre enter beta
+```
+
+```bash [npm]
+$ npx @changesets/cli pre enter beta
+```
+
+```bash [yarn]
+$ yarn changeset pre enter beta
+```
+
+:::
+
+This will generate a `pre.json` file in the `.changeset` folder that stores the current prerelease state. See the type definition of `PreState` in [`@changesets/types`](https://github.com/changesets/changesets/tree/main/packages/types) for more information of the state.
+
+::: info Prerelease mode on a separate branch
+
+- Update the [`baseBranch`](./config.md#baseBranch) option with the branch name. This allows the [`add`](./cli.md#add) command to properly detect the changed packages.
+
+- If you have set up CI to [automatically run version and publish](./automating.md#how-do-i-run-the-version-and-publish-commands), make sure to allow running the workflow for this branch too.
+
+:::
+
+Commit the changes and Changesets will now be in prerelease mode.
+
+## Releasing Prerelease Versions
+
+When you want to release a prerelease version, you can run the [`version`](./cli.md#version) and [`publish`](./cli.md#publish) commands as usual. See the [Versioning and Publishing](./versioning-and-publishing.md) guide for the usual flow.
+
+The only difference is that the versions will have the prerelease tag postfixed and the dist-tag will be the tag you specified when you entered prerelease mode.
+
+If you have set up CI to [automatically run version and publish](./automating.md#how-do-i-run-the-version-and-publish-commands), you should see a `version` PR with the `()` postfixed in the title.
+
+### Example
+
+Say we have three packages, `pkg-a`, `pkg-b`, and `pkg-c`:
+
+```
+pkg-a @ version 1.0.0
+ depends on pkg-b at range ^2.0.0
+pkg-b @ version 2.0.0
+pkg-c @ version 3.0.0
+```
+
+```md [.changeset/i-love-changesets.md]
+---
+"pkg-b": minor
+---
+```
+
+When running the `version` command, `pkg-b` will be released as `2.1.0-beta.0`. An important note is that this will bump dependent packages that wouldn't be bumped in normal releases because prerelease versions are not satisfied by most semver ranges, e.g. `2.1.0-beta.0` does not satisfy `^2.0.0`.
+
+The packages should now look like this:
+
+```
+pkg-a @ version 1.0.1-beta.0
+ depends on pkg-b at range ^2.1.0-beta.0
+pkg-b @ version 2.1.0-beta.0
+pkg-c @ version 3.0.0
+```
+
+Then, run the `publish` command as usual and it will publish the prerelease versions to npm with the `beta` dist-tag.
+
+::: danger Publishing new packages while in prerelease mode
+If you publish a **new**, unpublished package for the first time in prerelease mode, it will **still** be published with the `latest` tag alongside the prerelease tag.
+
+This is because npm enforces that all packages have a `latest` tagged version.
+:::
+
+## Exit Prerelease Mode
+
+When you're ready to do a stable release, you can exit prerelease mode with the [`pre exit`](./cli.md#pre) command. This will set an intent to exit prerelease mode in the `pre.json` file but it won't do any actual versioning.
+
+::: info Prerelease mode on a separate branch
+
+Make sure to revert the changes you made before merging back into the default branch:
+
+- Update the [`baseBranch`](./config.md#baseBranch) option back to the default branch.
+
+- If you have set up CI to [automatically run version and publish](./automating.md#how-do-i-run-the-version-and-publish-commands), remove any configuration to run the workflow for the prerelease branch.
+
+- You can now run the `exit` command, commit, and merge the changes back into the default branch.
+
+:::
+
+::: code-group
+
+```bash [pnpm]
+$ pnpm changeset pre exit
+```
+
+```bash [npm]
+$ npx @changesets/cli pre exit
+```
+
+```bash [yarn]
+$ yarn changeset pre exit
+```
+
+:::
+
+Make sure to commit the changes.
+
+You can now run the [`version`](./cli.md#version) and [`publish`](./cli.md#publish) commands as usual. The versions will now be released as stable versions without the prerelease tag and published to the `latest` dist-tag.
+
+### Example
+
+Taking the example before, after releasing the stable versions, the packages should now look like this:
+
+```
+pkg-a @ version 1.0.1
+ depends on pkg-b at range ^2.1.0
+pkg-b @ version 2.1.0
+pkg-c @ version 3.0.0
+```
+
+## Changing the Prerelease Tag
+
+During prerelease mode, you may want to change the tag for different stages of the prerelease, e.g. `alpha` -> `beta` -> `rc`. You can do this by directly changing the `"tag"` value in `.changeset/pre.json`:
+
+```json [.changeset/pre.json]
+{
+ "tag": "alpha", // [!code --]
+ "tag": "beta" // [!code ++]
+}
+```
+
+If you're using a different branch for prereleases, you do not need to rename the branch for the new tag. Prereleases only uses the specified tag for versions and dist-tags.
diff --git a/site/guide/snapshot-releases.md b/site/guide/snapshot-releases.md
new file mode 100644
index 000000000..8a17061c4
--- /dev/null
+++ b/site/guide/snapshot-releases.md
@@ -0,0 +1,109 @@
+# Snapshot Releases
+
+Snapshot releases are a way to release your changes for testing without updating the versions. This can be useful for releasing preview versions from PRs, nightly releases from the `main` branch, etc. These steps can be run in CI to automate the process of snapshot releases.
+
+Both a modified [`version`](./cli.md#version) and [`publish`](./cli.md#publish) commands are used to do a snapshot release. After both commands run, you will have a published version of packages in changesets with a version like `0.0.0-{tag}-{datetime}`.
+
+::: info Alternatives
+You can also use services such as [pkg.pr.new](https://pkg.pr.new) to easily set up snapshot releases. They publish to their own registry as ephemeral releases to prevent polluting versions and tags on npm.
+:::
+
+## Starting Off
+
+Create changesets as normal. When you are ready to release a snapshot, create a dedicated branch for doing so.
+
+## Versioning
+
+::: code-group
+
+```bash [pnpm]
+$ pnpm changeset version --snapshot
+```
+
+```bash [npm]
+$ npx @changesets/cli version --snapshot
+```
+
+```bash [yarn]
+$ yarn changeset version --snapshot
+```
+
+:::
+
+This will apply the changesets, but instead of using the next version, all versions will be set to `0.0.0-{datetime}`.
+
+If you want to add a personalized part to this version number, such as `bulbasaur`, you can run:
+
+::: code-group
+
+```bash [pnpm]
+$ pnpm changeset version --snapshot bulbasaur
+```
+
+```bash [npm]
+$ npx @changesets/cli version --snapshot bulbasaur
+```
+
+```bash [yarn]
+$ yarn changeset version --snapshot bulbasaur
+```
+
+:::
+
+This will instead update versions to `0.0.0-bulbasaur-{datetime}`.
+
+## Publishing
+
+Run `publish --tag bulbasaur` to publish the packages. By using the `--tag` flag, you will not add it to the `latest` [dist-tag](https://docs.npmjs.com/adding-dist-tags-to-packages) on npm.
+
+If you did not set a name when running `version --snapshot`, you should still use `--tag` to not publish it to the `latest` dist-tag. Use a random name like `publish --tag snapshot`.
+
+::: danger Always use a tag for snapshots
+This is **REALLY IMPORTANT** because if you do not include a tag, installing your package will default to the snapshot version, which is not what you want.
+:::
+
+## Disabling git tags
+
+When publishing snapshot releases, you may not want to create git tags as they may be temporary only. Use `publish --no-git-tag` to skip creating git tags for snapshot releases.
+
+## Using a snapshot version
+
+When you want to get people to test your snapshots, they can either update their package.json to your newly published version and run an install, or use the install command directly:
+
+::: code-group
+
+```bash [pnpm]
+$ pnpm add your-package-name@0.0.0-bulbasaur-{datetime}
+```
+
+```bash [npm]
+$ npm install your-package-name@0.0.0-bulbasaur-{datetime}
+```
+
+```bash [yarn]
+$ yarn add your-package-name@0.0.0-bulbasaur-{datetime}
+```
+
+:::
+
+Or you can install with the dist-tag:
+
+::: code-group
+
+```bash [pnpm]
+$ pnpm add your-package-name@bulbasaur
+```
+
+```bash [npm]
+$ npm install your-package-name@bulbasaur
+```
+
+```bash [yarn]
+$ yarn add your-package-name@bulbasaur
+```
+
+:::
+
+## What to do with the snapshot branch
+
+In almost all circumstances, we recommend that the changes after you have run `version` get merged back into your main branch. With snapshots, this is not the case. We recommend that you do not push the changes from this running of `version` to any branch. This is because the snapshot is intended for installation only, not to represent the correct published state of the repo. Save the generated version, and the tag you used, but do not push this to a branch you are planning to merge into the main branch, or merge it into the main branch.
diff --git a/site/guide/technical-decisions.md b/site/guide/technical-decisions.md
new file mode 100644
index 000000000..ec91f8b8d
--- /dev/null
+++ b/site/guide/technical-decisions.md
@@ -0,0 +1,55 @@
+# Technical Decisions
+
+This file is a discussion of some of the rules and design decisions that have gone into making changesets. The goal of all of these has been to make the experience of using changesets easy, while still providing the maximum value possible.
+
+## How changesets are combined
+
+Changesets are designed to be as easy to accumulate as possible. As such, when changesets are consumed with `version`, we flatten the version bumps into one single bump at the highest semver range specified.
+
+For example: if you run `version`, and we have `packageA` at `1.1.1`, which has two `minor` changesets, and one `patch` changeset, we will bump `packageA` to `1.2.0`.
+
+This allows changesets to be added and accumulated safely, with the knowledge that packages will only be released once at an appropriate version for the combined set of changesets, while still ensuring each change is captured in the changelog, with an indication of what kind of change it is.
+
+## How dependencies are bumped
+
+> [!NOTE]
+> This refers specifically to a feature of changesets used in monorepos
+
+When changesets are generated, we check to see if the selected packages will leave semver for any other packages within the monorepo.
+
+For example, if I have two packages:
+
+`packageA` at `1.1.1`
+
+and `packageB` at `1.1.0` that depends on `packageA` at `^1.1.0`.
+
+If I add `packageA` to a changeset with a `major` change, the version of `packageB` within the monorepo should also be updated. If it is not, either `packageB` in the monorepo will not use `packageA` in development, or `packageB` in development will not match an installation of `packageB` in production.
+
+As such we end up with a changeset that includes `packageA` as `major` and `packageB` as `patch`.
+
+All updating of dependencies is done as a patch bump. If you want to indicate a more significant change to `packageB` from consuming a new version of `packageA`, we recommend adding a second changeset specifically for `packageB`.
+
+## Why do we write files to disc
+
+There are two reasons we chose to do this. The first is so the changeset descriptions are editable after creation, and a user can go in and change this as they desire. The second is that it means we are unopinionated about your git workflows, with squashing and modifying commits being completely safe, without fear of breaking a release.
+
+## How Changesets differs from conventional commit-based tools
+
+While many versioning tools rely on conventional commits to determine releases, Changesets was built with a different philosophy, prioritizing monorepo management and flexible workflows over strict commit message parsing.
+
+1. Monorepo-first design: Changesets is built to manage complex workspace topologies. It allows you to group linked packages, define fixed packages, and explicitly declare how internal dependency bumps cascade through your repository.
+
+2. Intent-based files: Instead of parsing git commit messages, change intent is stored in dedicated Markdown files committed alongside your code. This ensures that release information is preserved regardless of how your git history is squashed or rewritten.
+
+3. Direct Semver selection: When creating a changeset, you directly specify a `major`, `minor`, or `patch` bump. Conventional commit-based tools, by comparison, rely on mapping specific commit types (e.g., `feat`, `fix`) to semver increments. We believe this design choice provides more clarity by keeping the documentation and the versioning intent together.
+
+## The versioning of peer dependencies
+
+Currently, if you list a package as a `peerDependency` of another package, this causes the package with the `peerDependency` to
+be released as a `major` change. This is because `peerDependency` changes will not be caught by a package installation.
+
+This decision is open for discussion.
+
+## How Changesets interacts with Git
+
+Changesets core flow of adding changesets, versioning packages/writing changelogs, and publishing packages should work without Git. Using Git in a way where the user doesn't explicitly ask to do something that involves Git such as showing changed packages in the add command shouldn't show an error if Git fails for any reason. Using Git in a way where the user explicitly chooses to use Git such as using the commit option or `status --since main`, Changesets should log an error and fail with a non-zero exit code.
diff --git a/site/guide/versioning-and-publishing.md b/site/guide/versioning-and-publishing.md
new file mode 100644
index 000000000..0f818bf93
--- /dev/null
+++ b/site/guide/versioning-and-publishing.md
@@ -0,0 +1,123 @@
+# Versioning and Publishing
+
+Once you have accumulated some changesets, you can use the CLI to update the versions and changelogs of your packages, and publish them to npm.
+
+This process is split into two steps: versioning and publishing.
+
+## Versioning
+
+Run the [`version`](./cli.md#version) command to update the package versions and changelogs:
+
+::: code-group
+
+```bash [pnpm]
+$ pnpm changeset version
+```
+
+```bash [npm]
+$ npx @changesets/cli version
+```
+
+```bash [yarn]
+$ yarn changeset version
+```
+
+:::
+
+Review the changes, ensure the versions and changelogs are updated as expected, and commit them to your repository:
+
+```bash
+$ git add .
+$ git commit -m "Version packages"
+```
+
+## Publishing
+
+Run the [`publish`](./cli.md#publish) command to publish the new versions of the packages:
+
+::: code-group
+
+```bash [pnpm]
+$ pnpm changeset publish
+```
+
+```bash [npm]
+$ npx @changesets/cli publish
+```
+
+```bash [yarn]
+$ yarn changeset publish
+```
+
+:::
+
+The `publish` command creates git tags for each package by default. This allows users to easily find the code for a specific release. The tags created are in the format of `pkg-name@X.X.X`, or in single-package repos, it is `vX.X.X`.
+
+Make sure to push the tags to your git remote after creating them:
+
+```bash
+$ git push --follow-tags
+```
+
+And you have released your changes! When you add more changesets again, repeat the process to continue releasing new versions of your packages.
+
+Check out the [CI automation](./automating.md) guide to simplify versioning and publishing so that releasing is as simple as merging a PR. And the [Backporting Changes](./backporting-changes.md) guide if you need to release changes in previous versions.
+
+::: tip Publish a different directory
+Changesets supports the `publishConfig.directory` option in the `package.json` to publish a different directory than the package root. This works the same way as [pnpm's support](https://pnpm.io/package_json#publishconfigdirectory), however, Changesets normalizes this to work in all package managers.
+:::
+
+## Publishing for the First Time
+
+For packages that are being published for the first time, make sure that the [`access`](./config.md#access) option is properly set. If all your packages are public, set it to `public`:
+
+```json [.changeset/config.json]
+{
+ "access": "public"
+}
+```
+
+If only some are public, use the `publishConfig.access` field in the `package.json` for those packages:
+
+```json [package.json]
+{
+ "name": "@scope/pkg-a",
+ "version": "1.0.0",
+ "publishConfig": {
+ "access": "public"
+ }
+}
+```
+
+If you have private packages, make sure you have [permissions](https://docs.npmjs.com/creating-and-publishing-private-packages#direct-publishing) to publish them. In CI, you will need to pass an [access token](https://docs.npmjs.com/about-access-tokens) to the workflow.
+
+::: warning Protect your access tokens
+Always take special care of access tokens and do not leak them in your CI workflow. Only pass them to the steps that need them. It is otherwise recommended to set up trusted publishing instead.
+:::
+
+### Trusted Publishing
+
+If you want to set up [trusted publishing](https://docs.npmjs.com/trusted-publishers) for a new package, you need to first manually publish the package locally, and then update its settings for trusted publishing.
+
+Usually, you can first create a stub package with a `package.json` that looks like this:
+
+```json [package.json]
+{
+ "name": "pkg-a",
+ "version": "0.0.0"
+}
+```
+
+Then, run `npm publish` and set up trusted publishing in the package settings. Then, create a changeset that bumps to the proper initial version. For example, to start with `0.1.0`:
+
+```md [.changeset/i-love-changesets.md]
+---
+"pkg-a": minor
+---
+
+Initial release
+```
+
+## Removing a Package
+
+If a package is no longer needed, you can delete the package directory from your repository as usual, and make sure all references to the package name is removed from the existing changesets. Search for lines such as `"my-deleted-package": patch` in the changesets frontmatter and remove them, and Changesets will skip the package for the next version and publish.
diff --git a/site/guide/why.md b/site/guide/why.md
new file mode 100644
index 000000000..855a1890a
--- /dev/null
+++ b/site/guide/why.md
@@ -0,0 +1,58 @@
+# Why Changesets
+
+## The Problem
+
+When organizing the release of packages, you may end up wanting to group several changes together written by different people and/or over a relatively large period of time. The best time to capture this information is when submitting a PR (when it is fresh in your mind), not when you eventually go to batch and release these changes.
+
+Git is a bad place to store this information, as it discourages writing detailed change descriptions. You want to allow people to provide as much documentation for the change as they want.
+
+## The Solution, Changesets
+
+The best way to think about a changeset as separate to either a changelog or a version bump is that a changeset is an "intent to change", carrying two key bits of information: **versioning** and **changelogs**.
+
+### Versioning
+
+The versioning information can be represented with [semver](https://semver.org) as major, minor, or patch.
+
+In a monorepo, we can also encode information about any other packages that should be re-released as part of this change. This ensures that if you upgrade to the latest of all the packages, they are all compatible. The current implementation is heavily informed by [bolt](https://github.com/boltpkg/bolt)'s opinion on version compatibility.
+
+### Changelogs
+
+The changelog information can be stored as a Markdown snippet.
+
+As storing this information directly in git is problematic, we store it in the filesystem using the following structure:
+
+```
+ | .changeset/
+ | |- UNIQUE_ID.md
+```
+
+## The Result
+
+A changeset is a Markdown file with YAML frontmatter. The contents of the Markdown is the change summary which will be written to the changelog and the YAML frontmatter describes the packages that have changed and their respective semver bump types:
+
+```md
+---
+"pkg-a": minor
+"pkg-b": patch
+---
+
+Summary of the change
+```
+
+This is useful because it breaks versioning into two steps:
+
+1. Adding a changeset - can be done in a PR, by a contributor, while the change is fresh in their mind.
+2. Versioning - combines all changesets, creates one version bump for each package based on the maximum version bump of each package, updates dependencies where needed, and writes changelogs. Can then be reviewed as an aggregate.
+
+## The Tooling that Makes this Worthwhile
+
+1. The [Changesets CLI](./cli.md) helps with generating new changesets, versioning, and publishing packages.
+2. The [Changesets GitHub Bot](./automating.md#how-do-i-ensure-pull-requests-have-changesets) ensure PRs have changesets and prompts for creating them.
+3. The [Changesets GitHub Action](./automating.md#how-do-i-run-the-version-and-publish-commands) automates versioning and publishing in CI so releasing is as simple as merging a PR.
+
+## Benefits for Single Package Repos
+
+Changesets are designed first and foremost to handle versioning in monorepos, where interdependencies flowing through the system are important to understand and capture.
+
+Conceptually though, the benefits of changesets are detachable from this. The workflow overall leads to an improvement in pull requests that helps increase confidence in versioning decisions and changelog entries.
diff --git a/site/index.md b/site/index.md
new file mode 100644
index 000000000..72eafe5dd
--- /dev/null
+++ b/site/index.md
@@ -0,0 +1,43 @@
+---
+layout: home
+
+hero:
+ name: Changesets
+ text: Version and Changelogs
+ tagline: A tool to manage versioning and changelogs
+ image:
+ light: /logo-light.svg
+ dark: /logo-dark.svg
+ alt: Changesets logo
+ actions:
+ - theme: brand
+ text: Get Started
+ link: ./guide/getting-started.md
+ - theme: alt
+ text: View on GitHub
+ link: https://github.com/changesets/changesets
+
+features:
+ - icon: ⚡️
+ title: Automated Versioning
+ details: Automatically updates versions based on change types.
+ - icon: 📦
+ title: Monorepo Support
+ details: Supports pnpm, yarn, and npm workspaces.
+ - icon: 📖
+ title: Changelog Generation
+ details: Automatically creates package changelogs.
+ - icon: 🔄
+ title: CI/CD Integration
+ details: Release through automated pull requests and release triggers.
+---
+
+
+
+
diff --git a/site/package.json b/site/package.json
new file mode 100644
index 000000000..f13670dff
--- /dev/null
+++ b/site/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "@changesets/docs",
+ "version": "0.0.1",
+ "private": true,
+ "description": "The official documentation for Changesets",
+ "type": "module",
+ "scripts": {
+ "dev": "vitepress dev",
+ "build": "vitepress build",
+ "preview": "vitepress preview",
+ "generate-og": "node scripts/generate-og.ts"
+ },
+ "devDependencies": {
+ "takumi-js": "^2.0.2",
+ "vitepress": "^2.0.0-alpha.18",
+ "vitepress-plugin-group-icons": "^1.7.5"
+ },
+ "engines": {
+ "node": "^22.11 || ^24 || >=26"
+ }
+}
diff --git a/site/packages/[pkg].md b/site/packages/[pkg].md
new file mode 100644
index 000000000..87e77682c
--- /dev/null
+++ b/site/packages/[pkg].md
@@ -0,0 +1 @@
+
diff --git a/site/packages/[pkg].paths.ts b/site/packages/[pkg].paths.ts
new file mode 100644
index 000000000..51a6c3cfb
--- /dev/null
+++ b/site/packages/[pkg].paths.ts
@@ -0,0 +1,117 @@
+import fs from "node:fs/promises";
+import path from "node:path";
+import { defineRoutes, type SiteConfig } from "vitepress";
+
+const config: SiteConfig = (globalThis as any).VITEPRESS_CONFIG;
+
+export default defineRoutes({
+ watch: ["../../packages/*/README.md", "../../packages/*/package.json"],
+
+ async paths() {
+ // Get packages to generate based on configured sidebar packages items
+ const sidebarItems = config.site.themeConfig.sidebar["/packages/"].items;
+ const packages: string[] = sidebarItems
+ .find((item: any) => item.base === "/packages/")!
+ .items.map((item: any) => item.link);
+
+ return await Promise.all(
+ packages.map(async (pkg) => {
+ const pkgDir = path.join(import.meta.dirname, `../../packages/${pkg}`);
+ const readmePath = path.join(pkgDir, "README.md");
+ const pkgJsonPath = path.join(pkgDir, "package.json");
+
+ const readmeContent = await fs.readFile(readmePath, "utf-8");
+ const pkgJson = JSON.parse(await fs.readFile(pkgJsonPath, "utf-8"));
+
+ const content = updateMarkdown(readmeContent, pkgJson, readmePath);
+
+ return { params: { pkg }, content };
+ }),
+ );
+ },
+});
+
+function updateMarkdown(
+ content: string,
+ pkgJson: Record,
+ contentPath: string,
+): string {
+ // Remove badges
+ const badgeRegex = /\[!\[.*?\]\(.*?\)\]\(.*?\)/g;
+ content = content.replace(badgeRegex, "");
+
+ // Relative links to our docs
+ const docsRegex = /https:\/\/changesets\.dev\//g;
+ content = content.replace(docsRegex, "/");
+
+ // Add our own badges
+ const h1Regex = /^# (.+)$/m;
+ if (!h1Regex.test(content)) {
+ throw new Error(
+ `The h1 title is missing in ${contentPath} which is required for docs`,
+ );
+ }
+ content = content.replace(
+ h1Regex,
+ `\
+# $1
+
+
+
+
+
+
+
+
+
+
+
+`,
+ );
+
+ // Add "Installation" section before "Usage" section
+ const usageRegex = /^## Usage$/m;
+ if (!usageRegex.test(content)) {
+ throw new Error(
+ `The "Usage" section is missing in ${contentPath} which is required for docs`,
+ );
+ }
+ content = content.replace(
+ usageRegex,
+ `\
+## Installation
+
+::: code-group
+
+\`\`\`bash [pnpm]
+$ pnpm add -D ${pkgJson.name}
+\`\`\`
+
+\`\`\`bash [npm]
+$ npm install -D ${pkgJson.name}
+\`\`\`
+
+\`\`\`bash [yarn]
+$ yarn add -D ${pkgJson.name}
+\`\`\`
+
+:::
+
+## Usage`,
+ );
+
+ return content;
+}
+
+function getRepoLink(pkgJson: Record): string {
+ const repoUrl = pkgJson.repository?.url ?? "";
+ const repoBase = repoUrl.replace(/^git\+/, "").replace(/\.git$/, "");
+ const repoPath = pkgJson.repository?.directory ?? "";
+ return `${repoBase}/tree/main/${repoPath}`;
+}
diff --git a/site/public/blog/announcing-changesets-v3.png b/site/public/blog/announcing-changesets-v3.png
new file mode 100644
index 000000000..0f9ea3cc8
Binary files /dev/null and b/site/public/blog/announcing-changesets-v3.png differ
diff --git a/site/public/logo-dark.svg b/site/public/logo-dark.svg
new file mode 100644
index 000000000..d1cfee859
--- /dev/null
+++ b/site/public/logo-dark.svg
@@ -0,0 +1,25 @@
+
diff --git a/site/public/logo-light.svg b/site/public/logo-light.svg
new file mode 100644
index 000000000..243072997
--- /dev/null
+++ b/site/public/logo-light.svg
@@ -0,0 +1,30 @@
+
diff --git a/site/public/og-image.png b/site/public/og-image.png
new file mode 100644
index 000000000..5e1a15bbb
Binary files /dev/null and b/site/public/og-image.png differ
diff --git a/site/scripts/generate-og.ts b/site/scripts/generate-og.ts
new file mode 100644
index 000000000..69473a72d
--- /dev/null
+++ b/site/scripts/generate-og.ts
@@ -0,0 +1,71 @@
+import fss from "node:fs";
+import fs from "node:fs/promises";
+import path from "node:path";
+import { render } from "takumi-js";
+import { googleFonts } from "takumi-js/helpers";
+import { extractBlogData } from "../.vitepress/theme/utils.ts";
+
+const blogDir = path.resolve(import.meta.dirname, "../blog");
+const blogOgOutDir = path.resolve(import.meta.dirname, "../public/blog");
+
+for (const blogFileName of await fs.readdir(blogDir)) {
+ if (!blogFileName.endsWith(".md") || blogFileName === "index.md") continue;
+
+ const blogOgOutFile = path.join(
+ blogOgOutDir,
+ `${blogFileName.replace(/\.md$/, ".png")}`,
+ );
+ if (fss.existsSync(blogOgOutFile)) {
+ console.log(`Skipping existing: ${blogOgOutFile}`);
+ continue;
+ }
+
+ const blogFilePath = path.join(blogDir, blogFileName);
+ const blogContent = await fs.readFile(blogFilePath, "utf8");
+ const blogData = extractBlogData(blogContent, `/blog/${blogFileName}`);
+
+ console.log("Generating OG image for", blogFileName);
+
+ const ogImageBuffer = await generateOgImage(blogData);
+
+ await fs.mkdir(blogOgOutDir, { recursive: true });
+ await fs.writeFile(blogOgOutFile, ogImageBuffer);
+}
+
+async function generateOgImage(data: ReturnType) {
+ // NOTE: For the most part, you can copy and paste this template to https://takumi.kane.tw/playground
+ // to easily adjust the styling, but update the `style` prop as React-style object so that it works.
+ const template = `\
+