My commit message
Agent Skill for my commit message guidelines
npx -y skills add nakat-t/skill-my-commit-message --skill my-commit-messageAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 12 days oldThe repository was created 12 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
A commit message convention based on Conventional Commits 1.0.0, narrowed down to only three types (feat/fix/chore). Always use this skill right before running git commit, when writing, deciding on, revising, or reviewing a commit message, when composing the text for `git commit -m`, when splitting a commit and rewriting each message, and when rewording messages via amend or rebase. Use it whenever "commit message", "conventional commits", "commit this", "write a message for me", or their Japanese equivalents ("コミットメッセージ", "コミットして", "commit しておいて", "メッセージを考えて") come up, even if the convention is not named explicitly. Covers how to pick a type (and how it maps to SemVer minor/patch/none), scope, how to express breaking changes, and what to write and what to leave out of the body. Do not use it to decide when to commit or how to split changes.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
17.5 KB, ~3.9k tokens by cl100k_base, as published. Nobody here has run it
Commit Message Convention
A convention for operating with a smaller set than Conventional Commits 1.0.0, while staying based on it.
This skill covers only "how to write the message." It does not cover when to commit or how to split changes. It assumes the content of the commit is already decided, and helps compose the text for it.
Overall Shape
<type>[optional scope][!]: <description>
[optional body]
[optional footer(s)]
The description (subject) is always required. "Summarize the change in one line" is a requirement of Conventional Commits, and it is separate from the body principle described later (no restating the summary).
Work top to bottom: decide the type → scope → whether ! is needed → subject → body → footer → self-check.
Step 1: Decide the Type
The Absolute Definition
The type expresses the SemVer impact itself. This always applies.
| type | SemVer | Meaning |
|---|---|---|
feat | minor | Backward-compatible feature addition. Users gain a new capability |
fix | patch | What reaches users changes, while compatibility is preserved |
chore | none | A change that does not need to move the version |
refactor: perf: docs: test: build: ci: style: revert: and the like are not used as types. They are "kinds" of change rather than types, and are expressed with the scope (Step 2).
Decision Flow
1. Does the change fall into any of the following?
- The contents of the release artifact (what is distributed to or executed by users) change
- It affects the process of building, packaging, or publishing the release artifact
- The contract of a public API that users rely on changes (including its documented description)
→ If no, it is chore. Stop here.
→ If yes, go to 2.
2. Did users gain a new observable capability?
→ If yes, feat; if no, fix.
3. Does it break compatibility for existing users? → If yes, add ! and a BREAKING CHANGE: footer (Step 3).
The baseline stance is: any change to something included in the release artifact, or to development resources that affect how it is built, is at least a patch. Even for refactoring or purely internal cleanup, if the bytes of the release artifact change, users can be affected, so use fix. "I did not intend to change behavior" is not a guarantee.
How to Determine What Counts as a Release Artifact
The scope of "release artifact" differs per repository. Do not guess; determine it mechanically from the packaging configuration.
- npm:
files/main/exports/bininpackage.json,.npmignore - Containers: the
COPYtargets inDockerfile,.dockerignore - Rust:
include/excludeinCargo.toml - Python:
packages/includeinpyproject.toml - Applications in general: entry points and output paths in the build configuration, deployment target paths
When the configuration does not settle it, ask: "If I reverted this change, would the behavior observed in the user's environment or the build output change?" If it would, it is fix or higher.
Cases That Are Easy to Get Wrong
| Case | type | Reason |
|---|---|---|
| Refactoring inside the release artifact | fix | The artifact changes. refactor is not a type |
| Performance improvement | fix | Same as above. perf is not a type |
Updating a runtime dependency (dependencies) | fix | It ends up in the user's environment |
Updating a dev dependency (devDependencies) | chore(deps) | It does not reach users |
| Lockfile (application) | fix(deps) | It determines what gets deployed |
| Lockfile (library) | chore(deps) | It is not used for the user's resolution |
Changing type definitions (.d.ts etc.) | fix / fix! if breaking | It can break the user's build |
| Adding or fixing tests only | chore(test) | Not included in the release artifact |
| Developer-facing helper scripts | chore | Same as above |
| CI changes that build or publish the release artifact | fix(ci) | It affects the build process |
| CI changes that only run lint or tests | chore(ci) | It does not affect the artifact |
| Fixing a typo in the README | chore(docs) | Not a public API contract |
| Correcting an error in the description of a public API | fix(docs) | A correction to a contract users rely on |
| Documenting a previously undocumented public API | feat(docs) | A contract users can rely on is added |
| An implementation behind a feature flag that is still off | fix | Users cannot observe it yet |
| The commit that turns the flag on | feat | The capability is added here |
By definition, feat involves the release artifact. If you are about to write a combination like feat(test) or feat(ci), the type decision is wrong (chore(test) / chore(ci) are correct). The only exception is feat(docs) in the table above.
Exception: Release Commits
A commit that only bumps the version number touches release artifacts such as package.json, but it uses chore(release).
chore(release): v1.4.0
Making it fix would create a cycle where a release triggers the next release, so it is explicitly carved out of the convention. If the version bump is mixed with other changes, this exception does not apply.
Step 2: Decide the Scope (optional)
Exactly one scope, lowercase. Multiple scopes such as chore(ci,build) are non-standard, so do not use them.
Since this convention removes docs ci test build from the types, the scope plays a double role: the kind of change and the area of the code. When both apply, use this priority:
- For
chore, prefer the kind:chore(ci)chore(test)chore(deps)chore(docs)chore(build)chore(release)- For
chore, the type carries no information beyond "it does not reach users," so the kind carries more information.
- For
- For
feat/fix, prefer the area:fix(auth)feat(parser)- For users, the affected area is the thing they most want to know.
- Put whichever one did not fit into the subject as natural prose. Example:
fix(auth): simplify the branching in token verification
Putting the kind in the scope for fix, as in fix(refactor) fix(perf) fix(deps), is also valid. It works especially well when you want to convey that "the release artifact changes, but the behavior users see does not." If the area information is not important, feel free to choose this.
Do not invent scope vocabulary. Extract it from the existing history and match it.
git log -10 --format=%s | grep -oE '^[a-z]+\([^)]+\)' | sort | uniq -c | sort -rn
If nothing in the existing vocabulary fits, omit the scope. Adding near-synonyms (creating authentication when auth already exists, etc.) degrades searchability of the history.
Step 3: ! and BREAKING CHANGE
In this convention, if you add !, you must write a BREAKING CHANGE: footer.
Conventional Commits 1.0.0 says the footer MAY be omitted when ! is present, but here it is deliberately made stricter. What is actually needed for a breaking change is not the fact that "something breaks" but what breaks and how to migrate, and that cannot be reconstructed from the diff. commitlint's default configuration does not check this correspondence, so the writer must uphold it.
- It applies in all cases, with or without a scope:
feat(api)!:feat!:fix(api)!:fix!: - Do not use
chore!. A breaking change affects users by definition, which contradictschore, the type that does not move the version. If you want to writechore!, the type decision is wrong. - The footer starts with
BREAKING CHANGE:(uppercase, space-separated). - A commit with
!corresponds to a SemVer major. Bothfeat!andfix!are major; it overrides the minor/patch mapping of the type.
feat(api)!: make session retrieval asynchronous
BREAKING CHANGE: getSession() now returns a Promise. Callers that use the
return value synchronously must await it, or switch to getSessionSync() if
a synchronous path is required. getSessionSync() remains available through
v3 as a migration window.
Step 4: Write the Subject
- Summarize the change in one line. This cannot be omitted.
- In English, use the imperative mood, start lowercase, and no trailing period (
add, notadded/adds). - In Japanese, the imperative is unnatural, so choose either the noun-ending style (
〜を追加) or the plain form (〜を追加する), matching the existing history. - Aim for 72 characters or fewer in English, with 100 as the hard limit. In Japanese, aim for about 50 characters.
If the content is too large to fit in one line, that is a sign the commit is too coarse, but splitting commits is out of scope for this skill. In the subject, narrow it down to the single most important point.
Step 5: Write the Body (most of the time, do not)
Principle
AI has dramatically lowered the human effort required to read code. There is no longer value in writing what can be learned by reading the diff. Keep only the information that would be lost forever if it were not written down.
The Test
Could a capable reader who has the diff and the whole repository reconstruct this statement with sufficient certainty? If they could, delete it. If they could not, keep it.
Do not keep something just because "it can be derived in theory." Conversely, keep what "can be derived, but only at great effort, and whose absence collapses the premise of the review" (e.g., a single line saying "no behavior change" for a mechanical rename across 400 files). When in doubt, choose the shorter option.
Information Worth Keeping
- The intent behind the change and what triggered it (an incident, an inquiry, a request)
- The user's instructions in this session and the requirements agreed on during the conversation (Step 6)
- Alternatives that were considered and rejected, and why. One of the highest-value pieces of information, because it prevents the discussion from being reopened later
- External constraints that shaped the solution (compatibility with other systems, deadlines, vendor circumstances)
- Side effects and risks that are invisible in the diff (e.g., the cache becomes eventually consistent, so downstream jobs may see values up to 60 seconds stale)
- Facts discovered during the work that are not written in the code (the actual behavior of an external API, etc.)
- Work that was deliberately deferred, and why
- Manual verification that automated tests do not reproduce
- External references (issue / incident / spec) → put these in the footer
Information That Must Not Be Written
- A list of the files or functions that were changed
- A restatement of what the code now does
- A repetition of the subject
- Things the diff shows obviously, such as "refactored X" or "added tests"
- Contentless boilerplate such as "as requested" or "I made the following changes"
- Mechanical counts such as lines changed or number of tests
The Most Important Point
If no information survives the filter, do not write a body. A subject-only commit is a correct state, not a deficiency.
The moment you start summarizing the diff in order to fill the body, the purpose of this skill is lost. Most commits are complete with a one-line subject.
Step 6: Information Originating in the Session
When an AI agent commits during a coding session, the user's instructions and the task requirements agreed on during the conversation must be kept in the body. This information is lost once the session ends and can never be reconstructed from the diff.
Operating rules to follow:
- Distill it. Do not transcribe the conversation verbatim; summarize it into the agreed requirements and constraints. However, when the exact wording is the requirement (the text of an error message, a naming decision, a threshold value), quote it verbatim.
- Split it per commit. When a single session produces multiple commits, write only the requirements that commit implemented in each one. Do not paste the same instruction text into every commit.
- Write the requirements as finally agreed. Keep an intermediate change of direction only when it will inform future decisions, and then keep it as a "rejected alternative" with the reasoning.
- Do not bring in confidential information. Always apply the next section.
Never Write Confidential Information
Commit history is permanent, and rewriting it requires destructive history operations. Beyond that, it travels farther than assumed at the time of writing, through repository publication, forks, mirrors, CI logs, and auto-generated CHANGELOGs.
When you summarize a session's conversation into a body, it is easy to accidentally carry over confidential information that appeared in the user's messages. Always run this check before writing anything derived from the conversation.
Do not write:
- Credentials of any kind (API keys, access tokens, passwords, private keys, connection strings)
- URLs containing tokens or session IDs
- Personal information (names, email addresses, phone numbers, internal account names)
- Confidential customer or partner names, contract terms, or pricing
- Unannounced product plans, release schedules, or non-public internal structure of internal systems
- Details of unfixed or undisclosed vulnerabilities. In a fix commit, do not write the attack steps or reproduction conditions; if needed, document them separately after disclosure.
How to replace them: "at the request of customer A Corp." → "due to a specific customer's migration requirement"; "verified at https://internal.example.com/?token=xxx" → "verified in the staging environment."
When in doubt, leave it out. If the information is truly needed, put a link to the issue in the footer and let readers follow it.
Step 7: Footer
Use the Token: value form. Replace whitespace inside a token with - (BREAKING CHANGE: is the only exception).
Commonly used ones:
Refs: #123
Closes: #123
Reverts: 9f2c1ab
BREAKING CHANGE: ...
Do not introduce custom trailers such as Requested-by:. They gain little relative to the tooling they require. Write reasons, constraints, and alternatives as prose in the body, and use the footer only for machine-readable references.
Language
- Match the language of the existing history. If there is no history, default to English.
git log -10 --format=%s
- The type / scope / footer tokens are always in English regardless of the language (
fix(auth):BREAKING CHANGE:). - Do not mix languages within a single commit. Quoting identifiers, error text, and API names is the exception.
Self-Check Before Committing
- Does the type match the SemVer mapping? Is it
choreeven though it affects the release artifact or how it is built? - Is a refactoring, performance improvement, or runtime dependency update marked
chore? (→fix) - Are
refactor:docs:test:ci:and the like used as types? (→ move them to the scope) - If there is a
!, is there aBREAKING CHANGE:footer? Conversely, is!missing on something breaking? - Does the
BREAKING CHANGE:cover both what breaks and how to migrate? - Has it become
chore!? - Is every sentence in the body information that cannot be reconstructed from the diff with sufficient certainty? Did you delete what can be?
- If deleting left the body empty, commit with the subject alone.
- Is any confidential information mixed in?
- Is the language consistent with the existing history?
How to Pass the Message
A message containing a body or footers breaks under shell interpretation if you cram newlines into -m. Pass it via standard input:
git commit -F - <<'EOF'
fix(auth): extend the token verification timeout to 5 seconds
The external IdP's p99 latency has degraded to 3.2 seconds, so the previous
3-second timeout was failing legitimate authentications. Waiting for the IdP
side to improve was rejected because there is no estimate for recovery. The
permanent fix is tracked in #451.
Refs: #448
EOF
Quoting as <<'EOF' matters. Without the quotes, ` and $ inside the message are expanded by the shell.
git commit -m "..." -m "..." also works (each -m becomes one paragraph). In that case, put the footers together in the last -m.
References
references/EXAMPLES.md— Good and bad examples side by side. Read it when a decision is unclear, especially when unsure what to keep in the body.assets/commitlint.config.js— A configuration to drop into a repository when you want to enforce this convention mechanically (optional). commitlint cannot check the correspondence between!andBREAKING CHANGE:, so that part is covered by the self-check.
What ships with it: 2 files
16.1 KB alongside SKILL.md, 1 of them executable
assets/
- commitlint.config.jsruns2.6 KB
references/
- EXAMPLES.md13.5 KB