본문으로 건너뛰기
cccskills
무료GitHub에 공개

prepare-release

Cut a new Voxt release. Use when the user says "prepare a release", "cut a release", "release Voxt", "do a release", "/prepare-release", or wants to run nbgv prepare-release, bump the version, generate end-user release notes, and announce them in the Releases chat.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(1)

  • SKILL.md14.0 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

prepare-release

Cut a Voxt release end to end: bump the version with nbgv, push dev + the new release/vX.Y branch, generate end-user release notes from the commit log, commit them to docs/releases/, and announce them in the Releases chat via RoboKitty.

This is a release action that pushes branches and posts publicly. Do the git mutations without stopping between mechanical steps, but pause once to let the user review the drafted release notes before the notes commit and the RoboKitty post (steps 6–8). Those are the hard-to-revert, outward-facing parts.

Reuse

  • nbgv (Nerdbank.GitVersioning) drives all versioning — never hand-edit version.json's version field. Branch name comes from version.json's release.branchName = release/v{version}.
  • RoboKitty MCP (mcp__voxt-robokitty__post_message) posts the announcement — same path /my-changes --post and /robokitty-post use. No new HTTP code.
  • Release-notes style is defined below; match prior notes' tone, don't reinvent a format.
  • Store notes (docs/releases/store-notes-vX.Y.txt) feed promote-release.yml — the same file is pushed to Google Play, the App Store and the Microsoft Store, so it's a plain-text distillation of the notes.
  • The configs sibling repo needs a matching release/vX.Y branch — CI loads config from it. Locate the clone first (step 3); don't skip step 3b.

Prerequisites

  • Clean working tree on dev (git status is clean; if not, stop and ask).
  • nbgv available. It's a local tool pinned in .config/dotnet-tools.json, so run dotnet tool restore once, then dotnet nbgv get-version to confirm.
  • You are up to date: git fetch origin && git switch dev && git pull --ff-only.

Steps

1. Read the target version

cat version.json      # e.g. "version": "2.13-alpha"

The release version is that value with any -alpha/prerelease tag dropped (2.13-alpha → 2.13). Call it X.Y. The new branch will be release/vX.Y. After prepare-release, dev bumps to the next minor (2.14-alpha).

2. Run prepare-release

On dev:

dotnet nbgv prepare-release

This creates release/vX.Y (version set to X.Y) and advances dev to the next -alpha, committing on both. Verify:

git branch --list 'release/v*' | tail; git log --oneline -1 dev

3. Cut and push the configs release branch FIRST

The CI build loads configuration from the configs repo's release/vX.Y branch, so it must exist before you push the app's release branch — otherwise the release build the app-branch push triggers fails for lack of config. Its remote is git@github.com:Actual-Chat/configs.git.

Find the actual clone first — do not assume a path or a folder name. It lives beside this repo, but the folder may be called configs, ActualChat.configs, actual-chat-configs, or anything similar, and the project root differs per environment (/proj in the AgentCli Docker container, D:\Projects on Windows, ~/Projects on macOS — see AC_ProjectRoot). Match on the remote URL, which is the only stable identifier:

