swain-release
Cut a release — detect versioning context, generate a changelog from conventional commits, bump versions, create a git tag, and optionally squash-merge to a release branch. Use when the user says "release", "cut a release", "tag a release", "bump the version", "create a changelog", "ship a version", "publish", or any variation of shipping/publishing a version. This skill is intentionally generic and works across any repo — it infers context from git history and project structure rather than assuming a specific setup. Supports the trunk+release branch model (ADR-013) when a `release` branch exists.
What this skill does
<!-- swain-model-hint: sonnet, effort: medium -->
# Release
<!-- session-check: SPEC-121 -->
Before proceeding with any state-changing operation, check for an active session:
```bash
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
bash "$REPO_ROOT/.agents/bin/swain-session-check.sh" 2>/dev/null
```
If the JSON output has `"status"` other than `"active"`, inform the operator: "No active session — start one with `/swain-init`?" Proceed if they dismiss.
Cut a release by detecting the project's versioning context, generating a changelog, bumping versions, and tagging. Works across any repo by reading context from git history and project structure rather than hardcoding assumptions.
## Override file
Before starting, read `.agents/release.override.skill.md` if it exists. This is a freeform markdown file authored by the project owner whose instructions layer on top of this skill — its contents take precedence where they conflict. It can narrow defaults, specify version file locations, set tag formats, add pre/post-release steps, or anything else.
If no override exists, proceed with context detection alone.
## Workflow
### 1. Gather context
Infer the project's release conventions from what already exists. Do all of these checks up front before proposing anything to the user.
**Tag history:**
```bash
git tag --sort=-v:refname | head -20
```
From existing tags, infer:
- **Tag format** — `v1.2.3`, `1.2.3`, `name-v1.2.3`, or something else
- **Versioning scheme** — semver, calver, or custom
- **Current version** — the most recent tag that matches the detected pattern
If there are no tags at all, note that this is the first release and ask the user what format they want.
**Commits since last release:**
```bash
git log <last-tag>..HEAD --oneline --no-decorate
```
If no tags exist, use all commits (or a reasonable window — ask the user if there are hundreds).
**Version files** — scan for files that commonly hold version numbers:
```bash
# Look for common version carriers
grep -rl 'version' --include='*.json' --include='*.toml' --include='*.yaml' --include='*.yml' -l . 2>/dev/null | head -20
```
Also check for `VERSION` files, `version:` in SKILL.md frontmatter, `version` fields in `package.json`, `pyproject.toml`, `Cargo.toml`, etc. Don't modify anything yet — just catalog what exists.
### 2. Determine the bump
Parse commits since the last tag using conventional-commit prefixes to suggest a bump level:
| Commit prefix | Suggests |
|---------------|----------|
| `feat` | minor bump |
| `fix` | patch bump |
| `docs`, `chore`, `refactor`, `test`, `ci` | patch bump |
| `BREAKING CHANGE` in body, or `!` after type | major bump |
The highest-level signal wins (any breaking change = major, any feat = at least minor, otherwise patch).
If commits don't follow conventional-commit format, fall back to listing them and asking the user what bump level feels right.
### 3. Propose the release
Present the user with a release plan before executing anything. Include:
- **Current version** (from latest tag, or "first release")
- **Proposed version** (with the detected bump applied)
- **Changelog preview** (thematic narrative — see step 4)
- **Files to update** (version files found in step 1, if any)
- **Tag to create** (using the detected format)
Wait for the user to confirm, adjust the version, or abort. If the user wants a different version than what was suggested, use theirs — the suggestion is a starting point, not a mandate.
### 4. Generate the changelog
**Synthesize, don't transcribe.** The changelog is for humans reading release notes, not for `git log --oneline` with extra steps. Dozens of commits should collapse into a few coherent narratives.
Before writing, read the existing CHANGELOG.md (if any) to match the voice, density, and structure the project already uses. The changelog should read like the same person wrote every entry.
#### Template-driven changelog
The changelog is rendered from a Jinja2 template (`templates/changelog.md.j2`) fed by a JSON data file. This separates the bucketing decision (which section does a change belong in?) from the rendering (how does the markdown look?).
**Step 4a — Classify commits into five buckets.** Each commit goes into exactly one:
| Bucket | What belongs here | What does NOT belong here |
|--------|-------------------|--------------------------|
| `features` | Shipped capability that the operator can interact with today: new skills, new CLI commands, new scripts the operator invokes, bug fixes to operator-facing workflows. The test: "can the operator do something new or different because of this?" The artifact must be in Complete (or the work is deployed with no tracking artifact). | Planning artifacts, internal quality improvements, threshold tweaks to internal tools, internal test suites, bug fixes to scripts the operator never invokes directly, partially-implemented work still in Active. |
| `in_progress` | Work that has shipped partially — code is in trunk, the operator can use some of it, but the tracking artifact is still Active (not yet Complete). Write as "X is now available in an early form because Y still needs Z." Be honest about gaps. | Fully shipped work (that's features). Purely planned work with no code in trunk (that's roadmap). |
| `roadmap` | Forward-looking previews of planned work — what's coming and why it matters to the user. Write as "X is being planned/designed because Y" not "SPEC-NNN created". Omit artifact IDs unless the reader would search for them. Skip items that are pure internal housekeeping. | Artifact state transitions ("EPIC activated", "SPEC created"), anything that shipped (that's features), anything with code in trunk (that's in_progress). |
| `research` | Trove collections, spike completions, research artifacts, evidence gathered. | Specs that resulted from research (those are roadmap or in_progress). |
| `supporting` | Internal quality improvements, internal test suites, threshold changes to internal tools, bug fixes to internal scripts, dependency bumps, cross-ref enrichment, minor refactors, CI changes. | Anything the operator interacts with directly (that's features). |
The key distinction agents get wrong: **creating a SPEC or EPIC is a roadmap change, not a feature.** A feature is something the operator can use *today* because it shipped in this release. A SPEC is a plan for something that will ship *later*.
The second distinction agents get wrong: **code in trunk with an Active artifact is in-progress, not a feature.** If the tracking spec's phase is Active, the work is partially available — use the `in_progress` bucket. Only move it to `features` when the artifact reaches Complete (or there is no artifact and the work is deployed and usable).
The third distinction agents get wrong: **internal improvements are supporting, not features.** Raising an internal threshold, fixing an anti-pattern in internal scripts, adding a test suite for swain's own code — these improve quality but don't give the operator a new capability. Ask: "would the operator notice this in their daily workflow?" If the answer is "only if something was broken before," it's supporting.
**Roadmap anti-pattern:** "EPIC-029 activated with 3 child SPECs (SPEC-118, SPEC-119, SPEC-120)" is noise — it describes artifact state transitions that only matter to the project maintainer. Instead write: "Trunk detection is being generalized so swain works on any branch name without configuration." The reader should understand *what's coming and why they'd care*, not which internal tracking artifacts changed state.
**Supporting anti-patterns — things that do NOT go in supporting:**
- Development process changes ("close handler reordered", "session-state tolerance added") — these are implementation details; omit them entirely.
- Artifact state transitions ("EPIC-053 approved and activated", "SPEC-220 created") — these describe planning activity, not shipped work; omit or put in roadmapRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.