# Migration Guide
## Overview
| Version | Theme | Key changes |
|---------|-------|-------------|
| **3.x** | AI-powered CLI | Built-in AI backends, git hooks, flat config |
| **4.x** | Config restructure + MCP | Nested config, MCP server, AI backends removed (commands kept as thin wrappers) |
| **5.x** | Release-only CLI | CLI commands stripped to release engineering; all git/PR/review workflows move to MCP tools |
| **6.x** | MCP-first workflows | PR, worktree, and breaking-commit tools added to MCP server; `sr init` improved |
| **7.x** | Config redesign | Entire config structure rewritten; 6 top-level sections; MCP server removed; agentspec removed; file snapshot/rollback removed |
| **7.1** | Build stage + reconciliation | New `hooks.build` phase runs after bump before tag; declared artifacts validated before tagging; `sr-manifest.json` proves completion; idempotent uploads; reconciliation blocks new releases on top of broken ones |
---
## Migrating from 3.x to 4.x
### Config restructured
The flat `sr.yaml` was reorganized into three sections — `commit`, `release`, `hooks`:
```yaml
# 3.x (flat)
branches: [main]
tag_prefix: "v"
commit_pattern: '...'
types: [...]
build_command: "cargo build --release"
pre_release_command: "cargo test"
hooks:
commit-msg: [sr hook commit-msg]
# 4.x (grouped by concern)
commit:
pattern: '...'
types: [...]
release:
branches: [main]
tag_prefix: "v"
version_files: [Cargo.toml]
floating_tags: true
hooks:
pre_release: ["cargo test"]
post_release: ["./notify.sh"]
```
Field mappings:
| 3.x field | 4.x location |
|-----------|--------------|
| `branches` | `release.branches` |
| `tag_prefix` | `release.tag_prefix` |
| `commit_pattern` | `commit.pattern` |
| `breaking_section` | `commit.breaking_section` |
| `misc_section` | `commit.misc_section` |
| `types` | `commit.types` |
| `version_files` | `release.version_files` |
| `floating_tags` | `release.floating_tags` |
| `artifacts` | `release.artifacts` |
| `stage_files` | `release.stage_files` |
| `build_command` | Removed — use `hooks.pre_release` |
| `pre_release_command` | `hooks.pre_release` |
| `post_release_command` | `hooks.post_release` |
| `hooks.commit-msg` | Removed |
| `hooks.pre-commit` | Removed |
### AI backends removed
sr 3.x called AI providers directly. In 4.x, the AI module was removed. Commands
(`commit`, `pr`, `review`, `worktree`, `rebase`) were kept as thin non-AI wrappers
that accept explicit flags instead of generating content.
### MCP server added
`sr mcp serve` exposes git operations as tools for AI assistants (Claude Code,
Gemini CLI, etc.). `sr init` creates both `sr.yaml` and `.mcp.json`.
### Git hooks removed
sr 3.x installed git hooks (`commit-msg`, `pre-commit`) via `.githooks/`. These
no longer exist. Remove them:
```bash
rm -rf .githooks/
rm -f .git/hooks/commit-msg .git/hooks/pre-commit .git/hooks/pre-push
git config --unset core.hooksPath 2>/dev/null || true
```
The 4.x `hooks:` section uses lifecycle event names (`pre_release`, `post_release`)
instead of git hook names.
### Crate consolidation
5 crates consolidated to 2:
| 3.x crate | 4.x status |
|------------|------------|
| `sr-ai` | Removed |
| `sr-git` | Merged into `sr-core` |
| `sr-github` | Merged into `sr-core` |
| `sr-core` | All release logic, git, GitHub, config |
| `sr-cli` | CLI dispatch only |
### GitHub Action: v3 → v4
Update `@v3` → `@v4`:
```yaml
# Before
- uses: urmzd/sr@v3
# After
- uses: urmzd/sr@v4
```
**Inputs removed in v4:**
| v3 input | What happened |
|----------|---------------|
| `command` | Removed. v3 accepted any subcommand (`release`, `plan`, `commit`, `pr`, etc.). v4 always runs `sr release` or `sr status`. |
| `force` | Removed in v4 (restored in v5). |
| `config` | Removed. sr always reads `sr.yaml` from the repo root. |
| `artifacts` | Removed in v4 (restored in v5). v3 accepted newline/comma-separated globs. |
| `build-command` | Removed. Use `hooks.pre_release` in `sr.yaml` instead. |
**Execution model changes:**
| Aspect | v3 | v4 |
|--------|----|----|
| Command dispatch | Configurable — any sr subcommand via `command` input | Fixed — always `sr release` or `sr status --format json` |
| Arg passing | Array-based (`sr "${ARGS[@]}"`) | Simple string (`sr $CMD`) |
| Artifact handling | Parsed from newline/comma input, each passed as `--artifacts` | Not supported |
| Build command | Written to temp script, passed as `--build-command` | Removed |
| Logging | `::group::` blocks with verbose echo | Minimal, no grouping |
| Exit code 2 | Sets all outputs to empty strings | Only sets `released=false` |
---
## Migrating from 4.x to 5.x
### CLI commands removed
The thin wrapper commands added in 4.x were removed. These workflows now live
entirely in the MCP server tools:
| Removed CLI command | MCP tool equivalent |
|---------------------|---------------------|
| `sr commit` | `sr_commit` (via `sr mcp serve`) |
| `sr pr` | `sr_pr_template` + `sr_pr_create` |
| `sr review` | AI assistant + `gh` CLI |
| `sr worktree` | `sr_worktree` + `sr_worktree_list` + `sr_worktree_remove` |
| `sr rebase` | `git rebase` directly |
| `sr plan` | `sr status` |
| `sr version` | `sr status --format json \| jq .next_version` |
| `sr changelog` | Generated automatically by `sr release` |
**Remaining CLI commands:** `release`, `status`, `config`, `init`, `mcp`, `migrate`,
`completions`, `update`.
### MCP tools expanded
New tools available via `sr mcp serve`:
| Tool | Description |
|------|-------------|
| `sr_commit` | Now supports `breaking` flag — auto-adds `!` and `BREAKING CHANGE:` footer |
| `sr_pr_template` | Generates PR template from branch commits/diff stats |
| `sr_pr_create` | Creates GitHub PR via `gh` CLI (title, body, labels, draft) |
| `sr_worktree` | Creates worktrees under `.sr/worktrees/` with metadata tracking |
| `sr_worktree_list` | Lists all worktrees with descriptions and creation dates |
| `sr_worktree_remove` | Removes worktree and cleans up metadata |
### Dirty working tree check removed
sr 4.x refused to release if the working tree had uncommitted changes. This check
was removed in 5.x because sr only stages files it explicitly modifies (version
files, changelog, stage_files) — it never runs `git add -A`. Unrelated files in
the working tree (downloaded CI artifacts, build outputs) are harmless and were
causing false failures.
### GitHub Action: v4 → v5
Update `@v4` → `@v5`:
```yaml
# Before
- uses: urmzd/sr@v4
# After — basic
- uses: urmzd/sr@v5
# After — with artifacts
- uses: urmzd/sr@v5
with:
github-token: ${{ steps.app-token.outputs.token }}
artifacts: "release-assets/*"
```
**Inputs restored from v3:**
| Input | v3 | v4 | v5 |
|-------|:---:|:---:|:---:|
| `force` | `false` | Removed | `false` — adds `--force` |
| `artifacts` | Newline/comma-separated | Removed | Space-separated, each passed as `--artifacts "glob"` |
**New inputs in v5:**
| Input | Default | Description |
|-------|---------|-------------|
| `package` | `""` | Target a specific monorepo package |
| `channel` | `""` | Release channel (e.g. canary, rc, stable) |
| `prerelease` | `""` | Pre-release identifier (e.g. alpha, beta, rc) |
| `stage-files` | `""` | Additional file globs to stage in release commit (space-separated) |
| `sign-tags` | `false` | Sign tags with GPG/SSH |
| `draft` | `false` | Create GitHub release as a draft |
**Execution model changes:**
| Aspect | v4 | v5 |
|--------|----|----|
| Arg passing | Simple string (`sr $CMD`) | `eval sr $CMD` (supports quoted globs) |
| Dirty tree check | sr refuses if working tree is dirty | Removed — unrelated files are harmless |
| CLI flag coverage | Only `--dry-run` | All `sr release` flags exposed as inputs |
**Inputs unchanged across all versions:**
| Input | Default |
|-------|---------|
| `dry-run` | `false` |
| `github-token` | `${{ github.token }}` |
| `git-user-name` | `sr[bot]` |
| `git-user-email` | `sr[bot]@urmzd.com` |
| `sha256` | `""` |
**Outputs unchanged across all versions:**
| Output | Description |
|--------|-------------|
| `version` | Released version |
| `previous-version` | Previous version |
| `tag` | Git tag created |
| `bump` | Bump level (major/minor/patch) |
| `floating-tag` | Floating major tag (e.g. `v3`) |
| `commit-count` | Commits included |
| `released` | `true`/`false` |
| `json` | Full release metadata as JSON |
### `sr init` improvements
- No longer fails if `sr.yaml` already exists — each step (sr.yaml, .mcp.json,
.gitignore) runs independently
- Automatically adds `.sr/` to `.gitignore` (used for worktree metadata and cache)
### Worktree management via `.sr/`
Worktrees created via MCP (`sr_worktree`) are stored under `.sr/worktrees/`
instead of sibling directories. Each worktree gets a metadata file at
`.sr/worktrees/<branch>.json` tracking its purpose, description, and creation
date. The `.sr/` directory is automatically gitignored by `sr init`.
---
## Migrating from 5.x to 6.x
v6 is a non-breaking release that was triggered by a version bump. There are no
breaking changes for users. All v5 config, action inputs, and CLI commands work
unchanged.
### What's new in v6
**MCP tools added:**
| Tool | Description |
|------|-------------|
| `sr_commit` | Now supports `breaking` flag — auto-adds `!` suffix and `BREAKING CHANGE:` footer |
| `sr_pr_template` | Generates PR template from branch commits and diff stats |
| `sr_pr_create` | Creates GitHub PR via `gh` CLI (title, body, labels, draft) |
| `sr_worktree` | Creates worktrees under `.sr/worktrees/` with metadata tracking |
| `sr_worktree_list` | Lists all worktrees with descriptions and creation dates |
| `sr_worktree_remove` | Removes worktree and cleans up metadata |
**`sr init` improvements:**
- No longer fails if `sr.yaml` already exists — each step (sr.yaml, .mcp.json,
.gitignore) runs independently and skips files that already exist
- Automatically adds `.sr/` to `.gitignore` (used for worktree metadata)
### GitHub Action: v5 → v6
Update `@v5` → `@v6`. All inputs and outputs are unchanged:
```yaml
# Before
- uses: urmzd/sr@v5
# After
- uses: urmzd/sr@v6
```
### Worktree management via `.sr/`
Worktrees created via MCP (`sr_worktree`) are stored under `.sr/worktrees/`
instead of sibling directories. Each worktree gets a metadata file at
`.sr/worktrees/<branch>.json` tracking its purpose, description, and creation
date. The `.sr/` directory is automatically gitignored by `sr init`.
---
## Migrating from 7.0 to 7.1
v7.1 is **additive, non-breaking**. Existing configs and workflows continue to work unchanged. The new capabilities are opt-in via `hooks.build`, plus one automatic behavior change: sr now uploads `sr-manifest.json` as the final asset on every release and refuses to cut a new release on top of a broken one.
### What changed in the pipeline
Old order (v7.0):
```
pre_release hooks → bump → commit → tag → push → create release → upload artifacts → post_release hooks
```
New order (v7.1):
```
pre_release hooks → bump → build → validate → commit → tag → push → create release → upload artifacts → post_release hooks → upload manifest
```
Two new stages:
- **`build`**: runs configured `hooks.build` commands after version files have been bumped on disk. Binaries built here embed the new version.
- **`validate`**: when `hooks.build` is non-empty, every `artifacts:` glob must resolve to ≥1 file, else the release aborts before tag creation. Guarantees the tag invariant: a tag on remote implies the declared artifacts exist.
Two new behaviors:
- **Idempotent upload**: `UploadArtifacts` skips any asset whose basename is already present on the release. Safe to re-run.
- **Reconciliation check**: at the start of `sr release`, sr inspects the latest remote tag's `sr-manifest.json`. If it declares artifacts that aren't present on the release, sr errors with: `previous release v1.2.3 is incomplete: ... missing (...). Heal it first — git checkout v1.2.3 && sr release --force — then re-run sr release.` Tags with no manifest (legacy) pass silently. `--force` bypasses.
### Opt-in `hooks.build` (recommended)
Move build commands from external CI steps (or from `hooks.pre_release`, where they would have embedded the pre-bump version) into `hooks.build`:
```yaml
# v7.0 (still works, but binaries embed old version)
packages:
- path: .
artifacts: ["release-assets/*.tar.gz"]
hooks:
pre_release:
- cargo build --release # runs BEFORE version bump — wrong version
post_release:
- cargo publish
# v7.1 (build embeds new version, sr validates output)
packages:
- path: .
artifacts: ["release-assets/*.tar.gz"]
hooks:
pre_release:
- cargo test # validations that can abort the release
build:
- cargo build --release # runs AFTER bump — embeds new version
- mkdir -p release-assets
- tar czf release-assets/sr.tar.gz target/release/sr
post_release:
- cargo publish
```
If `hooks.build` is empty, pipeline behavior is identical to v7.0 — no validation, no enforcement.
### GitHub Actions workflow changes
Workflows pin `urmzd/sr@v7` (floating major) — they pick up v7.1 automatically. Per-pattern guidance:
**Pattern A — build + sr in same job (teasr, fsrc, agentspec, github-insights, urmzd.com, zigbee-skill).** Move the build steps from the workflow into `hooks.build` in `sr.yaml`. The workflow reduces to a single `urmzd/sr@v7` step.
```yaml
# Before: separate build step in the workflow
- run: cargo build --release
- run: tar czf release-assets/app.tar.gz target/release/app
- uses: urmzd/sr@v7
# After: build lives in sr.yaml hooks.build; workflow just invokes sr
- uses: urmzd/sr@v7
```
**Pattern B — parallel matrix build → consolidate → sr (sr itself).** Keep the matrix. `hooks.build` runs in one process on one runner and cannot replace a cross-runner matrix. Leave `hooks.build` empty; ValidateArtifacts stays inactive (same safety level as v7.0). Reconciliation still applies.
**Pattern C — sr-only, no build (streamsafe, lazyspeak.nvim, mnemonist).** No change.
**Pattern D — post-release build (incipit, linear-gp, saige).** This pattern is structurally unreachable by sr's validation: sr completes (no artifacts declared → validate skipped → manifest uploaded as "complete"), then the workflow's post-release build runs outside sr. If that build fails, sr has no record and reconciliation won't trigger on the next release. Two options: (a) move the build into `hooks.build` on the same runner as sr, or (b) accept that this pattern has no binary-presence guarantee.
### Recovery: when a release breaks mid-way
Under v7.1, a partial failure is now detectable and recoverable:
```bash
# Scenario: sr uploaded 2 of 3 declared artifacts, then CI runner died.
# Next release attempt:
$ sr release
Error: previous release v1.2.3 is incomplete: 1 declared asset(s) missing
(sr-aarch64-darwin.tar.gz). Heal it first — git checkout v1.2.3 && sr release --force —
then re-run sr release.
# Heal:
$ git checkout v1.2.3
$ sr release --force # re-runs the pipeline; idempotent upload skips the 2 already present
$ git checkout main
$ sr release # now succeeds; cuts v1.2.4
```
If a workflow needs to trigger recovery non-interactively, add a `force` input:
```yaml
on:
workflow_dispatch:
inputs:
force:
description: "Re-release current tag (reconcile broken release)"
type: boolean
default: false
- uses: urmzd/sr@v7
with:
force: ${{ inputs.force }}
```
Many repos already have this input — they're ready.
### Legacy releases
Releases created before v7.1 don't have `sr-manifest.json`. sr treats them as `Unknown` status, neither complete nor incomplete, and doesn't block future releases. The manifest-based reconciliation only applies to releases cut by v7.1+.
---
## Migrating from 6.x to 7.x
v7 is a **breaking release** — the entire `sr.yaml` config structure was redesigned.
The old config had everything under `commit` and `release` top-level sections. The
new config has 6 top-level sections: `git`, `commit`, `changelog`, `channels`, `vcs`,
`packages`.
### Breaking changes summary
| Area | What changed |
|------|-------------|
| `commit.pattern` | Removed — regex is derived automatically from type names |
| `commit.types` | Changed from flat list `[{name, bump, section}]` to grouped by bump level `{minor: [], patch: [], none: []}` |
| `commit.breaking_section` / `commit.misc_section` | Removed — now configured via `changelog.groups` |
| `release.changelog` | Moved from under `release` to top-level `changelog` section |
| `release.branches` | Removed — channels now specify which branch to release from |
| `release.tag_prefix`, `sign_tags`, `floating_tags` | Moved to `git` section; `floating_tags` renamed to `floating_tag`; new `v0_protection` field added |
| `release.draft`, `prerelease` | Moved into channel config (`channels.content[].draft`, `channels.content[].prerelease`) |
| `release.release_name_template` | Moved to `vcs.github.release_name_template` |
| `release.channels` (map) | Replaced by top-level `channels` (object with `default` + `content` array) |
| `release.versioning` | Replaced by `packages[].independent` (bool) |
| `release.version_files`, `artifacts`, `stage_files` | Moved to package config (`packages[].version_files`, etc.) |
| `hooks` (top-level) | Removed — only package-level `packages[].hooks.pre_release` / `post_release` |
| `packages[].name` | Removed — package name is now derived from `path` |
| Per-type fallback `pattern` | Removed |
| MCP server | Removed (`sr mcp serve` command gone, delete `.mcp.json`) |
| agentspec dependencies | Removed |
| File snapshot/rollback | Removed (unnecessary complexity) |
### Before / After config comparison
**v6 `sr.yaml`:**
```yaml
commit:
pattern: '^(?P<type>\w+)(?:\((?P<scope>[^)]+)\))?(?P<breaking>!)?:\s+(?P<description>.+)'
breaking_section: Breaking Changes
misc_section: Miscellaneous
types:
- name: feat
bump: minor
section: Features
- name: fix
bump: patch
section: Bug Fixes
- name: perf
bump: patch
section: Performance
- name: docs
section: Documentation
- name: refactor
bump: patch
section: Refactoring
- name: revert
section: Reverts
- name: chore
- name: ci
- name: test
- name: build
- name: style
release:
branches: [main]
tag_prefix: "v"
floating_tags: true
sign_tags: false
changelog:
file: CHANGELOG.md
version_files:
- Cargo.toml
stage_files:
- Cargo.lock
artifacts:
- "target/release/sr-*"
draft: false
channels:
canary:
prerelease: canary
stable: {}
default_channel: stable
hooks:
pre_release:
- cargo build --release
post_release:
- cargo publish
```
**v7 `sr.yaml`:**
```yaml
git:
tag_prefix: "v"
floating_tag: true
sign_tags: false
v0_protection: true
commit:
types:
minor:
- feat
patch:
- fix
- perf
- refactor
none:
- docs
- revert
- chore
- ci
- test
- build
- style
changelog:
file: CHANGELOG.md
groups:
- name: breaking
content:
- breaking
- name: features
content:
- feat
- name: bug-fixes
content:
- fix
- name: performance
content:
- perf
- name: misc
content:
- chore
- ci
- test
- build
- style
channels:
default: stable
branch: main
content:
- name: canary
prerelease: canary
- name: stable
vcs:
github:
release_name_template: "{{ tag_name }}"
packages:
- path: .
version_files:
- Cargo.toml
stage_files:
- Cargo.lock
artifacts:
- "target/release/sr-*"
hooks:
pre_release:
- cargo build --release
post_release:
- cargo publish
```
### Field-by-field migration guide
| v6 field | v7 equivalent |
|----------|---------------|
| `commit.pattern` | Removed — derived from type names automatically |
| `commit.breaking_section` | `changelog.groups[].name` where `content: [breaking]` |
| `commit.misc_section` | `changelog.groups[].name` for catch-all types |
| `commit.types[].name` | Key in `commit.types.minor[]`, `commit.types.patch[]`, or `commit.types.none[]` |
| `commit.types[].bump: minor` | Move type name to `commit.types.minor[]` |
| `commit.types[].bump: patch` | Move type name to `commit.types.patch[]` |
| `commit.types[].bump: null` | Move type name to `commit.types.none[]` |
| `commit.types[].section` | `changelog.groups[].name` with the type in `content` |
| `commit.types[].pattern` | Removed — no per-type fallback patterns |
| `release.branches` | `channels.content[].branch` (each channel specifies its branch) |
| `release.tag_prefix` | `git.tag_prefix` |
| `release.floating_tags` | `git.floating_tag` |
| `release.sign_tags` | `git.sign_tags` |
| `release.changelog.file` | `changelog.file` |
| `release.changelog.template` | `changelog.template` (now a file path, not inline string) |
| `release.version_files` | `packages[].version_files` |
| `release.artifacts` | `packages[].artifacts` |
| `release.stage_files` | `packages[].stage_files` |
| `release.draft` | `channels.content[].draft` |
| `release.prerelease` | `channels.content[].prerelease` |
| `release.release_name_template` | `vcs.github.release_name_template` |
| `release.channels` (map) | `channels.content` (array) |
| `release.default_channel` | `channels.default` |
| `release.versioning: independent` | `packages[].independent: true` (default) |
| `release.versioning: fixed` | `packages[].independent: false` |
| `hooks.pre_release` | `packages[].hooks.pre_release` |
| `hooks.post_release` | `packages[].hooks.post_release` |
| `packages[].name` | Removed — derived from `path` |
### Step-by-step migration
1. **Replace `commit` section** — convert the flat types list to the grouped format:
```yaml
# Before
commit:
types:
- name: feat
bump: minor
- name: fix
bump: patch
- name: chore
# After
commit:
types:
minor: [feat]
patch: [fix]
none: [chore]
```
2. **Move `release.changelog` to top-level `changelog`** — and replace `breaking_section`/`misc_section` with `groups`:
```yaml
# Before
release:
changelog:
file: CHANGELOG.md
commit:
breaking_section: "Breaking Changes"
# After
changelog:
file: CHANGELOG.md
groups:
- name: breaking
content: [breaking]
- name: features
content: [feat]
- name: bug-fixes
content: [fix]
- name: misc
content: [chore, ci, test, build, style]
```
3. **Move git settings to `git` section:**
```yaml
# Before
release:
tag_prefix: "v"
floating_tags: true
sign_tags: false
# After
git:
tag_prefix: "v"
floating_tag: true # renamed: floating_tags → floating_tag
sign_tags: false
v0_protection: true # new field
```
4. **Convert `release.channels` map to `channels` array:**
```yaml
# Before
release:
branches: [main]
channels:
stable: {}
canary:
prerelease: canary
default_channel: stable
# After
channels:
default: stable
branch: main # single trunk branch
content:
- name: stable
- name: canary
prerelease: canary
```
5. **Move `release.version_files`, `artifacts`, `stage_files`, and `hooks` under `packages`:**
```yaml
# Before
release:
version_files: [Cargo.toml]
artifacts: ["target/release/sr-*"]
stage_files: [Cargo.lock]
hooks:
pre_release: [cargo build --release]
post_release: [cargo publish]
# After
packages:
- path: .
version_files: [Cargo.toml]
artifacts: ["target/release/sr-*"]
stage_files: [Cargo.lock]
hooks:
pre_release: [cargo build --release]
post_release: [cargo publish]
```
6. **Move `release.release_name_template` to `vcs`:**
```yaml
# Before
release:
release_name_template: "{{ tag_name }}"
# After
vcs:
github:
release_name_template: "{{ tag_name }}"
```
7. **Remove `packages[].name`** — the name is now derived from `path` automatically.
8. **Delete `.mcp.json`** — the MCP server has been removed:
```bash
rm .mcp.json
```
9. **Update the action** — change `@v6` to `@v7`:
```yaml
# Before
- uses: urmzd/sr@v6
# After
- uses: urmzd/sr@v7
```
### MCP server removed
The MCP server (`sr mcp serve`) and `.mcp.json` have been removed entirely.
| Removed | What to do |
|---------|------------|
| `sr mcp serve` | Delete `.mcp.json`; use the `sr` agent skill instead |
| `.mcp.json` | Delete from project root |
### GitHub Action: v6 → v7
The action inputs and outputs are unchanged. Only the version tag changes:
```yaml
# Before
- uses: urmzd/sr@v6
# After
- uses: urmzd/sr@v7
```
---
## Migrating from 3.x directly to 7.x
Follow the 3.x→4.x, 4.x→5.x, 5.x→6.x, and 6.x→7.x sections above in order,
or use this quick checklist:
1. **Remove git hooks** — delete `.githooks/`, unset `core.hooksPath`
2. **Restructure sr.yaml** — rewrite config using the new 6-section format
3. **Delete `.mcp.json`** — MCP server was removed in v7
4. **Update action** — change `@v3` to `@v7`
5. **Update scripts** — replace `sr version`, `sr changelog`, `sr plan` with `sr status`
### Action input migration: v3 → v7
| v3 input | v7 equivalent |
|----------|---------------|
| `command: release` | Default (no input needed) |
| `command: plan` | `dry-run: "true"` |
| `command: <other>` | Removed — use CLI or agent skills |
| `artifacts: "dist/*\nbin/*"` | `artifacts: "dist/* bin/*"` (space-separated) |
| `build-command: "make"` | Removed — use `packages[].hooks.pre_release` in sr.yaml |
| `config: custom.yaml` | Removed — always reads `sr.yaml` |
| `force: true` | `force: "true"` (same) |
### CI/CD script migration
```bash
# 3.x
VERSION=$(sr version --short)
sr changelog --write
sr plan --format json
# 7.x
VERSION=$(sr status --format json | jq -r '.next_version')
# Changelog is written automatically by sr release
sr status --format json
```