/arc:commit
Commit, push, publish
—What it does
Commit looks at your staged changes and groups them logically—feature code in one commit, tests in another, config changes in a third. Each gets a clear message following conventional commit format (feat:, fix:, refactor:, etc.). When asked to push, it pushes the branch and then publishes any changed npm package whose package metadata says it is publishable and whose version is not already on the registry.
—Why it exists
Messy commits make git history useless. You can't bisect to find a bug if every commit touches 15 unrelated files. You can't revert a broken feature if it's tangled with a refactor. Developers know this but batch changes anyway because splitting is tedious. Commit does the tedious part—you get clean history without the effort.
—Design decisions
- —Auto-detects domains. Feature code, tests, docs, config—grouped by what changed.
- —Conventional commit format. Enables automated changelogs and clear history.
- —Each commit is atomic. Independently revertable, cherry-pickable, bisectable.
- —Publishing happens only after a successful push.
- —Private packages and already-published versions are skipped.
Source document
<arc_runtime>
Requires the full Arc bundle. Arc-owned paths (agents/, references/, disciplines/, templates/, scripts/, rules/, skills/) resolve from the plugin root — the directory containing agents/ and skills/. Everything else is the user's repository.
</arc_runtime>
Commit Changes
Commit, push, and publish changes, intelligently splitting into separate commits when changes span multiple domains.
Usage:
/arc:commit- Auto-analyze and commit (may create multiple commits)/arc:commit push- Commit, push, then publish changed npm packages if present/arc:commit publish- Alias for the push-and-publish path
On the push/publish path, /arc:commit publishes a package whose version is already committed and not yet on the registry. /arc:release owns bumping versions, changelogs, and coordinated multi-package releases. Route version bumps there instead of doing them here.
The canonical order across both skills is commit → push → publish → tag.
Read the user's invocation: no argument means commit only; "push" or "publish" both mean the push-and-publish path.
Inspect Current Git State
Run these commands first and read the output before deciding on a commit strategy:
git status --porcelain 2>/dev/null || echo "(no changes)"
git diff --stat 2>/dev/null | head -20 || echo "(no diff)"
git log --oneline -5 2>/dev/null || echo "(no commits)" # style reference
git status --porcelain is the authoritative file list (the stat is a preview, and it truncates); read the contents of untracked files before judging them stray.
If there are no changes, tell the user and stop.
Instructions
If no user response is available at any decision point, take the conservative path — exclude rather than commit, stop rather than push or publish — and report what needs a human.
1. Analyze Changes
Review the git state above. If you need more detail on what changed, inspect the working tree — e.g. git diff for unstaged changes, git diff --staged for staged changes, or git diff <path> to focus on a file. Apply references/diff-review-checklist.md as you read the diff so substantive defects (race conditions, trust-boundary gaps, data-safety and side-effect mistakes, stale references, test gaps, dead code, performance regressions) are caught before they land in a commit. Alongside it, scan the diff yourself for debug logs, secrets or credentials, and stray files that should not be committed. A hit blocks those lines from landing: exclude the file (or the hunk, via git add -p) from every commit, leave the working-tree content untouched, and report each hit. Never delete user work to make a commit clean. Never commit a suspected secret; if one may already be in history, say so — committed secrets need rotation, not just removal.
2. Determine Commit Strategy
Single commit if:
- All changes are in the same domain/area, OR
- Changes are tightly coupled (e.g., feature + its tests)
Multiple commits if changes span multiple unrelated domains:
- Different packages (e.g.,
packages/ui,packages/api) - Different apps (e.g.,
apps/web,apps/admin) - Config vs source changes
- Unrelated features or fixes
3. Group Files by Domain
Common groupings:
packages/<name>/**- Package-specific changesapps/<name>/**- App-specific changesapp/**- Route or feature changes, grouped by route/featurecomponents/**- Shared UI changeslib/**/utils/**- Shared logic and helpers- Root config files (
.eslintrc,turbo.json, etc.) - Config *.stories.tsxwith their component - Same commit as component*.test.tswith their source - Same commit as source
In a flat repo, group by top-level directory unless changes are coupled across them.
4. Create Commits
For each logical group:
-
Stage only files for that group, including untracked files that belong to the group:
git add [files...] -
Create commit with conventional message format:
git commit -m "$(cat <<'EOF' type(scope): description EOF )"
Commit types:
feat- New featurefix- Bug fixrefactor- Code refactoringchore- Maintenance, deps, configdocs- Documentationtest- Testsstyle- Formatting, no code changeperf- Performance improvementci- CI/CD changes
Commit message rules:
- Use imperative mood: "add" not "added", "fix" not "fixed"
- First line under 72 characters
- Each commit should be atomic (single purpose)
- If you need "and" in the message, consider splitting the commit
After each commit, re-read HEAD before reporting hashes — a hook may have amended the commit.
Repo version mechanics: if the repo ships a version-bump script (often paired with a manifest such as .version-bump.json), use that script rather than editing version fields directly.
5. Handle Pre-commit Hook Failures
If TypeScript or lint errors block the commit:
Fix the root cause. A hook failure is information about the code, so anything that silences it
rather than resolving it — --no-verify on work you are landing (the one exception — a local WIP
commit you will amend before pushing — is rules/git.md's, and never applies to this skill's
output), as unknown as/as any, @ts-ignore, @ts-expect-error, eslint-disable comments,
empty catch blocks — leaves the defect in place and the commit dishonest.
If the root cause genuinely can't be fixed here, stop and say so rather than suppressing it.
Fixing Process:
- Read the error output carefully
- Identify the exact files and line numbers with issues
- For TypeScript errors:
- Read the file and understand the type error
- Fix the types properly by adding correct type annotations
- If a type is unclear, use
unknownand narrow it with type guards - Update interfaces/types as needed
- For lint errors:
- Read the file and understand the lint rule violation
- Fix the code to comply with the rule properly
- Refactor if needed to follow best practices
- Stage the fixes with the relevant commit
- Retry the commit
- Repeat until all errors are resolved
6. Push Changes (only if push or publish argument provided)
Skip this step unless the user asked to "push" or "publish".
If pushing:
git push
If the branch has no upstream:
git push -u origin $(git branch --show-current)
If push fails (e.g., diverged history), report the issue - do NOT force push unless explicitly authorized.
7. Publish npm Packages (only if push or publish argument provided)
Skip this step unless the user asked to "push" or "publish".
Publish only after commits and push have succeeded — the canonical order is commit → push → publish → tag.
Detect the repo's package manager (pnpm, npm, yarn, bun) from its lockfile or packageManager field first, and refer to it as <pm> in the commands below.
Detect candidate packages:
- Look for changed
package.jsonfiles and changed files under directories containing apackage.json. - Ignore generated directories such as
node_modules,dist,build,.next,.turbo, and coverage output. - A package is publishable only if
package.jsonhas aname, aversion, and does not have"private": true. - Prefer packages with a
publishConfig,files,bin,exports, or an explicit package-levelprepublishOnly/prepare/buildscript. If package intent is unclear, ask before publishing.
Pre-publish checks for each candidate:
-
Read the package's
package.json. -
Confirm the package has an npm package name and version.
-
Check whether that exact version is already published:
npm view <package-name>@<version> version- If the version exists, skip publishing and report it.
- If npm returns 404/not found, continue.
- If npm auth/network fails, stop and report the blocker.
-
Run package-local verification when scripts exist, using
<pm>consistently:<pm> testif atestscript exists<pm> buildif abuildscript exists<pm> typecheckif atypecheckscript exists
-
Publish from the package directory:
npm publishUse
npm publish --access publicfor scoped public packages whenpublishConfig.accessispublicor the existing package is public. Publishing itself usesnpm publishregardless of the install-time package manager; only the verification scripts above run through<pm>.
Publishing rules:
- NEVER publish a private package.
- NEVER publish before pushing the commit containing the package version.
- NEVER bump a package version unless the user explicitly asked for a version bump.
- NEVER publish if the working tree has uncommitted files that belong to that package. When the uncommitted files are step 1's own exclusions (a quarantined secret or debug line), say that explicitly — the block is the scan working, not an oversight.
- NEVER use
--forceor delete registry versions. - If multiple changed packages exist, publish each confirmed publishable package once.
8. Report Results
Tell the user:
- How many commits were created
- Summary of each commit (hash, message)
- Push status (if pushed), or remind them to push when ready
- Publish status for each package (if publish was requested): published, skipped, or blocked
Failure Scenarios
If you cannot fix an error properly:
- Explain why the error exists
- Describe what the proper fix would require (e.g., architectural changes, missing types, etc.)
- Ask for guidance
- Do NOT commit with workarounds