git-publish
Skill11 starsChanged 7 days agoApache-2.0View on GitHub
Offers to git init/commit the current project and, optionally, create a GitHub repo (via `gh`) and push — always behind two explicit confirmations, one for the local commit and one for the remote create+push. Use right after a project was just generated by `/init-project`, or whenever the user types `/git-publish` — the line `/new-feature` and `/new-feature-implement` print at the end of a run — or asks to create a git repo, commit, or push the current project. The two feature flows never invoke it.
- Reads credentials
- Deletes or force-pushes
- Commits and pushes
1 other project uses a version of this.
Adopted by
Most recently taken up by
- nerviz-ai/nervizword for word, first seen Nov 7, 2026
Other versions1 project uses a version of this.
Word for word · 1
- nerviz-ai/nerviz★ 11100% same
Edited · 0
None found.
Wrote their own version · 0
None found.
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository35 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- ai-architectSkill
- arch-adoptSkill
- arch-doctorSkill
- audit-usageSkill
- cache-architectSkill
- claude-code-architect-designerSkill
- docker-architectSkill
- domain-modelingSkill
- gof-design-patternsSkill
- graphql-api-architectSkill
- harness-lessonsSkill
- http-client-architectSkill
- init-projectSkill
- jobs-architectSkill
- messaging-architectSkill
- nerviz-diagramsSkill
- new-feature-implementSkill
- new-featureSkill
- new-projectSkill
- persistence-architectSkill
- platform-upgradeSkill
- project-bootstrapSkill
- project-configSkill
- report-issueSkill
- rest-api-architectSkill
- search-architectSkill
- security-architectSkill
- sonar-lessonsSkill
- sonarqube-setupSkill
- spikeSkill
- test-architectSkill
- transport-security-setupSkill
- triage-issueSkill
- use-case-designSkill
The file
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 2 are distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Very specific: line 59
Input (optional): paths to stage: When the invoking context or the typed argument names paths — /new-feature prints them for an approved …
- Very specific: line 70
Input (optional): project directory: When the invoking context names project: <absolute path> — project-initializer does, because it runs …
- Distinctive: line 81
Never writes project source files.
- Distinctive: line 109
Before gate 1's question, show the diff-file list and ask explicitly whether it actually matches the feature just built.
- Very specific: line 189
Only reached after gate 1 commits successfully, or when TRACKED+clean with unpushed commits/no remote.
- Very specific: line 205
Never git push --force, never --no-verify, never delete an existing remote without the user naming that as the explicit choice.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
git-publish — offer to commit and push, with confirmation
Why this is a skill (Form 1) and not Form 2
One piece chains into this one by name: project-initializer (after /init-project
finishes). /new-feature and /new-feature-implement used to as well, and print the typed
command instead since @.claude/decisions/0182-git-publish-printed-not-chained-by-the-feature-flows.md:
the chained call ran at the 250–370k context of the flow and committed before the run's audit
trail existed. disable-model-invocation: true (Form 2) blocks exactly that — the model can't call a
Form 2 skill via the Skill tool at all, only a human typing /git-publish can, the same restriction java-spring-boot-developer.md documents for why it can't
re-invoke gof-design-patterns. Precedent: @.claude/decisions/0007-pipeline-skills-invocation.md
(D17) — the five /new-feature pipeline skills stay without disable-model-invocation
for the same reason, and rely on an entry guard in the body instead of the flag. This
file's guard is the two AskUserQuestion gates below: no git side effect ever runs
without an explicit yes, regardless of what triggered the invocation.
Form 3 (agent) was rejected: the confirmation dialogue with the user is the heart of
this task, the context it needs fits entirely in this file, and the final output is
short — all three fail the counter-test in references/decision-matrix.md § 5.
Decision record: @.claude/decisions/0034-git-publish-skill.md.
Runs on sonnet with effort: low: a fixed procedure whose every side effect waits
behind the two gates (@.claude/decisions/0080-procedural-skills-on-sonnet.md).
Contract
Class: ops — the territory is skill_classes.ops in
@.claude/schemas/extensions.json, and it is empty: this skill writes no file. Its whole
effect is git over Bash, which the guard deliberately does not cover — a commit is not a
file write, and the two confirmations below are what gate it. allowed-tools pre-approves
only the local git subcommands and gh auth status; the remote step is left to
permissions.ask (decision 0076).
Input (optional, from the invoking context or the typed argument): a short description of
what was just done — e.g. "initial scaffold, blueprint hexagonal, maven, features: rest,jpa"
or "UC-001-order: order management feature". Used to build the commit message. No input →
generic message from what git status shows.
The typed argument. /new-feature and /new-feature-implement end by printing
/git-publish <message>[ — paths: <p…>][ — pre-existing: <p…>]. The message is everything
before the first literal — paths: or — pre-existing:; each marker, when present, opens
one of the two inputs below. Paths are space-separated.
Input (optional): paths to stage. When the invoking context or the typed argument names
paths — /new-feature prints them for an approved spec not implemented yet
(docs/use-cases/UC-NNN-<slug>/, docs/use-cases/BACKLOG.md) — gate 1 lists and stages
only those paths. Anything else dirty in the tree stays unstaged and is named in the report.
Input (optional): pre-existing changes. — pre-existing: <paths> is the list the feature
flow's guardrail took at the start of its run (IGNORED counts as an entry). It is the
PRE_EXISTING_WORK list of step 1, handed over instead of rediscovered: a /git-publish
typed after /clear has none of that run's context, so what the guardrail saw is what the
line carries. Without the marker, step 1 discovers it from git status --porcelain as before.
Input (optional): project directory. When the invoking context names
project: <absolute path> — project-initializer does, because it runs in a session opened
somewhere else — that directory is the project. Run every command of this procedure as
(cd "<path>" && git …), gh repo create included, so --source=. is the project and
git init never lands in the session's own repository. Without it, the project is the
session's directory.
Reads: git status, git remote -v, gh auth status. Nothing in the project files.
Writes: .git/ of the current project, and — only after the second confirmation —
a new GitHub repository via gh repo create, or a push to a remote the user names.
Never writes project source files.
Integration:
- Invoked by
project-initializer(agent) right after a green build, via theSkilltool, with a scaffold summary as context. - Typed by the user at the end of each of the two feature flows, after
/clear, from the line the flow printed: after/new-featureapproves a spec, with the approved spec's paths as the only paths to stage; after/new-feature-implementsucceeds, with the UC name/summary as the message. Neither flow invokes it. - Invocable directly by the user (
/git-publish, or by asking in plain language).
Procedure
1 · Read state, never assume it
git rev-parse --is-inside-work-tree 2>/dev/null && echo TRACKED || echo UNTRACKED
git status --porcelain 2>/dev/null
git diff --cached --stat 2>/dev/null
git remote -v 2>/dev/null
git log -1 --oneline 2>/dev/null
git check-ignore -q . && echo ROOT_IGNORED_BY_PARENTROOT_IGNORED_BY_PARENT — this project's own root is gitignored by an outer repo
(e.g. a demo under this meta-repo's own examples/). git status --porcelain reflects
the outer repo's tracked files, which have no relation to the feature this run just
implemented — src/, docs/use-cases/, all of it invisible to that status.
Before gate 1's question, show the diff-file list and ask explicitly whether it actually
matches the feature just built; don't let the caller's commit-message context imply it
does. If the caller (the feature guardrail's worktree step, in /new-feature or
/new-feature-implement, through the — pre-existing: IGNORED of the typed line) already flagged this, skip re-discovering it — just carry the
warning into gate 1's question.
Four states, four different phrasings for gate 1:
| State | Gate 1 asks |
UNTRACKED (no .git) | "Initialize git and create the first commit?" |
TRACKED, dirty (git status --porcelain non-empty) | "Commit these changes now?" |
TRACKED, clean | Skip gate 1 — nothing to commit. Go straight to gate 2 only if there are unpushed commits or no remote configured; otherwise report "nothing to do" and stop |
TRACKED, and git status --porcelain shows paths outside the ones the caller named | "Commit only this run's paths, or everything that is dirty?" — two options, and the question comes before gate 1's own |
PRE_EXISTING_WORK — the fourth state. Changes that belong to no caller of this skill:
someone else's cleanup, a deletion made by hand, a half-finished edit, an untracked file from a
previous run. Read from git status --porcelain, not from the index alone — an unstaged
edit and an untracked file are invisible to git diff --cached and git add -A commits them
anyway (lessons-learned-014 § 11).
.claude/audit-usage/** never counts toward this state: step 2.3 stages it with every
run, and the previous run's report lands after that run's commit by construction
(lessons-learned-016 § 8). A worktree whose only extra paths are under it is the plain
dirty state, not this one.
Deciding it silently is what went wrong in lessons-learned-012 § 7 — 1.503 staged
deletions rode along with a feature commit, and only a manual read of the list caught it.
Show the paths, say which of them the caller named, and ask with those two options. On
"only this run's paths", stage with git add -- <paths> and never git add -A; the rest
stays dirty and is reported as left behind, not reverted. On "everything that is dirty",
two commits, one gate, one push: first the run's paths plus .claude/audit-usage/ with
the run's message (step 2.4), then the rest with git add -A and
chore: commit changes from before this run, whose body lists every path it carries. One
commit for both gives the run's type to content the run did not write — a
docs(UC-…): approved spec once shipped a build-plugin change and a new compose service
(lessons-learned-016 § 9). The secret scan of step 2.2 covers both sets before either is
staged. The feature guardrail's worktree step
(.claude/skills/new-feature/references/entry-guardrail.md § 2) already flags this at the
start of the run and prints the list itself in the — pre-existing: part of the typed
line — when it did, use that list instead of rediscovering it, and diff it against what is dirty
now: what the guardrail saw is what the run did not produce.
2 · Gate 1 — local commit
AskUserQuestion, options: Yes, commit now / No, skip. "No" stops here — report
what would have been committed and don't touch anything.
On "Yes":
git initonly ifUNTRACKED.- Show
git statusand scan the file list for anything that looks like a secret before staging —.env,*.pem,*.key,credentials*,*secret*. If any match, stop and ask the user to confirm or exclude them; never stage a likely secret silently. git add -A(respecting.gitignore, already generated by the Initializr) — or, when the input named paths,git add -- <paths>with only the paths that exist, and nothing else..claude/audit-usage/is one of those paths, always, whether or not the caller named it: the trail of the run belongs to the commit of the run that produced it. Only.state/is ignored, and.gitignorealready handles that. Staging it in one run and leaving it out of the next is what makes every later diff start dirty (lessons-learned-012 § 15). This skill leaves no report of its own — its class,ops, declaresaudited: falseinskill_classesof.claude/schemas/extensions.json— because that report could only be written after this commit, and every publish would end dirty.git commit -m "<message>"— build the message from the input context following Conventional Commits:chore: initial project scaffold — <blueprint/build/features>for a project-initializer call,feat(UC-NNN-slug): <summary>for a/new-feature-implementcall,docs(UC-NNN-slug): approved specfor a/new-featureone, or a genericchore: commit pending changeswith no context.Attribution: append exactly the trailer the session provides, and nothing else. The running session states its own attribution lines; use them verbatim. When it states none, the commit carries none — no
Co-Authored-Byat all.Never write a model name from memory. Same discipline
@CLAUDE.mdinvariant 8 applies to Java and Spring Boot versions, and for a sharper reason here: this file is copied into every generated project, so a literal pinned in it goes stale in every one of them, silently and forever. A run under one model committed with another model's name because this step spelled one out, and the audit trail then recorded two models on one feature (lessons-learned-014 § 10). A wrong attribution is worse than an absent one — it is in the git history for good.
3 · Gate 2 — remote create/push
Only reached after gate 1 commits successfully, or when TRACKED+clean with unpushed
commits/no remote. AskUserQuestion, options:
- Create a new GitHub repo (gh) and push — needs
gh. Rungh auth statusfirst; not authenticated → report the exact command to fix it (gh auth login) and stop, never attempt to log in on the user's behalf. Ask visibility (public/private) as part of the same question. Then:gh repo create <artifactId> --<public|private> --source=. --remote=origin --push - Push to an existing remote — ask for the URL if
git remote -vshowed none;git remote add origin <url>(orset-urliforiginexists and the user confirms overwriting it), thengit push -u origin <current-branch>. - Skip, keep local only — stop, report the local commit is done and nothing was pushed.
Never git push --force, never --no-verify, never delete an existing remote without
the user naming that as the explicit choice.
The push itself raises a permission prompt after the gate's yes — git push and
gh repo create are in permissions.ask and deliberately absent from this skill's
allowed-tools, and ask is evaluated before any allow. That is the intended second look
at the one irreversible step, not a misconfiguration. A force push is refused outright by
guard bash (guard.force_push in @.claude/schemas/extensions.json), in every spelling
it can read.
4 · Report
✅ Committed <short-hash> — "<message>"
<✅ Committed <short-hash> — "chore: commit changes from before this run" (<n> paths) — only on "everything that is dirty">
<✅ Pushed to <remote-url> (branch <name>) | ⏭️ Local only, not pushed>Failure modes
gh missing or not authenticated:
❌ gh not authenticated. Run `gh auth login`, then re-invoke this skill to push.
Local commit is already done — nothing lost.Suspicious file staged:
⚠️ .env matched the secret-file scan. Excluded from `git add`.
Add it to .gitignore, or confirm explicitly if it must be committed.Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

