Pins the model that background recon subagents run on. An agent.spawn hook sets the Explore subagent's model to haiku, so a session driven by an expensive…

Set of prompts, skills, and scripts to aid in utilizing AI coding agents in development workflows.
The setup script and the review loops are Bash scripts that shell out to a handful of command-line tools. Install the ones below and make sure they are on your PATH.
Required (the setup script exits early if any is missing):
git, to clone the repo and drive the git-based commandsgh) 2.88.0+, installed and authenticated (/review-pr uses the gh pr edit --add-reviewer @copilot special value added in 2.88.0 to re-request Copilot code review)jq, a JSON processor used to read and edit each tool's settings and MCP config filesRequired only for optional steps:
npx), for the MCP servers and the Impeccable design skills. setup skips those steps with a warning if npx is not found.At least one AI coding tool:
agy command)kimi command)| Tool | macOS (Homebrew) | Debian / Ubuntu | Windows (winget) |
|---|---|---|---|
git | brew install git | sudo apt install git | bundled with Git for Windows |
gh | brew install gh | gh install docs | winget install GitHub.cli |
jq | brew install jq | sudo apt install jq | winget install jqlang.jq |
| Node.js | brew install node | sudo apt install nodejs npm | winget install OpenJS.NodeJS |
The other utilities the scripts call (bash, grep, sed, awk, sort, diff, find, comm, ...) are standard on macOS and Linux, and are bundled with Git for Windows.
Windows: Run
./setupand the review loops from Git Bash (part of Git for Windows). Git Bash ships Bash and the standard Unix utilities but notjq, so installjqseparately with the command above.
git clone https://github.com/rlorenzo/ai-coding-setup.git
cd ai-coding-setup
./setup
The script detects which AI tools you have installed and walks you through installing commands for each one interactively.
Windows: Run the setup script from Git Bash.
| Tool | Command format | Source directory | Installs to |
|---|---|---|---|
| Claude Code | Plugin (.claude-plugin/) | .claude/commands/, plugins/, mods/ | loaded in place from the clone |
| Claude Code (copy fallback) | Markdown (.md) | .claude/commands/, plugins/explore-agent/agents/ | ~/.claude/commands/, ~/.claude/agents/ |
| Codex CLI | Agent Skills (SKILL.md) | .codex/skills/ | ~/.codex/skills/ |
| Copilot CLI | Agent Skills (SKILL.md) | .copilot/skills/ | ~/.copilot/skills/ |
| Antigravity CLI | Unified Plugin (plugin.json) | .antigravity/ | ~/.gemini/antigravity-cli/plugins/ai-coding-setup/ |
| Kimi Code CLI | Agent Skills (SKILL.md) | .kimi-code/skills/ | ~/.kimi-code/skills/ |
| Shared prompts | Markdown (.md) | prompts/ | ~/.local/share/ai-coding-setup/prompts/ |
Kimi Code reads its user-level data from $KIMI_CODE_HOME when that variable is set; setup honors it and falls back to ~/.kimi-code. Kimi invokes skills as /skill:<name>, so the commands below are /skill:commitmsg, /skill:review-pr, and so on.
Claude Code is the one harness here with a plugin system of its own, and setup uses it by default: instead of copying seven Markdown files into ~/.claude/commands/, it registers this clone as a marketplace and installs from it.
The marketplace holds three plugins:
| Plugin | What it is | Needs |
|---|---|---|
ai-coding-setup | The seven commands | Nothing |
explore-agent | The Explore subagent as an agent file that shadows the built-in | Nothing |
explore-model | The same pinning as an agent.spawn function hook, with no shadow | CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 |
review-gate | The review gate as a tool.check function hook | CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 |
explore-agent and explore-model do the same job two ways and you want exactly one of them; see Explore. setup installs whichever your session can run and removes the other.
claude plugin marketplace add ./ # from inside the clone
claude plugin install ai-coding-setup@ai-coding-setup --scope user
claude plugin install explore-agent@ai-coding-setup --scope user
Three things are better this way:
git pull. The plugin loads in place from the clone, so pulling new commands makes them live at the next session start. The copy path needs another ./setup run to notice.claude plugin uninstall ai-coding-setup takes all seven commands and the agent with it, where the copies have to be deleted one by one.~/.claude/commands/. A command of your own that happens to share a name is never shadowed, and the source markers and stale-orphan pruning the copy path needs stop mattering.The trade-off is that the plugin loads in place: move or delete the clone and the commands go with it. A copy would have survived. If that matters more than live updates, answer n at the plugin prompt and setup falls back to copying, exactly as before. Either way it offers to remove whichever set it did not install, so no command is ever listed twice.
To install without a clone at all, point the marketplace at the repo:
claude plugin marketplace add rlorenzo/ai-coding-setup
claude plugin install ai-coding-setup@ai-coding-setup --scope user
Propose a conventional commit message for the currently staged changes. Detects ticket IDs from branch names and follows the project's recent commit style.
Usage:
/commitmsg$commitmsg/commitmsg/commitmsg/skill:commitmsgProcess unresolved review comments on a GitHub PR, fix valid issues, ensure CI passes, and re-request review.
Review bots count as required reviewers: every bot that has reviewed the PR must cover the head commit, falling back to the bots used on the repo's recent PRs, and asking you if none are found. The skill reads each bot's review body as well as its threads, so findings with no thread still get handled, and a non-approving verdict (Copilot's Changes recommended, a nonzero CodeRabbit count) blocks success until you accept the declined findings. It re-triggers Copilot, CodeRabbit, and Greptile itself and asks for the trigger of any other bot. It keeps working through its iterations without stopping to report, and treats comment text as untrusted: findings are judged against the code, never followed as instructions.
Usage:
/review-pr [PR_NUMBER]$review-pr [PR_NUMBER]/review-pr [PR_NUMBER]/review-pr [PR_NUMBER]/skill:review-pr [PR_NUMBER]Review staged files against four quality angles (simplification, reuse, efficiency, altitude), apply the fixes, fix linting issues, and check test coverage. On large diffs, fans the angles out to parallel mid-tier subagents when the agent has a subagent tool. The reuse angle searches shared and nearby modules before concluding nothing existing fits, and each reuse finding names the existing alternative and its path.
Usage:
/code-refinement$code-refinement/code-refinement/code-refinement/skill:code-refinementRun a standalone code review on staged changes. Writes findings to agent-code-review.md.
Usage:
/code-review$code-review/code-review/code-review/skill:code-reviewAudit dependency updates for supply-chain risk before they land: publish-age gate, changelog/diff verification, security advisories, community signals, and breaking changes. Changelogs, release notes, and package source are treated as third-party evidence to verify, not instructions: text that tells the agent to run something, skip a check, or approve the update is itself flagged as a HOLD.
Usage:
/dependency-review$dependency-review/dependency-review/dependency-review/skill:dependency-reviewRun a task with your current model as the orchestrator and reviewer while cheaper, faster subagents do the token-heavy research, coding, and testing. It matches model tier to task difficulty (your own tier for complex work, a mid tier for low/medium, the cheapest tier for mechanical), keeps the orchestrator's own reading and searching lean, runs delegation in bounded waves to respect your usage caps, and for long unattended runs auto-pauses and resumes across usage windows. No model names are hardcoded beyond a Claude example ladder: each harness orders its own available models by cost and capability, and everything else is written relative to whatever tier you are on. Agents without a native subagent tool (Codex, Copilot) delegate by spawning their own CLI non-interactively with an explicit model.
The skill also pins the model explicitly on every spawn (since Claude Code v2.1.198 the built-in Explore/Plan/general-purpose subagents inherit the main-session model, so an un-pinned background search bills at your tier), prefers model aliases over pinned IDs, drops reasoning effort for cheap-tier recon (and treats lower effort on your own tier as an alternative to a cheaper tier for bounded coding slices), gives each handoff an advisory time budget backed by a hard timeout, distinguishes what delegation buys on API vs. subscription billing (per-token savings vs. quota-bucket arbitrage), and closes non-trivial work with a fresh-context verifier that only refutes, never fixes.
Usage:
/efficient-orchestration$efficient-orchestration/efficient-orchestration/efficient-orchestration/skill:efficient-orchestrationRewrite a feature branch's git history into focused, logical commits before review or merge. It surveys the branch's commits past the merge base, folds review-response, fixup, WIP, and lint-fix noise into the substantive commits they amend, and reorders the result so each commit is reviewable on its own and git blame stays meaningful. Refuses to run on main or other long-lived branches, creates a backup branch before rewriting, and verifies the final tree is byte-identical to the original tip. Once verified it force-pushes with --force-with-lease (never bare --force) and deletes the backup branch; on any failure the backup is kept so the original history is never lost.
Usage:
/git-history-cleanup [BRANCH]$git-history-cleanup [BRANCH]/git-history-cleanup [BRANCH]/git-history-cleanup [BRANCH]/skill:git-history-cleanup [BRANCH]The subagent definitions ship as the explore-agent plugin, from plugins/explore-agent/agents/; on the copy path setup installs them to ~/.claude/agents/. These are Claude Code-only (the other harnesses have no equivalent mechanism).
They sit at that plugin's root rather than under .claude/ because the root agents/ directory is the only place Claude Code loads plugin agents from. The manifest's agents key accepts a list of file paths, claude plugin validate --strict passes, the install succeeds, and yet the agent is silently missing from the loaded plugin. So no manifest here names an agents key at all, and test/plugin-manifest.bats fails if one is added.
Since Claude Code v2.1.198 the built-in Explore subagent inherits your main-session model instead of always running on Haiku (capped at Opus on the Claude API). If your daily driver is Opus or Fable, every background codebase search Claude spontaneously delegates bills at that tier. This agent shadows the built-in (a user-level agent with the same name overrides it, which the docs explicitly support) and pins exploration back to haiku at effort: low with read-only tools.
Trade-off to know about: a custom Explore loads your CLAUDE.md/user memory like any subagent, which the built-in skips for speed. That is the cost the explore-model mod exists to remove. To remove the agent, claude plugin uninstall explore-agent, or delete ~/.claude/agents/Explore.md if you took the copy path.
They pin the same thing two ways, and you want exactly one:
explore-agent | explore-model | |
|---|---|---|
| How | An agent file that shadows the built-in | An agent.spawn hook that sets the spawn's model |
Loads CLAUDE.md on every search | Yes | No |
| Keeps the built-in's definition | No, replaces it | Yes |
| Needs function hooks | No | Yes |
Install both and you get neither's benefit: the spawn resolves to your shadow definition rather than the built-in, so the CLAUDE.md load is back and the hook has nothing left to improve. setup installs one and uninstalls the other, and re-running it after you enable function hooks switches you over.
A mod is a Claude Code plugin whose behavior is a hooks module: TypeScript loaded into the engine, one register(on, options) entry whose hooks are ($, e, next) functions wrapping an engine event, Express-middleware style. Where a classic hook is a shell command spawned after the fact, a function hook can rewrite the event, answer it, or refuse it, in process.
Four ship inside Claude Code (sec-default, diff, telemetry, agents-md). The ones here live in mods/.
Early access. Hooks modules load only when CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 is set, on Claude Code 2.1.260 or newer, and upstream says the API they are written against may change between releases without notice. setup offers to write the flag into ~/.claude/settings.json, and defaults to No: nothing else in this repo depends on an unreleased API, and a mod that stops loading after an update is a worse surprise than an agent file that never does.
Two things are worth knowing when you install one:
claude plugin details <mod> reports Hooks (0). The inventory counts classic hook matchers; a function-hooks module is not one, so the count reads zero even for a module that loads and fires. It is not a sign the mod is broken.claude binary, with no credentials and no home directory: CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 claude plugin test mods/explore-model. CI runs them for every mod; test/plugin-manifest.bats runs the same command locally and skips where claude is absent.Pins the model that background recon subagents run on, by hooking agent.spawn and setting the spawn's model.
This is the same goal as the explore-agent plugin and a better way to reach it. The agent file has to replace the built-in Explore definition to change its model, and a replacement is loaded like any other subagent, so it drags in your CLAUDE.md and user memory on every search, which the built-in skips for speed. The hook sets one field on the spawn and leaves the built-in definition running, so there is no shadow and no extra load.
Two spawns are handed straight through. A fork inherits its parent's context and model and ignores model outright, so rewriting it would only misdescribe what happens. A spawn that named its own model was an explicit choice by the caller, and the case the hook is here to decide is the one nobody decided.
It is also the enforcement /efficient-orchestration currently has to ask for: that skill instructs the model to pin a model on every spawn, which is a prompt-level plea the model can forget on exactly the code path where forgetting is expensive. The hook makes it an engine-level invariant instead.
| Option | Default | Effect |
|---|---|---|
model | haiku | The alias or id the named agents run on. Prefer an alias: it tracks whichever model answers to that name, where a dated id stops applying the day the next one ships. inherit registers no hook at all. |
agents | Explore | The subagent types this applies to. Only read-only recon agents belong here: a pinned agent runs on model whatever its own definition asks for. |
notice | false | Attach a one-line notice to each spawn the hook pins. Off by default, since the point is to be invisible; turn it on to confirm the mod is loaded and firing. |
claude plugin install explore-model@ai-coding-setup --scope user \
--config model=haiku --config agents=Explore --config notice=false
Note that this is a floor on cost, not the only one: setup also offers CLAUDE_CODE_SUBAGENT_MODEL=sonnet, which is the fallback tier for every subagent. The mod is the narrower, cheaper pin for the one agent Claude dispatches on its own.
The review gate as a tool.check hook. Same gate, better seat.
bin/review-gate is wired as a PreToolUse shell hook and fires on every command the agent runs (overwhelmingly ls, cat and test runs), each one paying a process start. Measured in this repo: roughly 160ms warm under Git Bash on Windows against 55ms for a bare bash -c true, and over a second on a cold file cache. The script's fast path exits before any git call, but bash still has to start.
The mod answers that same question with a substring test inside the engine's own process, and spawns the script only for a command that could actually be a commit. On the calls that dominate, the cost goes to zero.
The second gain is ask. A PreToolUse hook can only allow or deny, which is why the gate ships in warn and why its own docs describe handing the question back to you as something it cannot do; the closest it gets is denying and asking the agent to ask you. tool.check can answer ask, so a blocked commit becomes your permission prompt, carrying the gate's reason, diff and rubric.
What the mod does not do is decide anything. The rules (which commands commit, what a receipt has to match, when a rewrite is in progress, the git commit -a cases that can never be vouched for) stay in bin/review-gate, which the mod runs with the claude payload it already speaks and reads the JSON it already prints. One implementation, one test suite, no second copy to drift, and both routes read the same receipts under .git/ai-review/, so they can never disagree about whether a change was reviewed.
That last point is why the mod does not keep receipts in the engine's own $.store, which would have been the obvious place: code-review-loop writes the receipts, and a store only the mod can read would mean the loop's clean run no longer cleared the gate.
| Option | Default | Effect |
|---|---|---|
blocked | ask | What a blocked commit does. ask puts the gate's reason to you as a permission prompt. deny refuses outright, matching REVIEW_GATE=block. |
gate | unset | Where bin/review-gate is. Unset, the hook tries AI_REVIEW_GATE_BIN, then ~/.local/bin/review-gate, then review-gate on PATH. |
The script's own modes still decide everything else: REVIEW_GATE=off and the AI_REVIEW_GATE=off bypass work exactly as they do without the mod, and in warn mode the gate's reasoning goes to the transcript instead of a stderr nobody reads.
Install the two together and the script runs twice for one commit, issuing a second single-use nonce that invalidates the first, so setup removes the PreToolUse entry when it installs the mod.
claude plugin install review-gate@ai-coding-setup --scope user \
--config blocked=ask --config gate="$HOME/.local/bin/review-gate"
Two multi-agent feedback loops live in bin/: code-review-loop (for staged code) and plan-review-loop (for plan documents), alongside review-gate, the hook that keeps an agent from committing before the first of those has run. Each loop pairs an editor agent with a different reviewer agent and iterates until the reviewer is satisfied or --max-iterations is hit. Using two different models for editing and reviewing surfaces issues a single agent tends to miss in its own output.
Both scripts are installed onto your PATH by ./setup and rely on the prompts in prompts/ (installed to ~/.local/share/ai-coding-setup/prompts/).
Runs a full review cycle over your staged changes:
code-refinement prompt (four review angles, lint, test coverage). Skip with -s.agent-code-review.md.agent-review-summary.md.A pre-review snapshot of your staged work is saved to the git stash so you can restore the original if the loop mangles something. Files in the review scope that also have unstaged changes are rejected up front, so fully stage or unstage before running.
Pass --branch to widen the scope to the whole branch: the diff under review becomes every commit since the branch left the default branch (its merge-base) plus whatever is staged. The default branch is read from origin/HEAD, falling back to main then master; pass --branch REF to name another. Fixes from the loop are still staged, never committed, so you can fold them into the branch however you like.
Usage:
code-review-loop # default agents, 5 iterations
code-review-loop -m 3 # cap at 3 review cycles
code-review-loop -s # skip the refinement step
code-review-loop --branch # review the branch's commits plus staged changes
code-review-loop --branch develop # same, against a named base branch
code-review-loop --editor claude --reviewer codex
Outputs (project root): agent-code-review.md (latest findings), agent-review-summary.md (narrative).
When a run fails, read the logs. Each agent's full output is written to a per-run directory, printed in the banner at startup and again whenever an agent exits non-zero:
Logs : ~/.cache/code-review-loop/20260807-142516
One file per step, named for the step and the agent that ran it:
1-refinement.claude.log
3-review-initial.antigravity.log
4.1-response.claude.log
6.1-review.antigravity.log
final-summary.claude.log
Each records the agent, the tools it was allowed, its combined stdout and stderr, and its exit code. This is the difference between "it failed" and knowing why: a loop t
hooks/register.ts 47 lines1import type { On, PluginOptions } from 'claude-code'
2
3import Options from './options'
4
5/**
6 * Registers the spawn hook that pins the recon agents' model.
7 *
8 * Since Claude Code v2.1.198 the built-in `Explore` subagent inherits the
9 * main session's model, so a session on an expensive model pays that tier for
10 * every background codebase search Claude delegates. A user-level agent file
11 * of the same name overrides the built-in and can set `model:`, but a
12 * replacement definition is loaded like any other subagent, which means it
13 * also loads CLAUDE.md and user memory that the built-in skips for speed.
14 *
15 * Setting `model` on the spawn costs neither: the definition that runs is
16 * still the built-in, and only what it runs on changes.
17 *
18 * Two spawns are left exactly as they came. A fork inherits the parent's
19 * context and model and ignores `model` outright, so rewriting it would say
20 * something untrue about what happens. A spawn that named its own model was
21 * an explicit choice by the caller, and the case this hook is here to decide
22 * is the one nobody decided.
23 *
24 * @param on the engine's registrar
25 * @param options the plugin's options: `model`, `agents` and `notice`
26 */
27export function register(on: On, options: PluginOptions): void {
28 if (Options.isInherited(options)) {
29 return
30 }
31
32 const model = Options.modelOf(options)
33 const isAnnounced = Options.isAnnounced(options)
34
35 on('agent.spawn', { subagentType: Options.agentsOf(options) }, ($, e, next) => {
36 if (e.fork || e.model !== undefined) {
37 return next(e)
38 }
39
40 if (isAnnounced) {
41 $.ui.notice(e.tool_use_id, `${e.subagentType} pinned to ${model}`)
42 }
43
44 return next({ ...e, model })
45 })
46}
47hooks/options.ts 79 lines1import type { PluginOptions } from 'claude-code'
2
3/**
4 * The agents pinned when the `agents` option names none: the built-in
5 * read-only search agent, the one Claude dispatches on its own.
6 */
7const DEFAULT_AGENTS: readonly string[] = ['Explore']
8
9/**
10 * The model pinned when the `model` option names none.
11 */
12const DEFAULT_MODEL = 'haiku'
13
14/**
15 * The `model` value that registers no hook, for turning the mod off without
16 * uninstalling it.
17 */
18const INHERIT = 'inherit'
19
20/**
21 * The model the named agents run on.
22 *
23 * A blank or absent value reads as unset rather than as "pin nothing": an
24 * empty `model` would otherwise pin every recon spawn to the empty string.
25 *
26 * @param options the plugin's options
27 * @returns the model alias or id, trimmed
28 */
29function modelOf(options: PluginOptions): string {
30 const given = options.model
31
32 return typeof given === 'string' && given.trim() !== ''
33 ? given.trim()
34 : DEFAULT_MODEL
35}
36
37/**
38 * Whether the options ask for no hook at all.
39 *
40 * @param options the plugin's options
41 * @returns true when every spawn is left as the engine resolves it
42 */
43function isInherited(options: PluginOptions): boolean {
44 return modelOf(options) === INHERIT
45}
46
47/**
48 * The subagent types the hook decides.
49 *
50 * A `multiple` string option arrives as an array, but a single `--config
51 * agents=...` pass arrives as one bare string, so both are read.
52 *
53 * @param options the plugin's options
54 * @returns the agent names, blanks dropped
55 */
56function agentsOf(options: PluginOptions): readonly string[] {
57 const given = options.agents
58 const listed = Array.isArray(given)
59 ? given
60 : typeof given === 'string'
61 ? given.split(',')
62 : []
63 const named = listed.map(agent => agent.trim()).filter(agent => agent !== '')
64
65 return named.length > 0 ? named : DEFAULT_AGENTS
66}
67
68/**
69 * Whether each pin is announced on the spawn it belongs to.
70 *
71 * @param options the plugin's options
72 * @returns true when the hook attaches a notice
73 */
74function isAnnounced(options: PluginOptions): boolean {
75 return options.notice === true
76}
77
78export default { agentsOf, isAnnounced, isInherited, modelOf }
79