Skip to content

v2.5.0

Choose a tag to compare

@n-shadloo n-shadloo released this 26 Aug 18:54
· 1 commit to main since this release
v2.5.0
3437596

v2.5.0

Minor release, and the largest change to the skill's scope since 2.0.0. It stops being a
commit-and-PR authoring skill and becomes a git skill: a seventh mode takes branches,
rebases, conflicts, undo, and recovery. Alongside it, mode 4 becomes safe to run unattended,
and the no-attribution default becomes something the skill checks rather than something it
states. MINOR rather than MAJOR because nothing that worked in 2.4.0 works differently —
every one of the six existing modes behaves exactly as it did, and the read-only guarantee
that covered modes 1–3, 5, and 6 now covers mode 7 too.

One narrowing is worth knowing about before you upgrade. See Upgrade notes.

Mode 7: the rest of git

The skill used to say branching, rebasing, and merge-conflict resolution were "a different
task."
For anyone whose only git skill this is, there is no different task — the exclusion
just handed those requests back to the agent's own priors, on exactly the operations that
lose commits. Mode 7 takes them: branches, merge against rebase, history editing, undo,
moving work, conflict resolution, and recovery.

It is read-only by default, like modes 1–3, 5, and 6. It reads the real state, tells you
what git is actually reporting, and gives you the commands. It executes only under the same
explicit autonomous request mode 4 needs.

Before anything that can lose work, it names the reflog entry or the branch that gets it
back
— before the command runs, not after it fails.

The hard limits are absolutes, and they are the counter-instinct ones rather than a
restatement of the manual:

  • Published history on a shared branch is never rewritten. Rebase, amend, squash, and
    reset apply to unpublished work, or to your own feature branch once you say it is yours
    alone.
  • Never force-push. Where you explicitly ask to update your own already-pushed branch
    after a rebase, it uses --force-with-lease and says what that protects: the lease refuses
    the push if the remote branch moved since your last fetch, so a commit someone else pushed
    there cannot be silently overwritten. A plain --force overwrites it and reports success.
  • Uncommitted work is never discarded without your confirmationreset --hard,
    checkout -- <path>, restore without --staged, clean, and stash drop.
  • A conflict is never resolved by picking a side to make the sequence continue. Both
    sides were written on purpose; it reads each one, decides from what the change was for, and
    tells you what it decided and why.
  • No rebase, merge, cherry-pick, or bisect is ever left half-finished without the exact
    state and the command that ends it.

The one piece of knowledge most worth having is that ours and theirs swap. In a merge
ours is the branch you are on. In a rebase your commits are replayed onto the base, so the
base is ours and your own work arrives as theirs. Assuming ours is your work is the
most common way conflict resolution goes quietly wrong, and the skill reads which operation
is in progress instead of assuming.

Two new reference files carry the depth: branching-and-history.md for everything except
conflicts, and conflicts.md for conflicts and rerere. They are separate on purpose — a
conflict is read mid-operation, and an agent stopped on a conflicted rebase needs one file it
can load on its own.

The no-attribution default is now checked, not asserted

The rule was already in 2.2.0 and agents kept breaking it. A rule stated once and ignored
is a defect in the skill, not in the agent.

The two lists are closed rather than sampled. The old wording said a trailer is never
inferred "from history, branch names, or the diff" — three examples, which left everything
unnamed reading as permitted. Now there are exactly two legitimate sources: your words in the
session, and the mode 6 squash transcription. Every forbidden one is named, because each of
them looks like permission: the agent's own identity, the model or tool name,
commit.template, a prepare-commit-msg or commit-msg hook, GIT_AUTHOR_* and
GIT_COMMITTER_*, CI variables, editor plugins, and the trailers on your existing commits.

A repository full of AI or Co-authored-by: lines grants nothing. Convention detection
matches subject shape, scope vocabulary, and tense — never trailers.

A template or hook that injects a trailer is a finding. The line is stripped and you are
told which file produced it, rather than it being kept silently.

The author identity is never set. No --author, no -c user.name, no -c user.email,
no writes to git config.

And it is verified after the fact. After every commit the agent makes itself, it reads
the whole message back from git log -1 --format=full; if an unrequested Co-authored-by:,
Signed-off-by:, generated-with line, or agent identity is present, it amends it out at once
and reads again to confirm. The same check runs across every commit a push would publish, and
a hit stops the push and names the commit and the line. A commit is not reported as done
until that check passes.

The opt-in is untouched: ask for a co-author, a sign-off, or agent credit in the session and
you get it.

