Arness Ship
Guides through branching, staging, committing, pushing, and optionally opening a pull request. Works standalone or as the final step in the Arness pipeline.
Pipeline position:
arn-code-review-implementation -> arn-code-document-project -> **arn-code-ship**
This skill handles the entire shipping workflow: verifying git state, ensuring the user is on the right branch, staging changes safely, generating meaningful commit messages, pushing, and creating a pull request via the GitHub CLI or Bitbucket CLI.
Workflow
Step 1: Check Git State
Check ## Arness config in CLAUDE.md for Git: yes. If not present, run runtime check: git rev-parse --is-inside-work-tree.
If Git is not available, inform the user: "This project is not a git repository. /arn-code-ship requires Git." and exit.
Read the Platform field from ## Arness config in CLAUDE.md (values: github, bitbucket, or none). Store this value for use in Step 5. If the Platform field is not present, fall back to legacy detection: check for GitHub: yes and treat as github; otherwise treat as none.
Gather current state:
- Current branch:
git branch --show-current - Uncommitted changes:
git status --short(never use-uall) - Commits ahead of main:
git log main..HEAD --oneline(skip if on main) - Remote tracking:
git rev-parse --abbrev-ref @{upstream}(may fail if no upstream)
If no uncommitted changes AND no commits ahead of remote, inform the user: "Nothing to ship — working tree is clean and up to date with remote." and exit.
Step 2: Branch Decision
If on main/master:
- Warn the user: "You're on the main branch. It's recommended to create a feature branch before shipping."
- Offer to create a new branch:
- If Arness context is available (current spec or plan), suggest a name derived from it (e.g.,
feat/websocket-support,fix/checkout-500-error) - Otherwise ask the user for a branch name
- Create with
git checkout -b <branch-name>
- If Arness context is available (current spec or plan), suggest a name derived from it (e.g.,
- Let the user continue on main if they prefer
If on a feature branch:
- Confirm: "You're on branch
<branch-name>. Proceeding."
Step 3: Stage and Commit
- Show current changes: run
git status --shortandgit diff --stat - Check for sensitive files in the diff — warn if any match common patterns:
.env,.env.*- Files containing
credential,secret,token,password,keyin their name id_rsa,*.pem,*.key
- Lint and Format Gate. Read the
Linting:field from CLAUDE.md## Arnessblock:- If
Linting: noneorLinting: skip(or the field is missing) — skip this sub-step silently and proceed to staging. - If
Linting: enabled:-
Read
<code-patterns-dir>/linting.md(the per-service detection produced byarn-code-codebase-analyzer, covering both linters and formatters). -
Compute the staged diff scope:
git diff --name-only HEAD(or against the base branch if uncommitted changes are not yet staged — fall back gracefully). -
For each section in
linting.mdwhoseScope hintintersects the diff, invoke the section'sDiscovered check commandagainst the changed files within that scope. The discovered command MUST be a check-only invocation per the analyzer contract — never run a mutation/write command as the gate. When the underlying tool supports per-file invocation, narrow accordingly; otherwise run as-is. -
Aggregate results across all invocations: total issue count
N, broken down bykind(lint vs format) and severity (error/warning/info), and per service. -
If
N == 0: print a one-line confirmation ("Lint and format clean: 0 issues across <services>.") and proceed to staging. -
If
N > 0: show the breakdown (per-service counts, lint vs format totals, severity totals). Determine the suggested default:N <= 20→ suggest Fix nowN > 20→ suggest File a backlog issue Then ask (usingAskUserQuestion):
Found N issues across <comma-separated services> (<L> lint, <F> format). Suggested: <Fix now | File a backlog issue>. How would you like to proceed?
- Fix now — pause shipping, address the issues, then return
- File a backlog issue and proceed — record the issues for later, proceed with commit
- Proceed with documented reason — annotate the commit message with rationale, proceed without filing a backlog issue
Apply the choice:
- (1) Fix now — exit
arn-code-ship. Tell the user: "Run your linter or formatter, fix the issues, then re-run/arn-code-shipwhen ready." Do not commit. (Note: format violations are usually auto-fixable via the project's write-mode formatter command, but this skill never invokes mutation commands itself.) - (2) File a backlog issue and proceed — read the
Issue trackerfield from## Arness. Forgithub:gh issue create --title "Lint/format backlog: N issues from <branch>" --body "<output summary including lint vs format breakdown>". Forjira: use the Atlassian MCP server to create the issue with the same title and body. Fornone: warn the user that no issue tracker is configured and fall back to choice (3). Then proceed to staging. - (3) Proceed with documented reason — prompt the user for a one-line rationale. Append "Lint/format exception: <rationale>" to the commit message body (this happens later in sub-step 6). Proceed to staging.
-
- If a tool command fails to execute (binary not found, config invalid, or appears to be a mutation command): warn the user with the specific error and fall through to the standard 3-option menu treating the failure as a single issue (
N=1, suggested default: Fix now). Do not silently skip the gate on a tool failure.
- If
- Offer staging options via
AskUserQuestion:- Stage all changes —
git add -A - Choose files to stage — show the list, let user select
- Already staged — user has manually staged files, proceed with what's staged
- Stage all changes —
- Scan for CHANGE_RECORD.json:
- Read
## Arnessconfig from CLAUDE.md to get the plans directory - Scan for
CHANGE_RECORD.jsonin plans subdirectories:SWIFT_*/CHANGE_RECORD.json,STANDARD_*/CHANGE_RECORD.json,CATCHUP_*/CHANGE_RECORD.json, and*/CHANGE_RECORD.json - If multiple found, use the most recently modified file
- If found, read the
ceremonyTierfield to determine the tier tag
- Read
- Generate a commit message:
- Detect the project's commit convention from
git log --oneline -10and follow it. Default to imperative mood (e.g., "Add feature X", not "Added feature X"). - If a CHANGE_RECORD.json was found, prepend the tier tag to the commit message:
[swift],[standard],[thorough], or[catchup](e.g.,[swift] Add rate limiting to /api/users) - If Arness context is available (project name, spec, plan), use it to generate a meaningful commit message summarizing the changes
- Otherwise, generate from
git diff --staged --statand file content - If sub-step 3 (Lint Gate) was resolved with Proceed with documented reason: append "Lint exception: <rationale>" to the commit message body before presenting it.
- Present the generated message to the user
- Let the user customize or approve
- Detect the project's commit convention from
- Commit using the approved message
Step 4: Push
- Check if the branch has a remote tracking branch:
git rev-parse --abbrev-ref @{upstream} - If tracking branch exists:
git push - If no tracking branch:
git push -u origin <branch-name> - Handle push rejection:
- If push is rejected (remote has new commits), suggest
git pull --rebasefirst - Never force-push without explicit user approval
- If push is rejected (remote has new commits), suggest
Step 5: Create Pull Request (optional)
Use the Platform value read in Step 1 to determine the PR creation path.
Deferred Label Check:
If Platform is github: check if Arness labels exist by running `gh label list --search "a