Skip to content
Development
Skill

/release

Prepare a declared release target, or preview it with --dry-run. Derive its version and require authorization before publication.

From plugin
codearbiter
15356 skills20 agents38 commands

Claude Code

$ npx -y skills add arbiterForge/codeArbiter --skill release --agent claude-code

SKILL.md

release.SKILL.md
name: release
description: Prepare a declared release target, or preview it with --dry-run. Derive its version and require authorization before publication.
argument-hint: "[target] | --dry-run"

release

The single permitted path to a version tag. Routed to when the user invokes `/release [target]`. Derive the bump from the commit log, update the changelog, tag — nothing more.

**One command, any number of declared targets.** A project declares one or more release targets in `$PROJECT_ROOT/.codearbiter/release-targets.md` (grammar and parser contract: `{{PLUGIN_ROOT}}/hooks/_releaselib.py`'s module docstring). `/release` takes the target's name as its only argument. When `$TARGET` is omitted and the declared file names exactly one target, that target is used — a single-target project's bare `/release` behaves exactly as it always has. When more than one target is declared, `$TARGET` is required; STOP and ask rather than guessing which one a bare invocation meant. **Resolve the omitted-single-target case mechanically, never by assumption** (MEDIUM, adversarial review 2026-07-31: `tag-prefix` itself takes `$TARGET` as a REQUIRED positional argument and has no way to express "the implicit one", so naming it here was not itself enough — the mechanical step that turns an omitted target into a concrete name before `tag-prefix` is ever called has to be spelled out too): run `"$PY" "{{PLUGIN_ROOT}}/hooks/_releaselib.py" list-targets` first — the sanctioned enumeration, through the same tested grammar `tag-prefix` already reads, rather than a by-eye scan of the delimiter block. Exactly one printed line confirms which name `$TARGET` is; more than one is the multi-target STOP above, restated by the tool rather than assumed. There is deliberately no second command per target: N commands would be N public surfaces to govern, catalog, and carry, for one operation whose only difference is which declared row it reads.

Every phase below is written once, against that row. Nothing in this skill is per-target prose.

**Execution-shell contract.** Every fenced `sh` command and every inline shell fragment in this workflow runs inside one POSIX-compatible shell session. On Windows, resolve and enter Git for Windows' own `bash.exe` before the interpreter step below; MUST NOT paste the `sh` snippets into PowerShell and treat PowerShell's exit status as their verdict. A native PowerShell session may be used only to locate and launch Git Bash, for example by resolving `git.exe`, taking its installation root, and invoking `bash.exe --noprofile --norc` from that installation's `bin` directory. Reject WSL aliases and WindowsApps stubs because they execute in a different filesystem. If no POSIX-compatible shell is available, STOP; do not translate the workflow ad hoc into a second command language.

**Interpreter convention, stated once and applying to every helper invocation in this file** (A-3.6). `python3` is not universally present — a Windows consumer commonly has `python` on PATH and no `python3` at all, and a literal `python3` spelling fails on every invocation at once there.

**Resolve the interpreter ONCE, by presence, before the first invocation:**

PY=python3; { command -v python3 >/dev/null 2>&1 && python3 --version >/dev/null 2>&1; } || PY=python
PYTHONDONTWRITEBYTECODE=1; export PYTHONDONTWRITEBYTECODE
PYTHONUTF8=1; PYTHONIOENCODING=utf-8; export PYTHONUTF8 PYTHONIOENCODING
{{IF:claude}}PROJECT_ROOT=${CLAUDE_PROJECT_DIR:-$(pwd)}{{ELSE}}PROJECT_ROOT=$(pwd){{END}}
cd "$PROJECT_ROOT" || { printf 'STOP — cannot enter the resolved project root.\n' >&2; exit 1; }

**`command -v` alone is not enough** (LOW, #584): a Windows host commonly ships a `python3` *App Execution Alias* stub at `%LOCALAPPDATA%\Microsoft\WindowsApps\python3` that satisfies `command -v python3` with no Python actually installed — running it opens the Microsoft Store and exits non-zero. Only actually RUNNING it (`python3 --version`) tells the truth; `command -v` merely tells you a name resolves on `PATH`. `python3` wins whenever both it and `python` are genuinely present — the resolve-once order above tries it first and only falls back to `python` when it is absent or the stub — so a host with both interpreters gets the one this convention exists to prefer, not an arbitrary pick.

Set `PYTHONDONTWRITEBYTECODE` and resolve then enter `$PROJECT_ROOT` before the first invocation as shown. The host-conditional root uses Claude's harness pointer when available and the session cwd on Codex/Pi. It applies to every helper below and prevents a read-only or dry-run inspection from creating `__pycache__` beside a vendored helper. Every helper invocation below is then spelled `"$PY" "{{PLUGIN_ROOT}}/hooks/<script>" <args>` literally, one spelling throughout — including the inline `"$PY" -c "…"` snippets. Two spellings for one thing invites reading the difference as meaningful (blind exercise run 14 flagged exactly that when only three steps used `"$PY"` and fifteen still said `python3`).

**Both quotes are load-bearing, and the second one is the easier to lose** (HIGH-1, blind exercise run 16). Quoting only the interpreter — `"$PY" {{PLUGIN_ROOT}}/hooks/<script>` — leaves the script path exposed to word splitting, and a plugin root containing a space is an ordinary Windows install (`C:\Users\First Last\.claude\plugins\…`, since an account name with a space is unremarkable). On such a host the path splits at the space, Python is handed a truncated filename, and EVERY step of this lane fails at once: target resolution, `last-tag`, `classify-window`, `check-manifests`, `classify`, `notes-match`. The operator's only diagnostic is `can't open file '…\First'`, which names nothing recognisable. The same applies to any `$PROJECT_ROOT`-rooted path passed as an argument. Payload pathspecs are not an exception: load their line-delimited records into positional parameters and expand `"$@"` as specified under Targets.

**MUST NOT spell them `p

Read more
@arbiterforge
Ships withcodearbiter

Open-source governance and hard gates for AI coding agents across Claude Code, Codex CLI, and Pi.

15356 skills20 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
153
Star history of arbiterForge/codeArbiter on GitHub, a chart by star-history.com

Other skills on codearbiter.

brainstorming

brainstorming

Refine feature and sprint intent into a useful specification. Capture scope, observable criteria and material choices without…

commit-gate

commit-gate

Create a verified local Git commit when committing changes is requested. Not for explaining commit history, drafting a message…

debug

debug

Investigate an unexplained defect or unexpected behavior without changing application code. Use for root-cause diagnosis and an…

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills2w309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc2w293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react5d252k
@facebook@facebookInstall Skill

Questions about release.

Which coding agents can use release?
release installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.