Configuration
Project configuration for Craft is stored in .craft.yml in the project root.
GitHub Project
Section titled “GitHub Project”Craft tries to determine GitHub repo information from the local git repo. You can also hard-code it:
github: owner: getsentry repo: sentry-javascriptPre-release Command
Section titled “Pre-release Command”This command runs on your release branch as part of craft prepare. Default: bash scripts/bump-version.sh.
preReleaseCommand: bash scripts/bump-version.shThe command is executed with the following environment variables:
CRAFT_OLD_VERSION: The previous version (or0.0.0if no previous version exists)CRAFT_NEW_VERSION: The new version being released
The script should:
- Use these environment variables to perform version replacement
- Replace version occurrences
- Not commit changes
- Not change git state
Note: For backward compatibility, the old and new versions are also passed as the last two command-line arguments to the script, but using environment variables is safer and recommended.
Example script:
#!/bin/bashset -eux
# Use CRAFT_NEW_VERSION provided by craftexport npm_config_git_tag_version=falsenpm version "${CRAFT_NEW_VERSION}"Automatic Version Bumping
Section titled “Automatic Version Bumping”When minVersion: "2.21.0" or higher is set and no custom preReleaseCommand is defined, Craft automatically bumps version numbers based on your configured publish targets. This eliminates the need for a scripts/bump-version.sh script in most cases.
How It Works
Section titled “How It Works”- Craft examines your configured
targetsin.craft.yml - For each target that supports version bumping, Craft updates the appropriate project files
- Targets are processed in the order they appear in your configuration
- Each target type is only processed once (e.g., multiple npm targets won’t bump
package.jsontwice)
Supported Targets
Section titled “Supported Targets”| Target | Detection | Version Bump Method |
|---|---|---|
npm |
package.json exists |
npm version --no-git-tag-version (with workspace support) |
pypi |
pyproject.toml exists |
hatch, poetry, setuptools-scm, or direct edit |
crates |
Cargo.toml exists |
cargo set-version (requires cargo-edit) |
gem |
*.gemspec exists |
Direct edit of gemspec and lib/**/version.rb |
pub-dev |
pubspec.yaml exists |
Direct edit of pubspec.yaml |
hex |
mix.exs exists |
Direct edit of mix.exs |
nuget |
*.csproj exists |
dotnet-setversion or direct XML edit |
npm Workspace Support
Section titled “npm Workspace Support”For npm/yarn/pnpm monorepos, Craft automatically detects and bumps versions in all workspace packages:
- npm 7+: Uses
npm version --workspacesto bump all packages at once - yarn/pnpm or npm < 7: Falls back to bumping each non-private package individually
Workspace detection checks for:
workspacesfield in rootpackage.json(npm/yarn)pnpm-workspace.yaml(pnpm)
Private packages ("private": true) are skipped during workspace version bumping.
Python (pypi) Detection Priority
Section titled “Python (pypi) Detection Priority”For Python projects, Craft detects the build tool and uses the appropriate method:
- Hatch - If
[tool.hatch]section exists →hatch version <version> - Poetry - If
[tool.poetry]section exists →poetry version <version> - setuptools-scm - If
[tool.setuptools_scm]section exists → No-op (version derived from git tags) - Direct edit - If
[project]section withversionfield exists → Editpyproject.tomldirectly
Enabling Automatic Version Bumping
Section titled “Enabling Automatic Version Bumping”To enable automatic version bumping, ensure your .craft.yml has:
minVersion: '2.21.0'targets: - name: npm # or pypi, crates, etc. # ... other targetsAnd either:
- Remove any custom
preReleaseCommand, or - Don’t define
preReleaseCommandat all
Disabling Automatic Version Bumping
Section titled “Disabling Automatic Version Bumping”To disable automatic version bumping while still using minVersion 2.21.0+:
minVersion: '2.21.0'preReleaseCommand: '' # Explicitly set to empty stringOr define a custom script:
minVersion: '2.21.0'preReleaseCommand: bash scripts/my-custom-bump.shError Handling
Section titled “Error Handling”If automatic version bumping fails:
- Missing tool: Craft reports which tool is missing (e.g., “Cannot find ‘npm’ for version bumping”)
- Command failure: Craft shows the error from the failed command
- No supported targets: Craft warns that no targets support automatic bumping
- No applicable files: If targets support bumping but none of them find a version to update (e.g. no
.csprojwith a<Version>),craft preparefails instead of releasing with a stale version. SetpreReleaseCommand: ''if your versions don’t live in project files.
In all error cases, Craft suggests defining a custom preReleaseCommand as a fallback.
Recovery from Failed Prepare
Section titled “Recovery from Failed Prepare”If version bumping succeeds but craft prepare fails mid-way (e.g., during changelog generation or git operations), you may need to clean up manually:
-
Check the release branch: If a release branch was created, you can delete it:
Terminal window git branch -D release/<version> -
Revert version changes: If files were modified but not committed, reset them:
Terminal window git checkout -- package.json pyproject.toml Cargo.toml # or whichever files were changed -
Re-run prepare: Once the issue is fixed, run
craft prepareagain. Version bumping is idempotent—running it multiple times with the same version is safe.
Post-release Command
Section titled “Post-release Command”This command runs after a successful craft publish. Default: bash scripts/post-release.sh.
postReleaseCommand: bash scripts/post-release.shRelease Branch Name
Section titled “Release Branch Name”Override the release branch prefix. Default: release.
releaseBranchPrefix: publishFull branch name: {releaseBranchPrefix}/{version}
The prefix may contain slashes, which is useful for monorepos that release
several independently-versioned products from one repository. Pairing a slashed
releaseBranchPrefix with a per-product github.tagPrefix keeps each product’s
release branches and tags separate:
releaseBranchPrefix: release/clitargets: - name: github tagPrefix: "cli@"This produces branches like release/cli/1.2.3 and tags like cli@1.2.3. See
the GitHub target docs
for the full monorepo pattern.
Changelog Policies
Section titled “Changelog Policies”Craft supports simple and auto changelog management modes.
Simple Mode
Section titled “Simple Mode”Reminds you to add a changelog entry:
changelog: CHANGESOr with options:
changelog: filePath: CHANGES.md policy: simpleAuto Mode
Section titled “Auto Mode”Automatically generates changelog from commits:
changelog: policy: autoAuto mode uses .github/release.yml to categorize PRs. This file follows GitHub’s release.yml format with Craft-specific extensions.
AI summaries
Section titled “AI summaries”Add an aiSummary object to enable summaries for automatic changelogs. Omit it
or use aiSummary: false to disable generation.
changelog: policy: auto aiSummary: levels: [release] # default; choose any combination of release, category, scope minItems: 5 # summarize groups with more than 5 original entries style: Concise and friendly for developers. # optional tone guidance| Setting | Default | Behavior |
|---|---|---|
levels |
[release] |
Select visible summaries; omitted or empty arrays use [release]. |
minItems |
5 |
Strict entry-count threshold. 0 includes every nonempty selected group. Category counts include descendants; release counts include the whole changelog. |
style |
Neutral | Optional writing guidance (1–500 characters), applied at every level. Facts, coverage, length and plain-text safeguards still apply. |
llm.endpoint |
https://api.githubcopilot.com/responses |
Full POST URL; HTTPS required except loopback HTTP. |
llm.model |
gpt-5.4-nano |
Model ID supported by the endpoint and credential. |
llm.apiKeyEnv |
GITHUB_TOKEN |
Name of the environment variable containing the token. Never put the token in configuration or CLI arguments. |
For short changelogs, keep the default levels: [release] and minItems: 5
to add an overview while leaving the original entries expanded. Selecting all
levels with minItems: 0 explicitly summarizes even one-entry groups.
Lower-level digests are reused for parent summaries even when hidden. Each
parent makes an AI synthesis call over its child digests. The release overview
is one or two short sentences covering the themes across every category, rather
than joined category summaries. Scopes explain concrete changes and options;
categories synthesize their useful outcomes in a brief sentence, even when a
category has only one scope. Ordinary category prose is limited to 55% of its
children’s combined prose length, with an 80-character floor, subject to the
absolute limits below. Release overviews use their fixed word/character limits
so already brief categories do not force incomplete sentences. Copying eight
consecutive child words triggers a bounded repair.
Categories with explicit breaking/security source entries or migration settings
are generated in separate guidance batches. Model-inferred fact metadata alone
does not select this display role or disable compression. These guidance categories
are exempt from these compression and phrase-copy limits so migration actions,
risks and applicability conditions can stay precise. These category calls also
receive bounded original PR context for critical entries, since a child digest
can omit migration details. Context excerpts do not increase entry counts.
Recognized explicit migration settings (such as an empty-string opt-out) and
required CLI flags must survive in detailed guidance, including intermediate
reduction rounds; missing operational terms trigger the same bounded
repair/fallback. Ordinary test-setup instructions do not impose these constraints.
Release overviews still condense those categories; critical facts remain in the
internal ledger. Besides each changelog entry, the model receives the Markdown
text of its PR description (without code blocks, HTML, images or prose emoji,
capped at 1200 characters with breaking-change and migration paragraphs
prioritized) as context only; it is never rendered. Visible prose is capped at
400 characters and 35 words for the release, 600 characters and 22 words for ordinary
categories, 900 for breaking/security guidance and 1200 for each scope. Critical
guidance has extra room to preserve complete migration conditions.
The model also receives each node’s character budget as planning context.
Overviews with an incomplete ending or malformed control text are rejected.
Invalid structured model output gets one repair attempt within the same
64-request and 120-second budgets. Transport and authentication failures do not
trigger retries or provider switching. Source-linked critical facts are carried
and validated internally without appending their text to every displayed summary.
All original entries remain
intact. Category and scope summaries preserve originals in expandable blocks,
including links and nested content. Category prose and
scope headings stay expanded; each original entry is folded only once. Scope
summaries need an existing scope heading; scopeGrouping: false still allows
category/release summaries. Unscoped entries contribute to both parent levels.
Output examples
Section titled “Output examples”These examples use two original entries and minItems: 0.
levels: [release] adds an overview and leaves originals expanded:
CLI authentication now supports signing in and out.
### New Features#### CLI- Add login command- Add logout commandlevels: [category] keeps scope headings visible and folds original entries:
### New Features
Expanded CLI authentication workflows.
#### CLI
<details><summary>Show 2 items</summary>
- Add login command- Add logout command
</details>levels: [scope] summarizes each eligible scope:
### New Features#### CLIAdded login and logout commands.
<details><summary>Show 2 items</summary>
- Add login command- Add logout command
</details>levels: [release, scope] combines an overview with scope summaries:
CLI authentication now supports signing in and out.
### New Features#### CLIAdded login and logout commands.
<details><summary>Show 2 items</summary>
- Add login command- Add logout command
</details>levels: [category, scope] keeps both summaries visible:
### New Features
Expanded CLI authentication workflows.
#### CLI
Added login and logout commands.
<details><summary>Show 2 items</summary>
- Add login command- Add logout command
</details>Selecting all three levels also adds the release overview. Excluding release
omits it. Category/release summaries retain scope context; scope summaries can
omit the scope name because their heading supplies it.
Connection settings
Section titled “Connection settings”The CLI and Actions share the HTTP client. With an authorized Copilot token in
GITHUB_TOKEN, aiSummary: {} uses the default Luna Responses endpoint. For a
custom provider, specify its connection and token variable:
changelog: policy: auto aiSummary: llm: endpoint: https://gateway.example.com/v1/chat/completions model: your-model apiKeyEnv: TEAM_MODEL_TOKENPer-field precedence is CLI flags (--ai-endpoint, --ai-model,
--ai-api-key-env), CRAFT_AI_LLM JSON, scalar environment overrides
(CRAFT_AI_ENDPOINT, CRAFT_AI_MODEL, CRAFT_AI_API_KEY_ENV), then effective
project/workspace configuration. Workspace changelog objects replace the
inherited object. Endpoints ending in /responses use Responses; others use
Chat Completions. Both require structured JSON output. Invalid settings are
rejected; missing tokens and provider errors retain the original output. Failure
warnings identify the generation stage and a fixed reason code, plus HTTP status
for rejected requests. Credentials, source content and provider bodies are omitted.
Generation sends changelog content and critical PR titles to the chosen provider. Breaking/security facts retain source IDs. Generated prose is escaped; review it for accuracy. Requests are bounded to 64 calls, 3 concurrent calls, 30 seconds per request, 120 seconds total, 24,000 input bytes and 8,192 output tokens. Any failure preserves the entire original changelog without retries or provider switching. Existing leftover-entry limits still apply.
Dry runs, highlighted PR previews, prepare --no-changelog and version analysis
make zero model calls. See AI summary authentication
for Action inputs, secret mapping, Copilot permissions and billing.
Craft Extensions to release.yml
Section titled “Craft Extensions to release.yml”Craft extends GitHub’s format with two additional fields:
| Field | Description |
|---|---|
commit_patterns |
Array of regex patterns to match commit/PR titles (in addition to labels) |
semver |
Version bump type for auto-versioning: major, minor, or patch |
Default Configuration
Section titled “Default Configuration”If .github/release.yml doesn’t exist, Craft uses these defaults based on Conventional Commits:
changelog: exclude: labels: - skip-changelog categories: - title: Breaking Changes 🛠 commit_patterns: - "^(?<type>\\w+(?:\\((?<scope>[^)]+)\\))?!:\\s*)" semver: major - title: Security 🔒 commit_patterns: - "^(?<type>security(?:\\((?<scope>[^)]+)\\))?!?:\\s*)" semver: patch - title: New Features ✨ commit_patterns: - "^(?<type>feat(?:\\((?<scope>[^)]+)\\))?!?:\\s*)" semver: minor - title: Bug Fixes 🐛 commit_patterns: - "^(?<type>fix(?:\\((?<scope>[^)]+)\\))?!?:\\s*)" - '^Revert "' semver: patch - title: Documentation 📚 commit_patterns: - "^(?<type>docs?(?:\\((?<scope>[^)]+)\\))?!?:\\s*)" semver: patch - title: Internal Changes 🔧 commit_patterns: - "^(?<type>(?:build|refactor|meta|chore|ci|ref|perf|tests?|style)(?:\\((?<scope>[^)]+)\\))?!?:\\s*)" semver: patchExample Configuration
Section titled “Example Configuration”changelog: categories: - title: Features labels: - enhancement commit_patterns: - "^(?<type>feat(?:\\((?<scope>[^)]+)\\))?!?:\\s*)" semver: minor - title: Bug Fixes labels: - bug commit_patterns: - "^(?<type>fix(?:\\((?<scope>[^)]+)\\))?!?:\\s*)" semver: patchCustom Changelog Entries from PR Descriptions
Section titled “Custom Changelog Entries from PR Descriptions”The legacy #body-in-changelog opt-in must be a standalone, top-level line in
the PR or commit body. Surrounding blank lines are optional.
Mentions inside prose, inline or fenced code, blockquotes and HTML comments do
not opt in. Prefer a curated “Changelog Entry” section to including a full body.
By default, the changelog entry for a PR is generated from its title. However, PR authors can override this by adding a “Changelog Entry” section to the PR description. This allows for more detailed, user-facing changelog entries without cluttering the PR title.
To use this feature, add a markdown heading (level 2 or 3) titled “Changelog Entry” to your PR description, followed by the desired changelog text:
### Description
Add `foo` function, and add unit tests to thoroughly check all edge cases.
### Changelog Entry
Add a new function called `foo` which prints "Hello, world!"
### Issues
Closes #123The text under “Changelog Entry” will be used verbatim in the changelog instead of the PR title. If no such section is present, the PR title is used as usual.
Advanced Features
Section titled “Advanced Features”-
Multiple Entries: If you use multiple top-level bullet points in the “Changelog Entry” section, each bullet will become a separate changelog entry:
### Changelog Entry- Add OAuth2 authentication- Add two-factor authentication- Add session management -
Nested Content: Indented bullets (4+ spaces or tabs) are preserved as nested content under their parent entry:
### Changelog Entry- Add authentication system- OAuth2 support- Two-factor authentication- Session managementThis will generate:
- Add authentication system by @user in [#123](url)- OAuth2 support- Two-factor authentication- Session managementNote: Nested items do NOT get author/PR attribution - only the top-level entry does.
-
Plain Text: If no bullets are used, the entire content is treated as a single changelog entry. Multi-line text is automatically joined with spaces to ensure valid markdown output.
-
Content Isolation: Only content within the “Changelog Entry” section is included in the changelog. Other sections (Description, Issues, etc.) are ignored.
Scope Grouping
Section titled “Scope Grouping”Changes are automatically grouped by scope (e.g., feat(api): groups under “Api”):
changelog: policy: auto scopeGrouping: true # defaultScope headers are only shown for scopes with more than one entry. Entries without a scope are listed at the bottom of each category section without a sub-header.
Example output with scope grouping:
### New Features
#### Api
- Add user endpoint by @alice in [#1](https://github.com/...)- Add auth endpoint by @bob in [#2](https://github.com/...)
#### Ui
- Add dashboard by @charlie in [#3](https://github.com/...)
- General improvement by @dave in [#4](https://github.com/...)Workspace-aware changelogs
Section titled “Workspace-aware changelogs”When you select a Craft release workspace, automatic changelogs include commits
that change files in that workspace and commits that change shared files outside
all workspaces. Commits confined to another workspace are excluded. Craft detects
package ownership from pnpm, npm, or Yarn workspaces as well as the release
workspaces in .craft.yml. Commits spanning workspaces appear in each affected
workspace’s changelog. This also scopes automatic version detection; single-unit
repositories keep their existing behavior.
If a release includes files from another workspace, add its directory to
includePaths on that release unit. Paths are relative to the repository root,
match whole directory names, and cannot escape the repository:
workspaces: packages/cli: changelog: policy: auto includePaths: - apps/cli-docsMost workspaces need no includePaths setting. Craft rejects includePaths and
unownedPaths in configurations without workspaces, because there is no
workspace ownership to adjust.
Files outside every workspace, such as root build files or an application that
lives at the repository root, count as shared by default. Use
changelog.unownedPaths to change that:
include(default): shared files appear in this workspace’s changelog.exclude: this workspace ignores shared files.own: this workspace owns them, and every other workspace ignores them. At most one workspace can useown.
For example, when the main application lives at the repository root next to independently released packages:
workspaces: app: changelog: policy: auto unownedPaths: own packages/ui: changelog: policy: autoapp gets commits to root files, and packages/ui gets only commits that touch
packages/ui.
A workspace’s first release has no previous tag. Craft then starts its
changelog at the commit that added the workspace to .craft.yml instead of the
start of the repository history. Push a tag with the workspace’s tag prefix to
start from a different commit.
Title Stripping (Default Behavior)
Section titled “Title Stripping (Default Behavior)”By default, conventional commit prefixes are stripped from changelog entries.
The type (e.g., feat:) is removed, and the scope is preserved when entries
aren’t grouped under a scope header.
This behavior is controlled by named capture groups in commit_patterns:
(?<type>...)- The type prefix to strip (includes type, scope, and colon)(?<scope>...)- Scope to preserve when not under a scope header
| Original Title | Scope Header | Displayed Title |
|---|---|---|
feat(api): add endpoint |
Yes (Api) | Add endpoint |
feat(api): add endpoint |
No | (api) Add endpoint |
feat: add endpoint |
N/A | Add endpoint |
To disable stripping, provide custom patterns using non-capturing groups:
commit_patterns: - "^feat(?:\\([^)]+\\))?!?:" # No named groups = no strippingSkipping Changelog Entries
Section titled “Skipping Changelog Entries”You can exclude PRs or commits from the changelog in several ways:
Magic Word
Section titled “Magic Word”Add #skip-changelog anywhere in your commit message or PR body:
chore: Update dependencies
#skip-changelogSkip Label
Section titled “Skip Label”PRs with the skip-changelog label are automatically excluded.
Configuration
Section titled “Configuration”Configure exclusions in .github/release.yml:
changelog: exclude: labels: - skip-changelog - dependencies authors: - dependabot[bot] - renovate[bot]Configuration Options
Section titled “Configuration Options”| Option | Description |
|---|---|
changelog |
Path to changelog file (string) OR configuration object |
changelog.filePath |
Path to changelog file. Defaults to <workspace>/CHANGELOG.md for a directory workspace, otherwise CHANGELOG.md. Explicit paths take precedence. |
changelog.policy |
Mode: none, simple, or auto. Default: none |
changelog.scopeGrouping |
Enable scope-based grouping. Default: true |
changelog.includePaths |
Extra workspace directories to include in automatic changelogs. Release workspaces only. Default: [] |
changelog.unownedPaths |
include, exclude, or own files outside every workspace. Release workspaces only. Default: include |
changelog.aiSummary |
Opt-in HTTP release, category, and scope summaries. Default: disabled. |
Versioning
Section titled “Versioning”Configure default versioning behavior:
versioning: policy: auto # auto, manual, or calverVersioning Policies
Section titled “Versioning Policies”| Policy | Description |
|---|---|
auto |
Analyze commits to determine version bump (default when using craft prepare auto) |
manual |
Require explicit version argument |
calver |
Use calendar-based versioning |
Calendar Versioning (CalVer)
Section titled “Calendar Versioning (CalVer)”For projects using calendar-based versions:
versioning: policy: calver calver: format: '%y.%-m' # e.g., 24.12 for December 2024 offset: 14 # Days to look back for date calculationFormat supports:
%y- 2-digit year%m- Zero-padded month%-m- Month without padding
Minimal Version
Section titled “Minimal Version”Require a minimum Craft version:
minVersion: '0.5.0'Required Files
Section titled “Required Files”Ensure specific artifacts exist before publishing:
requireNames: - /^sentry-craft.*\.tgz$/ - /^gh-pages.zip$/Status Provider
Section titled “Status Provider”Configure build status checks:
statusProvider: name: github config: contexts: - Travis CI - BranchArtifact Provider
Section titled “Artifact Provider”Configure where to fetch artifacts from:
artifactProvider: name: github # or 'gcs' or 'none'GitHub Artifact Provider Configuration
Section titled “GitHub Artifact Provider Configuration”By default, the GitHub artifact provider looks for artifacts named exactly as the commit SHA. You can customize this with the artifacts configuration option.
Pattern Syntax
Section titled “Pattern Syntax”- Regex patterns: Wrapped in
/(e.g.,/^build-.*$/) - Exact strings: Plain text (e.g.,
build,release-artifacts)
Configuration Formats
Section titled “Configuration Formats”1. Single artifact pattern - searches all workflows:
artifactProvider: name: github config: artifacts: /^sentry-.*\.tgz$/2. Multiple artifact patterns - searches all workflows:
artifactProvider: name: github config: artifacts: - /^sentry-.*\.tgz$/ - release-bundle3. Workflow-scoped patterns - filter by workflow name:
artifactProvider: name: github config: artifacts: build: release-artifacts # exact workflow → exact artifact /^build-.*$/: artifacts # workflow pattern → exact artifact ci: # exact workflow → multiple artifacts - /^output-.*$/ - bundle /^release-.*$/: # workflow pattern → multiple artifacts - /^dist-.*$/ - checksumsCommon Examples
Section titled “Common Examples”Fetch artifacts named craft-binary and craft-docs from the “Build & Test” workflow:
artifactProvider: name: github config: artifacts: Build & Test: - craft-binary - craft-docsFetch all .tgz files from any workflow:
artifactProvider: name: github config: artifacts: /\.tgz$/Backward Compatibility
Section titled “Backward Compatibility”When artifacts is not configured, the provider uses the legacy behavior where it searches for an artifact with a name matching the commit SHA exactly. This ensures existing configurations continue to work without changes.
Targets
Section titled “Targets”List release targets in your configuration:
targets: - name: npm - name: github - name: registry id: browser type: sdk onlyIfPresent: /^sentry-browser-.*\.tgz$/See Target Configurations for details on each target.
Per-target Options
Section titled “Per-target Options”These options apply to all targets:
| Option | Description |
|---|---|
includeNames |
Regex: only matched files are processed |
excludeNames |
Regex: matched files are skipped |
id |
Unique ID for the target (use with -t target[id]) |
Example:
targets: - name: github includeNames: /^.*\.exe$/ excludeNames: /^test.exe$/