bahaospanov/skills/tree/main/git-gates
git-gates
function hooks を基盤にした Claude Code mod。現在のセッションでユーザーの許可がない commit、push、merge をブロックし、すでに取り込まれたブランチの push を拒否する。commit メッセージ(Conventional Commits 形式、issue 参照、本文への Haiku チェック)と MR の説明を確認し、push した一連の commit が各 commit の時点でプロジェクトを動かせることを検証し、マージ済みでクリーンな作業の後に worktree とブランチを片付ける。
この mod について
Bakhtiyar Ospanov の agent skills と Claude Code mod:function hooks で構築されたプラグイン群。
Skills
skills CLI が対応する任意の agent では、次のように使える:
npx skills add bahaospanov/skills --skill <skill>
Claude Code では 1 つのプラグインとしてすべてを導入し、/bahaospanov-skills:<skill> で呼び出せる:
/plugin marketplace add bahaospanov/skills
/plugin install bahaospanov-skills@bahaospanov
| Skill | 目的 |
| --- | --- |
| prototype-stages | mattpocock/skills prototype(MIT)の UI ブランチを作り直したもの。フロー全体、段階別にまとめたオプション、ワンクリックパネルを提供する |
| scheme | 制御フロー、データフロー、変更前後、レイヤーを ASCII の図で示す |
Mods
アーリーアクセス版。API はリリース間で変わる。
目的ごとに mod を 1 つ使う。
| Mod | 目的 | | --- | --- | | git-gates | git 作業を承認済みで整理された状態に保つ | | lean-docs | 残す価値のあるドキュメント | | lean-comments | 残す価値のあるコメント | | lean-scripts | 残す価値のあるスクリプト |
Haiku のレビューは先にコードでゲートされるため、失敗しようのない呼び出しではモデルを呼ばない。ターンの最後には、そのターンで触れたリポジトリの git diff(Bash で行った編集も含む)を読み、1 セッションあたり最大 2 回のフォローアッププロンプトを送る。
git-gates
push はデプロイにあたるため、agent は現在のセッションでユーザーの明示的な同意を必要とする。開始時のプロンプトまたは実行中に入力されたメッセージが対象で、バックグラウンドタスクの報告は同意を取り消さない。同意チェック自体に失敗した場合、その呼び出しはブロックされる。
| Check | 実行対象 | 必要なもの | その後 | | --- | --- | --- | --- | | consent | git commit、push、PR/MR merge | 現在のセッションで commit、push、ship、deploy、pr、mr、tag、release のいずれかが入力され、保護ブランチがある場合はその名前も必要 | 呼び出しをブロック | | grants | セッション中の後続 commit | タスクごとに commit を求めるメッセージ、または承認メッセージ後の grant ツール | commit が grant を消費 | | messages | git commit | Conventional Commits の件名、先回りしたレビュー回答がないこと、最後の行に issue または ticket(#87、#BLK-23)があること。メッセージまたはブランチ名にある場合はそちらを使う | commit をブロック | | descriptions | MR/PR の説明設定 | 0 列目の固定ラベルブロック | 呼び出しをブロック | | landed branch | git push | push 済みのブランチ head が保護ブランチにすでに含まれ、新しい MR に触れていない | push をブロック | | every commit works | リモートにない 2〜15 個の commit の push | Sonnet:後の commit が復活させるものを前の commit が削除していないこと、後の commit で追加されるものを前の commit が使っていないこと。順序が問題ないとメッセージに書かれていればスキップ | push をブロック | | stale work | セッション終了時 | セッション中に commit または push したブランチの head が統合ブランチにあり、worktree がクリーン | 確認後、ローカルと origin の worktree とブランチ削除を促す |
保護ブランチはリポジトリの push policy ファイルから取得する。統合ブランチは保護ブランチで、ポリシーがない場合はリモートのデフォルトブランチと、存在する dev、develop、main、master を使う。
origin のブランチ head がすでに統合ブランチに含まれていれば、そのリモートブランチの削除にキーワードは要らない。
単独の #87 が有効なのはリモートのあるリポジトリだけで、issue tracker がなければ要求しない。入力した issue は、このセッションのリポジトリとその worktree の commit に紐付く。issue 番号で終わるブランチ(perf/mobile-lcp-89)なら、メッセージをその番号で終えられる。
lean-docs
| Check | 実行対象 | 検出内容 | その後 | | --- | --- | --- | --- | | docs-review | git checkout で新規作成または増補されたドキュメント | Haiku:作業後に誰も読まない文書(runbook、セットアップページ、ナレーション) | Claude に理由を伝える | | docs-no-repeat-code | 書かれているドキュメントの行 | 1 つのコードファイルにすでに一緒に現れる識別子 | 書き込みを拒否 | | limit-docs | セッション終了時 | 新規または増補されたドキュメント、コードより本文が多い文書、コードを繰り返す文書 | フォローアッププロンプト |
lean-comments
コメントは原則書かない。測定値、落とし穴、不変条件を記録するコメントは残し、コードを言い換えたり変更を説明したりするコメントは削る。
| Check | 実行対象 | 検出内容 | その後 | | --- | --- | --- | --- | | limit-edits | Write または Edit | 追加コメントが 3 行を超える、または編集箇所の周囲がコメント過多 | Claude に指針を伝える | | limit-turns | セッション終了時 | そのセッションの diff で 1 ファイルあたり新規コメントが 3 行を超える | フォローアッププロンプト |
lean-scripts
| Check | 実行対象 | 検出内容 | その後 | | --- | --- | --- | --- | | scripts-review | git checkout で作成または増補されたスクリプト | Haiku:必要なときにもう一度入力すればよいスクリプト | Claude に理由を伝える |
Mods のインストール
function hooks を有効にした場合だけ mods が読み込まれるため、まず shell profile で次を export する:
export CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1
この設定がないと Claude Code は mods を黙ってスキップする。その後、Claude Code で次を実行する:
/plugin marketplace add bahaospanov/skills
/plugin install <mod>@bahaospanov
開発
mod ごとに 1 つのフォルダーを使う。tsconfig.json と types/ は共有される。インストール済み mod は自分のフォルダーだけを持つため、2 つの mod が共有するコードは各 hooks/shared/ にコピーされる。
CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 claude --plugin-dir ./<mod> --debug
<mod>/hooks/ のファイルを保存すると mod が再読み込みされる。--plugin-dir を繰り返せば複数を読み込める。
Check
npm run typecheck # すべての mod とテストに対して tsc を実行
npm run check:shared # hooks/shared/ のコピーが各 mod で同一か確認
claude plugin validate ./<mod> # エンジンが見るモジュール hook と呼び出し
claude plugin test ./<mod> # mod のテスト
Types
types/ は、上記の方法で開始したセッション内で実行する /plugin-types types によって書き込まれる。次の場合は再生成し、手動編集しない:
- Claude Code の更新(
head -1 types/claude-code.d.tsとclaude --versionを比較) $に追加する plugin の有効化または無効化- MCP サーバーの接続または切断
生成結果を commit する。git diff types/ で変更を確認できる。
インストール
まず作者の README で marketplace とプラグイン名を確認してください。コマンドはリポジトリの構成によって変わる場合があります。
claude plugin marketplace add bahaospanov/skills claude plugin install git-gates
原文 / README
bahaospanov
Bakhtiyar Ospanov's agent skills, and Claude Code mods: plugins built on function hooks.
Skills
For any agent the skills CLI supports:
npx skills add bahaospanov/skills --skill <skill>
Or in Claude Code, all of them as one plugin, invoked as /bahaospanov-skills:<skill>:
/plugin marketplace add bahaospanov/skills
/plugin install bahaospanov-skills@bahaospanov
| Skill | Purpose |
| --- | --- |
| prototype-stages | mattpocock/skills prototype (MIT), its UI branch reworked: whole flows, options grouped by stage in a one-click panel |
| scheme | ASCII schematic of a code change: control flow, data flow, before/after, or layers |
Mods
Early access; the API changes between releases.
One mod per purpose.
| Mod | Purpose | | --- | --- | | git-gates | Git work is authorized and tidy | | lean-docs | Docs worth keeping | | lean-comments | Comments worth keeping | | lean-scripts | Scripts worth keeping |
Haiku reviews are gated in code first, so a call that cannot fail the review costs no model call. End-of-turn checks read the git diff of repos the turn touched, Bash edits included, and send at most two follow-up prompts a session.
git-gates
Pushing is a deploy, so the agent needs the user's word in the current turn: the prompt that opened it or one typed while it ran. If a consent check itself fails, the call is blocked.
| Check | Runs on | Needs | Then | | --- | --- | --- | --- | | consent | git commit, push; PR/MR merge | commit, push, ship, deploy, pr, mr, tag or release typed in the current turn (a message typed while it runs or a background task's report does not withdraw it); merge needs "merge"; a protected branch must be named | Call denied | | grants | Later commits in the session | A message asking for a commit per task, or the grant tool after an authorizing message | Commits spend the grant; pushes never | | messages | A git commit | Conventional Commits subject, no reviewer pre-answers, a last line with the issue or ticket (#87, #BLK-23) when your messages or the branch name one; then Haiku: a body only when the cause is subtle | Commit denied | | descriptions | Setting an MR/PR description | Fixed-label blocks at column 0 | Call denied | | landed branch | A git push | The branch's pushed head already sits in a protected branch, and the message names no new MR | Push denied | | every commit works | A git push of 2 to 15 commits no remote has | Sonnet: no commit removes something a later one stops using, or uses something a later one adds; skipped when the message says the order is fine | Push denied | | stale work | The end of a turn | A branch the session committed to or pushed whose head sits in an integration branch, its worktree clean | Follow-up prompt to remove the worktree and the branch, local and on origin, once checked |
Protected branches come from a repo's own push policy file.
Integration branches are the protected ones; with no policy, the remote's default branch and any of dev, develop, main, master that exist.
Deleting a branch on origin needs no keyword when origin's head of it already sits in an integration branch.
A bare #87 counts only in a repo with a remote; with no issue tracker, nothing is asked.
Issues you typed bind only commits in the session's repo and its worktrees; a branch ending in its issue number (perf/mobile-lcp-89) lets the message end with that one instead.
lean-docs
| Check | Runs on | Flags | Then | | --- | --- | --- | --- | | docs-review | A doc grown in a git checkout | Haiku: text nobody reads after the task (runbooks, setup pages, narration) | Claude gets the reason | | docs-no-repeat-code | A doc line being written | Identifiers that already appear together in one code file | Write denied | | limit-docs | The end of a turn | New or grown docs, prose outweighing code, doc lines repeating code | Follow-up prompt |
lean-comments
No comments by default: keep the ones that record a measured number, a trap or an invariant, cut the ones that restate the code or narrate the change.
| Check | Runs on | Flags | Then | | --- | --- | --- | --- | | limit-edits | A Write or Edit | More than 3 added comment lines, or a comment-heavy region around the edit | Claude gets the guidance | | limit-turns | The end of a turn | More than 3 new comment lines per file in the turn's diff | Follow-up prompt |
lean-scripts
| Check | Runs on | Flags | Then | | --- | --- | --- | --- | | scripts-review | A script written or grown in a git checkout | Haiku: scripts you could just type again when needed | Claude gets the reason |
Install mods
Mods load only with function hooks enabled, so export this in your shell profile first:
export CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1
Without it Claude Code skips the mods silently. Then, in Claude Code:
/plugin marketplace add bahaospanov/skills
/plugin install <mod>@bahaospanov
Develop
One folder per mod. tsconfig.json and types/ are shared. An installed mod
carries only its own folder, so code two mods share is copied into each one's
hooks/shared/.
CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 claude --plugin-dir ./<mod> --debug
Saving a file under <mod>/hooks/ reloads the mod. Repeat --plugin-dir to
load several.
Check
npm run typecheck # tsc over every mod and its tests
npm run check:shared # hooks/shared/ copies are identical across mods
claude plugin validate ./<mod> # what the engine sees the module hook and call
claude plugin test ./<mod> # the mod's tests/
Types
types/ is written by /plugin-types types, run inside a session started as
above. Regenerate, never edit, when:
- Claude Code updates (
head -1 types/claude-code.d.tsvsclaude --version) - a plugin that adds to
$is enabled or disabled - an MCP server is connected or disconnected
Commit the result; git diff types/ shows what the update changed.