root="${AC_ProjectRoot:-$(cd "$(git rev-parse --show-toplevel)/.." && pwd)}"
configs=""
for d in "$root"/*/; do
    url=$(git -C "$d" remote get-url origin 2>/dev/null) || continue
    case "${url%.git}" in *[:/]Actual-Chat/configs) configs="${d%/}"; break;; esac
done
[ -n "$configs" ] || { git clone git@github.com:Actual-Chat/configs.git "$root/configs" && configs="$root/configs"; }
echo "configs repo: $configs"

Match the remote path exactly (after stripping .git), not as a substring — sibling roots hold near-miss repos that a loose pattern grabs instead. The [:/] class covers both remote forms (git@github.com:Actual-Chat/configs.git and https://github.com/Actual-Chat/configs).

Verify $configs is non-empty before using it. git -C "" silently operates on the current directory, so an empty variable turns every command below into one that rewrites branches in the app repo:

[ -n "$configs" ] && git -C "$configs" rev-parse --show-toplevel || { echo "configs repo not found — stop"; }

Then create release/vX.Y from the latest master and push. Use git -C "$configs" rather than cd, so later steps aren't left running from the wrong directory — the non-empty check above is what actually protects the app repo:

git -C "$configs" fetch origin
git -C "$configs" switch master && git -C "$configs" pull --ff-only
git -C "$configs" switch -c release/vX.Y     # skip if it already exists
git -C "$configs" push -u origin release/vX.Y

If the SSH remote can't authenticate in this environment, push over HTTPS with the token instead: git -C "$configs" push "https://x-access-token:${GH_TOKEN}@github.com/Actual-Chat/configs.git" release/vX.Y. If release/vX.Y already exists on origin and equals origin/master, it's already done — leave it.

Leave the clone on master when you're done. git switch -c without -u leaves the new branch untracked, and a checkout parked on a release branch is how prompt edits meant for dev end up on the wrong branch — dev CI reads configs master, release branches read their own.

3b. Push the app branches

Only after the configs branch is live:

git push origin dev
git push origin release/vX.Y

4. Get the one-line commit log since the previous release

The previous release branch is release/vX.(Y-1) on origin (e.g. release/v2.12). Collect subjects for the notes-writing input:

git log --format='%s' origin/release/vX.(Y-1)..release/vX.Y > /tmp/release-commits-vX.Y.txt
wc -l /tmp/release-commits-vX.Y.txt

Ignore the housekeeping lines (Set version to …, Merge branch …, AOT/AGENTS regeneration, pure test:/build:/chore: churn) when writing notes — they're not user-facing.

5. Write end-user release notes

Read the full commit log and distill it into end-user notes. This is the core judgment step — see Release-notes style below. Draft the file at docs/releases/release-notes-vX.Y.md.

5b. Write the store notes

Distill the notes once more into docs/releases/store-notes-vX.Y.txt. This file goes verbatim into Google Play's "What's new", the App Store's "What's New" and the Microsoft Store's release notes when the release is promoted (/promote-release), so:

  • 500 characters max including newlines — Play's limit, and the promote workflow refuses a longer file. Check with wc -m.
  • Plain text: no markdown, no bold, no headings. Emoji-free except • bullets.
  • First line: one sentence with the release theme. Then 4–6 • bullets, the biggest user-visible wins first, one line each.
  • Same voice as the notes, no sign-off. See store-notes-v2.17.txt for the shape.

STOP and show both drafts (notes + store notes) to the user for review before committing. Incorporate any edits they ask for.

6. Commit the notes on the release branch

git switch release/vX.Y
# write docs/releases/release-notes-vX.Y.md and store-notes-vX.Y.txt
git add docs/releases/release-notes-vX.Y.md docs/releases/store-notes-vX.Y.txt
git commit -m "docs: add release notes vX.Y"
git push origin release/vX.Y

7. Merge the notes into dev, push dev

git switch dev
git merge --no-ff release/vX.Y -m "Merge release notes vX.Y into dev"
git push origin dev

Usually this merges cleanly — git's ort strategy keeps dev's newer version.json, so the only change that lands on dev is the notes file. Verify after: grep '"version"' version.json should still show the next -alpha.

Only if version.json does conflict (release branch has X.Y, dev has the next -alpha), resolve by keeping dev's version before pushing:

git checkout --ours version.json && git add version.json
# resolve any other conflicts by keeping dev's side unless it's the notes file
git commit --no-edit
git push origin dev

If the only thing you actually need on dev is the notes files and the merge is noisy, the equivalent clean alternative is: git switch dev && git checkout release/vX.Y -- docs/releases/release-notes-vX.Y.md docs/releases/store-notes-vX.Y.txt && git commit -m "docs: add release notes vX.Y" && git push origin dev.

/promote-release dispatches promote-release.yml on release/vX.Y and reads docs/releases/store-notes-vX.Y.txt from there, so step 6 is what makes the promotion possible; this merge just keeps dev complete.

8. Announce in the Releases chat via RoboKitty

Only if the RoboKitty MCP is available (mcp__voxt-robokitty__post_message tool present). The Releases chat is:

  • URL: https://voxt.ai/chat/s-pmMsV1UVKG-dCKQXnYpX9
  • chatId: s-pmMsV1UVKG-dCKQXnYpX9 (place pmMsV1UVKG)

Post the release notes wrapped in a fenced code block so they render verbatim:

mcp__voxt-robokitty__post_message(
  chatId = "s-pmMsV1UVKG-dCKQXnYpX9",
  text   = "```\n<the full release-notes markdown>\n```"
)

Confirm with a one-liner: Posted release notes vX.Y → Releases (LID: <id>). On any MCP failure, surface the error verbatim and stop — don't retry blindly.

If the mcp__voxt-robokitty__* tools aren't loaded this session (common — the server is declared in .mcp.json but not always auto-connected), call the HTTP endpoint directly instead of asking the user to paste. It's the same RoboKitty server over plain JSON-RPC, authed with ActualChat_RoboKitty_API_Key:

# wrap the committed notes in a code fence
{ echo '```'; cat docs/releases/release-notes-vX.Y.md; echo '```'; } > /tmp/rk-text.txt
# build the JSON-RPC body with jq (safe escaping of backticks/emoji/newlines)
jq -n --rawfile t /tmp/rk-text.txt \
  '{jsonrpc:"2.0",id:2,method:"tools/call",params:{name:"post_message",
    arguments:{chatId:"s-pmMsV1UVKG-dCKQXnYpX9",text:$t}}}' > /tmp/rk-body.json
curl -s -X POST "https://voxt.ai/mcp" \
  -H "Authorization: Bearer ${ActualChat_RoboKitty_API_Key}" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  --data-binary @/tmp/rk-body.json

The response is an SSE data: line; success looks like "structuredContent":{"result":<LID>}. Report that LID. (Use the prod key/URL above; ActualChat_RoboKitty_Dev_API_Key + https://dev.voxt.ai/mcp target the dev instance.) Only if neither the tool nor the key is available, print the notes for the user to paste manually.

9. Hand off to the promotion

The release/vX.Y push triggers the release build. Its prod deploy jobs wait for a Maintainers approval in the prod environment, then only stage the apps: Play internal track, TestFlight (iOS + Mac), a pending Microsoft Store submission. Nothing reaches end users yet. Tell the user:

Release build: <run url>. Approve the prod deployment, test the staged builds, then run /promote-release to publish them.

Release-notes style

The notes are for end users, not engineers. Translate commits into user value; drop implementation detail entirely.

  • Header: **🎉 Voxt vX.Y is here! 🎉** then a one/two-sentence summary of the release's theme.
  • Body: grouped sections under bold headings with an emoji, e.g. **🚀 What's New**, then feature blocks. Use short prose or tight bullet lists. Lead with the biggest user-visible wins.
  • Group many small commits into one plain-language line ("Dozens of small fixes — quiet polish across UI, animations, and edge cases").
  • No commit hashes, file names, class names, RPC/codec/internal terms.
  • Roughly one screenful; short releases can be ~15 lines, big ones ~40.
  • Footer: a warm thanks + — The Voxt.ai team 🎧.

Keep the voice friendly and confident. When in doubt about whether a change is worth mentioning, ask: "would a user notice or care?" If no, fold it into the "small fixes" line or drop it.

Quick reference

StepCommand / action
Target versioncat version.json → drop -alpha → X.Y
Bumpdotnet nbgv prepare-release (on dev)
Config branch (first!)configs clone (locate by remote URL, step 3): release/vX.Y from latest master, push — CI loads it
Push app branchesgit push origin dev && git push origin release/vX.Y (after config branch)
Commit loggit log --format='%s' origin/release/vX.(Y-1)..release/vX.Y
Notes filedocs/releases/release-notes-vX.Y.md
Store notesdocs/releases/store-notes-vX.Y.txt — plain text, ≤ 500 chars, committed with the notes
Merge to devgit merge --no-ff release/vX.Y, keep dev's version.json
Announcemcp__voxt-robokitty__post_message → s-pmMsV1UVKG-dCKQXnYpX9, code-fenced
Publish to storesnot here — /promote-release after the builds are tested

Common mistakes

  • Hand-editing version.json's version. Let nbgv own it. Only ever resolve it in the merge by keeping dev's side.
  • Copying commit subjects into the notes. Notes are user value, not a changelog. Rewrite everything.
  • Forgetting the code fence in the RoboKitty post — the notes must be inside triple-backticks so markdown renders literally.
  • Wrong previous-release branch for the diff → notes miss or double-count commits. Confirm origin/release/vX.(Y-1) is the actual prior release.
  • Skipping the review pause. The notes are public; show them first.
  • Forgetting the configs release branch (step 3b). The CI release build loads config from configs' release/vX.Y; without it the build fails.
  • Skipping the store notes, or writing them in markdown. They're pasted verbatim into three store listings; a missing or 500+ character file makes /promote-release fail at its first step.

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Delete the `-bak` backup branches that `/prepare-merge` leaves behind, local and on origin, once the work they back up has merged. Use when the user says "remove my bak branches", "clean up bak branches", "delete the backups", or "/clean-bak-branches".

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Actual-Chat/actual-chat572026년 10월 21일 업데이트

create-pr

무료

Use when work on a branch is finished and the next step is a pull request — "create a PR", "open a PR", "push and PR this", "/create-pr" — when a draft PR should be marked ready for review — "mark the PR ready", "undraft it", "it's ready for review" — or right after either has happened and the team has not been told about it yet.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Actual-Chat/actual-chat572026년 10월 21일 업데이트

Search Google Cloud (GKE) server logs of the DEV environment (dev.voxt.ai). Use when troubleshooting anything that needs the server side of the story — stream stalls, RPC peer changes / reconnects, watchdog closures, mesh/node churn, pod restarts — or when the user says "check GCP logs", "check server logs on dev", or gives a dev.voxt.ai timeline from a client console log.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Actual-Chat/actual-chat572026년 10월 21일 업데이트

Search Google Cloud (GKE) server logs of the PROD environment. Use when troubleshooting a production incident that needs the server side of the story — stream stalls, RPC peer changes / reconnects, watchdog closures, mesh/node churn, pod restarts — or when the user says "check PROD logs", "check production server logs", or gives a production timeline from a client console log.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Actual-Chat/actual-chat572026년 10월 21일 업데이트

memories

무료

What this project has already learned the hard way, and where any new such fact belongs. Two jobs. (1) Routing: this project keeps NO per-project Claude memories — read this before writing anything down, and pick a durable home from the list here. (2) An index, by area, of non-obvious facts worth knowing before you guess: debugging rigs and measurements that lie, iOS/WebKit and the tethered iPhone, the Windows app, production and deployment, and general codebase traps. Use before setting up a browser- or server-driven debugging session, when a bug reproduces only on iPhone, in Safari or in the Windows app, before changing deployment configuration or reading store/crash data, when something behaves unexpectedly and you are about to guess why, and whenever you are tempted to record a fact for later.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Actual-Chat/actual-chat572026년 10월 21일 업데이트

Review the EF Core migrations a release (or a PR) carries against how Voxt is deployed: a rolling update whose new pods wait for the migration Job, while old pods keep serving. Use before cutting a release branch, before merging a PR that adds a migration, or when the user says "check the migrations", "are the migrations safe to ship", "expand/contract check", "/migration-release-check". Reports risks; never blocks, edits or runs anything on prod.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Actual-Chat/actual-chat572026년 10월 21일 업데이트

Actual-Chat의 스킬 모두 보기

이 스킬의 문제 신고