Mode 4 is safe to run unattended

Its stops were real but scattered through prose, and nothing said what a stop must hand
back.
A stop that produces an unusable handoff is barely better than not stopping. Every
stop now carries the same five fields: the goal and the exact blocked step; what was
attempted, with the git output verbatim; the causes eliminated and how; the single decision
needed from you; and the state that remains, with whether it is safe to leave.

Five conditions stop it, each naming the git state that is its evidence: a rejected push,
an ambiguous remote or upstream, staged work that will not group into one commit, a tag or
release that already exists, and a hook that fails. The state left behind is never tidied up
to make the report look clean.

Completion is proved rather than asserted. A command that exits zero is not evidence a
commit landed as intended, so mode 4 now claims completion only from git log -1 --format=full and git status read after the push, and shows you that output.

A rejected push is a concurrency signal, not an ambiguity. It means another writer moved
the branch. The skill fetches, reads the divergence, and reports the exact commits on each
side — and never rebases or merges it for you, because either choice picks an outcome that is
yours to make. The same rule reaches the release path: a rejected git push origin <tag>
means someone already published that version, and git tag -f is now named alongside
--force so neither reads as permitted.

Work in the repository the agent did not create is treated as yours — inspected, never
swept into a commit, never rewritten.

The frontmatter parses again

Releases 2.1.0 through 2.4.0 shipped YAML a strict parser rejected. description and
compatibility were plain scalars containing ": ", which YAML reads as a nested mapping
key, so safe_load aborted on the second line and never reached the rest. Claude Code's
loader tolerated it, so nothing surfaced the error. Both are folded block scalars now, with
the text preserved byte for byte.

Two CI workflows run on every push and pull request so this class of break cannot ship again.
One parses the frontmatter and holds description under its 1024-character limit. The other
resolves every references/ link, catches orphaned reference files and unclosed code fences,
and holds SKILL.md under its context-budget ceiling.

Files updated

  • SKILL.md — version 2.5.0; a rewritten description covering the repository operations;
    mode 7 with its hard limits; the read-only guarantee restated as modes 1–3 and 5–7; the
    trailer-source and author-identity rules in the ground rules and their consequences in the
    trailer block; stop conditions with the five handoff fields; a proof-of-completion section
    carrying the post-commit and pre-push attribution checks; boundaries and freshness. To hold
    the byte ceiling, depth moved into the reference files that already owned it — the
    merge-commit message and the gh gathering block to pr-review.md, PR structure to
    pull-requests.md, release style to release-notes.md, the breaking-change example to
    conventional-commits.md.
  • references/branching-and-history.md — new. Branch naming and deletion, merge against
    rebase and the criterion that decides, updating against a moved base, interactive rebase
    and autosquash, splitting a commit, the three reset modes, cherry-pick, stash, worktrees,
    recovery through the reflog, and the inspection commands.
  • references/conflicts.md — new. Reading the markers, the ours/theirs inversion,
    resolving without a tool the repo does not have, proving the resolution before continuing,
    ending or aborting each sequence, and rerere.
  • references/conventional-commits.md — the attribution section names the forbidden trailer
    sources and the author-identity ban.
  • references/release-notes.md — the tag hard limits name git tag -f and classify a
    rejected tag push as another writer's publish.
  • AGENTS.md — mode 7, the attribution rules, and the mode 4 changes, written self-contained.
  • README.md — seven modes throughout; a mode 7 section; the attribution section documents
    the closed source lists and the two checks; layout tree updated.
  • GEMINI.md, .cursor/rules/git-authoring.mdc — mode 7, its hard limits, and the
    attribution rules; both still defer to AGENTS.md for detail.

Upgrade notes

Drop-in for 2.4.0. All six existing modes behave identically, and the no-attribution default
still governs every one of them.

One narrowing. A hook bypass is no longer available, on request or otherwise. It
previously shared an exception with amend and rewrite — "unless the user explicitly requested
that separate action" — and --no-verify is the single command that turns a failing check
into a green run, so it is now absolute. A hook that fails is a finding that stops the work
and reports what the hook said. If you were relying on asking for a bypass, run that commit
yourself.

Two things to expect from mode 4. It stops in more places than it used to, visibly and
with a handoff; and it shows you git log -1 --format=full and git status output when it
reports success, rather than just saying it pushed.

Mode 7 needs git and nothing else. gh stays optional for modes 1–5 and required only
for mode 6.

Full Changelog: v2.4.0...v2.5.0