# Setupbay — full catalogue > Every loadout on https://setupbay.com with every file inlined. Generated at build time. "Verified install" (Level 1) means automated checks passed on the files (parse, install paths, MCP config, safety scan, references, size, licence, starter build where a fixture exists); no AI agent is run for it. Agent test status "untested" means no AI agent has been run yet. Agents can query this catalogue instead of reading it all: MCP server https://setupbay.com/mcp (Streamable HTTP, read-only, no auth; tools search_loadouts, get_loadout, get_loadout_file, get_install_instructions, list_agents, list_tags) or `GET https://setupbay.com/api/v1/search?q=&agent=&tags=&verified=`. Setup for each agent: https://setupbay.com/docs/#mcp Pages by agent: https://setupbay.com/agents/claude-code/, https://setupbay.com/agents/codex/, https://setupbay.com/agents/cursor/, https://setupbay.com/agents/gemini-cli/, https://setupbay.com/agents/antigravity-cli/, https://setupbay.com/agents/copilot/. By stack: https://setupbay.com/stacks/. New and updated: https://setupbay.com/new/ (feeds: https://setupbay.com/feed.xml, https://setupbay.com/rss.xml). ## Current practice (trends, updated 2026-10-17) Read by hand from about 1,000 public posts on X by developers sharing real configs, repos and failure reports (engagement bait excluded), then checked against official changelogs and docs. Only behaviour confirmed in vendor documentation is stated as fact. Page: https://setupbay.com/trends/. JSON: https://setupbay.com/api/trends.json. ### Review is the bottleneck, so review gets configured (as of 2026-10-16) Claude Code Review reads REVIEW.md from the default branch, never from the pull request; Cursor Bugbot reads .cursor/BUGBOT.md and ignores .cursor/rules. Developers also have one agent ask another model (codex exec, claude -p) for a read-only review before saying done, and attach screenshots to PRs with gh --attach (gh 2.99). Practice: Put review-only rules in review files, cap nits, get a read-only second opinion on risky diffs, and keep PRs small. - Source: Claude Code docs, customise Code Review, https://code.claude.com/docs/en/code-review-customize (2026-10-16) - Source: Cursor docs, Bugbot, https://cursor.com/docs/bugbot (2026-10-16) - Source: GitHub CLI 2.99.0, https://github.com/cli/cli/releases/tag/v2.99.0 (2026-09-01) - Source: @Damir_Akaza: Claude Code asks codex exec to review, https://x.com/Damir_Akaza/status/2106333764548702392 (2026-10-03) - Loadouts: ai-code-review-rules (https://setupbay.com/loadouts/ai-code-review-rules/), second-opinion-review (https://setupbay.com/loadouts/second-opinion-review/), pr-hygiene-for-agents (https://setupbay.com/loadouts/pr-hygiene-for-agents/) ### Spend caps move from goodwill to flags and ledgers (as of 2026-10-16) Accenture now centrally funds $29 a month of Claude per employee from 1 October, with anything above charged to a project code (404 Media, 15 October; Accenture says it is a funding rule, not a hard limit). Practitioners cap unattended runs instead of trusting the session: Claude Code's --max-budget-usd works in print mode only, counts subagent spend, and since 2.1.296 prices Sonnet 5.5 cache reads at $0.10 per million tokens. Codex and Antigravity report token usage in their JSON output but have no budget flag. Practice: Cap every headless run with the agent's own flag where one exists, and keep a shared daily ledger across agents for the ones that only report tokens. - Source: 404 Media: Accenture funds $29 a month of Claude per employee, https://www.404media.co/accenture-tells-employees-they-can-now-spend-only-29-on-claude-per-month/ (2026-10-15) - Source: Claude Code changelog (2.1.296 cache-read pricing; 2.1.217 budget stops subagents), https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md (2026-10-17) - Source: @dhillonpost: --max-budget-usd counts subagent spend, print mode only, https://x.com/dhillonpost/status/2106644976494854234 (2026-10-04) - Source: @ekcheungAI: cap a headless run with --max-turns and --max-budget-usd, https://x.com/ekcheungAI/status/2111524159755010507 (2026-10-17) - Loadouts: agent-spend-cap (https://setupbay.com/loadouts/agent-spend-cap/), headless-agents-ci (https://setupbay.com/loadouts/headless-agents-ci/) ### Expo SDK 58 ships a CLI built for coding agents (as of 2026-10-15) Expo SDK 58 (React Native 0.88, built for iOS 27) adds the experimental @expo/agent-cli. It sits on top of Expo CLI, EAS CLI and expo-doctor, answers Expo Go compatibility without starting the app, prints next steps after each command, and syncs agent skills shipped inside node_modules. Expo's reason: agents kept finding out about native modules by hitting runtime errors. Practice: Make the native boundary explicit to the agent, with a development build for new native modules and a fingerprint check before any EAS Update. - Source: Expo changelog: SDK 58, https://expo.dev/changelog/sdk-58 (2026-10-15) - Source: @kadikraman: Expo SDK 58 is out, with expo/agent-cli, https://x.com/kadikraman/status/2111140629640048700 (2026-10-16) - Loadouts: expo-eas-update (https://setupbay.com/loadouts/expo-eas-update/), expo-react-native (https://setupbay.com/loadouts/expo-react-native/) ### Parallel agents in worktrees are the default (as of 2026-10-15) Running several agents at once, each in its own git worktree, is built into the tools: claude --worktree and worktree-isolated subagents, managed worktrees in Codex 0.162, and gh issue develop --worktree. Practice: One task per worktree and branch, separate ports and dependencies, and clean up only after merge. - Source: Claude Code docs, worktrees, https://code.claude.com/docs/en/worktrees (2026-10-16) - Source: GitHub CLI 2.99.0, https://github.com/cli/cli/releases/tag/v2.99.0 (2026-09-01) - Loadouts: parallel-agents-worktrees (https://setupbay.com/loadouts/parallel-agents-worktrees/) ### Antigravity CLI ships weekly: a plugin marketplace, then Auto mode (as of 2026-10-14) Antigravity CLI 1.3.2 (8 October) added /plugin and the official marketplace for plugins that bundle skills, MCP servers, subagents, rules and hooks; 1.3.5 (14 October) added Auto mode (--mode auto), which approves edits and safe commands and has a separate agent review commands that would leave the terminal sandbox. 1.4.0 (16 October) fixed ${VAR} expansion in plugin MCP headers. Practice: Pin what a plugin installs and read its skills and MCP config before enabling it; use Auto mode with the terminal sandbox on, not instead of it. - Source: Antigravity CLI 1.3.2 release notes (plugin marketplace), https://github.com/google-antigravity/antigravity-cli/releases/tag/1.3.2 (2026-10-08) - Source: Antigravity CLI 1.3.5 release notes (Auto mode), https://github.com/google-antigravity/antigravity-cli/releases/tag/1.3.5 (2026-10-14) - Source: Antigravity CLI 1.4.0 release notes, https://github.com/google-antigravity/antigravity-cli/releases/tag/1.4.0 (2026-10-16) - Loadouts: one-agents-md-every-agent (https://setupbay.com/loadouts/one-agents-md-every-agent/), headless-agents-ci (https://setupbay.com/loadouts/headless-agents-ci/) ### Teams write rules against AI-sounding prose (as of 2026-10-14) Readers now name the tells on sight: delve, seamless, pivotal, "it's not just X, it's Y", em-dash runs, emoji bullets and proof nobody can check such as "10,000+ users". Wikipedia's WikiProject AI Cleanup keeps a dated list of overused words by model generation, and practitioners are adding plain-writing rules to their agent files so READMEs, PR descriptions and release notes stop reading as generated. Practice: Put plain-writing rules in AGENTS.md for every file the agent writes, and lint prose for the known patterns while skipping code and quotations. - Source: @CDGalpha: the tells, from 'delve' to em-dash spam and fake proof, https://x.com/CDGalpha/status/2110292549210620174 (2026-10-14) - Source: Wikipedia: Signs of AI writing, https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing (2026-10-17) - Loadouts: no-ai-voice-writing (https://setupbay.com/loadouts/no-ai-voice-writing/) ### Evals start from real traces, not metric lists (as of 2026-10-13) Practitioners building agents keep repeating one order of work: read 30 to 50 real traces, note what failed, group the notes into failure modes, and only then write evals, replaying real failures after every prompt, tool or model change. Generic scores (helpfulness, coherence) are out; binary checks tied to observed failures are in. Practice: Do error analysis on real traces first; turn each recurring failure into a regression case that links to its trace and is shown to fail on the old output. - Source: Hamel Husain: LLM evals FAQ, https://hamel.dev/blog/posts/evals-faq/ (2026-10-16) - Source: @Benogju: look at the data, start with around 30 traces, https://x.com/Benogju/status/2104930651573240043 (2026-09-29) - Source: @pauliusztin_: replay your agent's real failures after every change, https://x.com/pauliusztin_/status/2109986591959626178 (2026-10-13) - Loadouts: evals-from-real-failures (https://setupbay.com/loadouts/evals-from-real-failures/) ### MCP servers start moving to the stateless 2026-07-28 spec (as of 2026-10-12) The 2026-07-28 revision removes the initialize handshake and Mcp-Session-Id: clients discover a server with server/discover, every request carries its protocol version, and multi-round-trip results replace server-initiated requests. Builders point out that stateless servers run behind a normal load balancer. Adoption is early: one survey of 26,000 public remote servers found about 3% on the new revision, and developers report clients differing on which revision they ask for, so servers answer both for now. Practice: Serve both revisions during the migration, and probe the server with an opening server/discover, an unknown version and a multi-round-trip tool call before shipping. - Source: MCP specification 2026-07-28: changelog, https://modelcontextprotocol.io/specification/2026-07-28/changelog (2026-10-17) - Source: @mohabbuilds: stateless MCP runs behind a normal load balancer, https://x.com/mohabbuilds/status/2107485248351064089 (2026-10-06) - Source: @McpMetrics: about 3% of 26k remote servers on 2026-07-28, https://x.com/McpMetrics/status/2108302356836200562 (2026-10-08) - Source: @duggalgg: one server, two revisions, for a while, https://x.com/duggalgg/status/2109359944931885099 (2026-10-11) - Loadouts: mcp-2026-07-28-migration (https://setupbay.com/loadouts/mcp-2026-07-28-migration/), mcp-server-python (https://setupbay.com/loadouts/mcp-server-python/), mcp-server-typescript (https://setupbay.com/loadouts/mcp-server-typescript/), mcp-server-go (https://setupbay.com/loadouts/mcp-server-go/) ### Skills and plugins get vetted like dependencies (as of 2026-10-11) After Plugin4Shell, practitioners describe skill bundles with shell access as a supply chain: pin the version, read what each skill can run and reach, and scan before install. NVIDIA's SkillSpector scans skill folders for risky patterns (v2.13.0 on 16 October), and Claude Code marketplaces accept a full commit SHA per plugin, with background auto-update off by default for third-party marketplaces. Practice: Install skills, plugins and MCP servers only after a pinned, reviewed scan; prove the checkout matches the pinned SHA and keep auto-update off for third-party sources. - Source: @SarahLakzit: a skill bundle with shell reach is a supply chain, https://x.com/SarahLakzit/status/2109274745585742114 (2026-10-11) - Source: @TheDailyViber: skills look like documentation, behave like supply chain, https://x.com/TheDailyViber/status/2102389962897248684 (2026-09-22) - Source: NVIDIA SkillSpector v2.13.0, https://github.com/NVIDIA/SkillSpector/releases/tag/v2.13.0 (2026-10-16) - Source: Claude Code docs: plugin marketplace reference, https://code.claude.com/docs/en/plugins/marketplace-reference (2026-10-17) - Loadouts: agent-extension-vetting (https://setupbay.com/loadouts/agent-extension-vetting/), github-actions-hardening (https://setupbay.com/loadouts/github-actions-hardening/) ### AGENTS.md is the shared contract; per-agent files stay thin (as of 2026-10-10) Claude Code reads AGENTS.md natively from v2.1.277, but only when no CLAUDE.md is on the path, so a stray CLAUDE.md now shadows it. Codex, Copilot and Cursor read AGENTS.md; Antigravity CLI reads GEMINI.md and AGENTS.md. Practice: Keep rules in AGENTS.md. Any CLAUDE.md or GEMINI.md should only import it (@AGENTS.md) plus genuine agent quirks. - Source: Claude Code docs, memory and AGENTS.md, https://code.claude.com/docs/en/memory (2026-10-16) - Source: @torfinpd: CLAUDE.md shadows AGENTS.md in 161 of 283 top repos, https://x.com/torfinpd/status/2108876607431553167 (2026-10-10) - Source: @mitsuhiko: AGENTS.md only, https://x.com/mitsuhiko/status/2088900774466105797 (2026-08-16) - Loadouts: one-agents-md-every-agent (https://setupbay.com/loadouts/one-agents-md-every-agent/), cursor-rules-that-load (https://setupbay.com/loadouts/cursor-rules-that-load/) ### Short always-on rules plus on-demand skills (as of 2026-10-10) Long instruction files are being split into Agent Skills that load only when needed. Cursor loads skills from .agents/skills and other agents' folders and offers /migrate-to-skills; pnpm 12.11 links skills shipped inside packages; vendors ship skills as plugins (Unity). Practice: Keep AGENTS.md short; move procedures longer than about 15 lines into .agents/skills//SKILL.md. - Source: Cursor docs, skills, https://cursor.com/docs/skills (2026-10-16) - Source: pnpm docs, agent skills, https://pnpm.io/agent-skills (2026-10-10) - Source: Unity agent plugin, https://github.com/Unity-Technologies/unity-agent-plugin (2026-10-16) - Loadouts: cursor-rules-that-load (https://setupbay.com/loadouts/cursor-rules-that-load/), unity-agent-plugin (https://setupbay.com/loadouts/unity-agent-plugin/) ### Agent loops go mainstream; the limits move outside the agent (as of 2026-10-09) Ralph-style loops are now built in: Claude Code's /goal re-runs turns until a separate small model judges a condition met, and Codex's /goal (0.128.0 and later) keeps a persistent objective across turns. Practitioners note that in-session loops and plugins keep one growing context, so for long jobs they still run a fresh process per pass with the check, iteration cap and stop file enforced by a script. Practice: Give every loop a check it cannot edit, an iteration and no-progress cap, its own branch and a human who merges; use /goal for shorter jobs. - Source: Claude Code docs: keep Claude working toward a goal, https://code.claude.com/docs/en/goal (2026-10-16) - Source: Codex 0.128.0 release notes: persisted /goal workflows, https://github.com/openai/codex/releases/tag/rust-v0.128.0 (2026-04-30) - Source: @DRMacIver: the Claude Ralph plugin didn't clear context between iterations, https://x.com/DRMacIver/status/2102456718915469473 (2026-09-22) - Source: @mitchalderson: /goal fires off a Ralph loop, https://x.com/mitchalderson/status/2108622371829518390 (2026-10-09) - Loadouts: ralph-loop-guarded (https://setupbay.com/loadouts/ralph-loop-guarded/) ### Hard rules move from prose into hooks and permissions (as of 2026-10-08) "Never do X" lines go into PreToolUse hooks that deny with a reason, and policy hooks fail closed with onFailure "block" (Claude Code v2.1.295). Only exit code 2 blocks; other non-zero exits do not. Deny rules are one layer, not a sandbox: Read denies do not stop shell reads. Practice: Enforce must-never rules with hooks or deny rules, test each by attempting the forbidden action, and keep a sandbox for real isolation. - Source: Claude Code docs, hooks reference, https://code.claude.com/docs/en/hooks (2026-10-16) - Source: @paulhq: only exit 2 blocks, https://x.com/paulhq/status/2100933039945912672 (2026-09-18) - Source: @coldboothq: deny rules are not a sandbox, https://x.com/coldboothq/status/2106519666885619942 (2026-10-03) - Loadouts: claude-code-hooks-guardrails (https://setupbay.com/loadouts/claude-code-hooks-guardrails/) ### Supply chain and injection are first-class concerns (as of 2026-10-08) Plugin4Shell (September 2026) bypassed marketplace pinning in several agents (fixed in Claude Code 2.1.179 and Codex 0.146.0). Codex ignores project AGENTS.md in untrusted folders. claude -p runs a repository's hooks without a trust prompt unless --bare is used, which Anthropic recommends for scripts. Practice: Pin CLIs, plugins and MCP packages, run CI agents with --bare and least privilege, and treat PR, issue and page text as data. - Source: Claude Code docs, headless mode, https://code.claude.com/docs/en/headless (2026-10-16) - Source: Codex docs, non-interactive mode, https://developers.openai.com/codex/noninteractive (2026-10-16) - Source: The Hacker News: Plugin4Shell, https://thehackernews.com/2026/09/plugin4shell-lets-repository-owners.html (2026-09-18) - Loadouts: headless-agents-ci (https://setupbay.com/loadouts/headless-agents-ci/), supabase-agent-safety (https://setupbay.com/loadouts/supabase-agent-safety/), agent-extension-vetting (https://setupbay.com/loadouts/agent-extension-vetting/), github-actions-hardening (https://setupbay.com/loadouts/github-actions-hardening/) ### SwiftUI logic moves into Swift packages tested on Linux (as of 2026-10-07) iOS developers working with agents keep the Xcode project out of reach and the logic in a local Swift package: the agent edits Packages/, Xcode imports it, and the package's tests run in seconds on Linux in the official swift Docker image, with only the SwiftUI views built on a macOS runner. Swift Testing ships with the toolchain on Linux, so the same tests run in both places. Practice: Put view models and logic in a Swift package with Swift Testing, run swift test on Linux CI, and build the views on macOS. - Source: @GameManiaSPX: move the logic into a local Swift package, https://x.com/GameManiaSPX/status/2107449164473029109 (2026-10-06) - Source: @muratnakmuay: package tests on Linux in swift:6.4, views on a macOS runner, https://x.com/muratnakmuay/status/2107796854264025581 (2026-10-07) - Source: Apple: Swift Testing documentation, https://developer.apple.com/documentation/testing (2026-10-17) - Loadouts: swiftui-swift-test-ci (https://setupbay.com/loadouts/swiftui-swift-test-ci/), ios-mobilebuildmcp (https://setupbay.com/loadouts/ios-mobilebuildmcp/) ### Handoff files replace compaction between sessions (as of 2026-10-06) Instead of letting long sessions compact, practitioners write a short handoff before clearing context or switching agents: the goal, files touched, decisions and why, the exact failing test and error, and one next step. Several commit it to the repository so a different agent, or a person, can resume, and note which MCP servers the work needs because the next agent may not have them. Practice: Write HANDOFF.md before /clear, compaction or a switch of agent, record the commit it describes, and re-run its checks before trusting it. - Source: @automater_ai: goal, files touched, done, next step, https://x.com/automater_ai/status/2107481727073395054 (2026-10-06) - Source: @calloway_dev: one owner per task; read the handoff before starting, https://x.com/calloway_dev/status/2107099970562085278 (2026-10-05) - Source: @agentjeanclaude: commit a handoff file when switching agents, https://x.com/agentjeanclaude/status/2104989005813260667 (2026-09-29) - Source: @PublicAI_: failing test and last error in every handoff, https://x.com/PublicAI_/status/2104179567510556875 (2026-09-27) - Loadouts: agent-handoff (https://setupbay.com/loadouts/agent-handoff/) ### Official MCP SDKs settle: Python v2 and Go v1.8 (as of 2026-10-02) The official Python SDK's v2 line renamed FastMCP to MCPServer, removed the old import path and added an in-memory Client for tests (2.3.0 on 2 October). The official Go SDK reached v1.8.0 on 14 September, generating tool schemas from Go structs. Agents trained on older examples still write the removed v1 imports. Practice: Pin the SDK version, name the current API in the agent's rules, and test every tool through the SDK's own client. - Source: MCP Python SDK docs: what's new in v2, https://py.sdk.modelcontextprotocol.io/whats-new/ (2026-10-17) - Source: mcp 2.3.0 on PyPI, https://pypi.org/project/mcp/2.3.0/ (2026-10-02) - Source: modelcontextprotocol/go-sdk v1.8.0, https://github.com/modelcontextprotocol/go-sdk/releases/tag/v1.8.0 (2026-09-14) - Loadouts: mcp-server-python (https://setupbay.com/loadouts/mcp-server-python/), mcp-server-go (https://setupbay.com/loadouts/mcp-server-go/) ### Subagent model and effort are chosen per task, in writing (as of 2026-10-01) Instruction files now tell the lead agent which model and effort each subagent gets by task class. Claude Code subagents take model and effort in front matter; Codex custom agents take model and model_reasoning_effort in TOML. Practice: Route mechanical work to small models at low effort, keep judgement work on the strongest model, and brief every subagent fully. - Source: Claude Code docs, subagents, https://code.claude.com/docs/en/sub-agents (2026-10-16) - Source: Codex docs, subagents, https://developers.openai.com/codex/subagents (2026-10-16) - Source: @chrisbanes: subagent model and reasoning selection (gist), https://gist.github.com/chrisbanes/dc1407ddd22d6e8d6c4d374b564eac9a (2026-10-01) - Loadouts: subagent-model-routing (https://setupbay.com/loadouts/subagent-model-routing/) ### Frameworks ship their own agent skills and MCP servers (as of 2026-09-23) Framework and tool makers now publish version-matched agent context themselves: Phaser 4 ships agent skills inside its npm package, Expo has an official plugin for Claude Code and Codex and opened its hosted MCP server to the Free plan, and Sentry's XcodeBuildMCP was renamed MobileBuildMCP (npm mobilebuildmcp, 23 September). Practice: Point the agent at the framework's own skills or MCP server for the installed version instead of relying on model memory and old tutorials. - Source: phaserjs/phaser: skills folder, https://github.com/phaserjs/phaser/tree/master/skills (2026-10-16) - Source: Expo changelog: Expo MCP server on the Free plan, https://expo.dev/changelog/the-expo-mcp-server-is-now-available-on-the-free-plan (2026-05-26) - Source: getsentry/MobileBuildMCP (formerly XcodeBuildMCP), https://github.com/getsentry/XcodeBuildMCP (2026-09-23) - Source: @KhalidDevLog: daily mobile MCPs, https://x.com/KhalidDevLog/status/2096183096697586039 (2026-09-05) - Loadouts: phaser-web-game (https://setupbay.com/loadouts/phaser-web-game/), expo-react-native (https://setupbay.com/loadouts/expo-react-native/), ios-mobilebuildmcp (https://setupbay.com/loadouts/ios-mobilebuildmcp/) ### Gemini CLI gives way to Antigravity CLI (as of 2026-06-18) Google announced the move on 19 May 2026; Gemini CLI stopped serving individual Google accounts on 18 June 2026 (enterprise and API-key use continue). Antigravity CLI keeps GEMINI.md, reads workspace skills from .agents/skills/ and MCP servers from .agents/mcp_config.json, where remote servers use serverUrl. Practice: Move workspace skills from .gemini/skills/ to .agents/skills/ and MCP servers into .agents/mcp_config.json. - Source: Antigravity CLI: migrating from Gemini CLI, https://antigravity.google/docs/cli/gcli-migration/ (2026-10-16) - Source: Google Developers Blog: transitioning Gemini CLI to Antigravity CLI, https://developers.googleblog.com/an-important-update-transitioning-gemini-cli-to-antigravity-cli/ (2026-05-19) - Loadouts: one-agents-md-every-agent (https://setupbay.com/loadouts/one-agents-md-every-agent/) ## Claude Code hooks guard rails (`claude-code-hooks-guardrails` v1.0.0) Fail-closed PreToolUse, post-edit and Stop hooks that block force-pushes, .env reads and wild deletes, check each edit and run tests before done. - URL: https://setupbay.com/loadouts/claude-code-hooks-guardrails/ - JSON: https://setupbay.com/api/loadouts/claude-code-hooks-guardrails.json - Categories: workflow, security - Stacks: bash, jq - Licence: MIT - First listed: 2026-10-17; updated: 2026-10-17 - Verified install (Level 1): verified (checked 2026-10-19; 9 passed, 0 failed, 1 not applicable) - Agent tests: untested - Last checked: 2026-10-17 - Credits: @AlexRusin: two-tier hooks and stop_hook_active (https://x.com/AlexRusin/status/2103535255357391289); @paulhq: only exit 2 blocks; test a hook by trying the forbidden thing (https://x.com/paulhq/status/2100933039945912672); @coldboothq: Read deny rules are not a sandbox (https://x.com/coldboothq/status/2106519666885619942); Claude Code hooks reference (https://code.claude.com/docs/en/hooks) ### Install paths - `AGENTS.md` (instructions): claude-code → AGENTS.md; codex → AGENTS.md; cursor → AGENTS.md; gemini-cli → AGENTS.md; antigravity-cli → AGENTS.md; copilot → AGENTS.md - `CLAUDE.md` (adapter): claude-code → CLAUDE.md - `GEMINI.md` (adapter): gemini-cli → GEMINI.md - `.cursor/rules/guard-rails.mdc` (rules): cursor → .cursor/rules/guard-rails.mdc - `skills/install-guard-hooks/SKILL.md` (skill): claude-code → .claude/skills/install-guard-hooks/SKILL.md; codex → .agents/skills/install-guard-hooks/SKILL.md; cursor → .agents/skills/install-guard-hooks/SKILL.md; gemini-cli → .agents/skills/install-guard-hooks/SKILL.md; antigravity-cli → .agents/skills/install-guard-hooks/SKILL.md; copilot → .agents/skills/install-guard-hooks/SKILL.md - `skills/install-guard-hooks/scripts/guard-bash.sh` (reference): claude-code → .claude/skills/install-guard-hooks/scripts/guard-bash.sh; codex → .agents/skills/install-guard-hooks/scripts/guard-bash.sh; cursor → .agents/skills/install-guard-hooks/scripts/guard-bash.sh; gemini-cli → .agents/skills/install-guard-hooks/scripts/guard-bash.sh; antigravity-cli → .agents/skills/install-guard-hooks/scripts/guard-bash.sh; copilot → .agents/skills/install-guard-hooks/scripts/guard-bash.sh - `skills/install-guard-hooks/scripts/post-edit-check.sh` (reference): claude-code → .claude/skills/install-guard-hooks/scripts/post-edit-check.sh; codex → .agents/skills/install-guard-hooks/scripts/post-edit-check.sh; cursor → .agents/skills/install-guard-hooks/scripts/post-edit-check.sh; gemini-cli → .agents/skills/install-guard-hooks/scripts/post-edit-check.sh; antigravity-cli → .agents/skills/install-guard-hooks/scripts/post-edit-check.sh; copilot → .agents/skills/install-guard-hooks/scripts/post-edit-check.sh - `skills/install-guard-hooks/scripts/stop-gate.sh` (reference): claude-code → .claude/skills/install-guard-hooks/scripts/stop-gate.sh; codex → .agents/skills/install-guard-hooks/scripts/stop-gate.sh; cursor → .agents/skills/install-guard-hooks/scripts/stop-gate.sh; gemini-cli → .agents/skills/install-guard-hooks/scripts/stop-gate.sh; antigravity-cli → .agents/skills/install-guard-hooks/scripts/stop-gate.sh; copilot → .agents/skills/install-guard-hooks/scripts/stop-gate.sh - `skills/install-guard-hooks/scripts/selftest.sh` (reference): claude-code → .claude/skills/install-guard-hooks/scripts/selftest.sh; codex → .agents/skills/install-guard-hooks/scripts/selftest.sh; cursor → .agents/skills/install-guard-hooks/scripts/selftest.sh; gemini-cli → .agents/skills/install-guard-hooks/scripts/selftest.sh; antigravity-cli → .agents/skills/install-guard-hooks/scripts/selftest.sh; copilot → .agents/skills/install-guard-hooks/scripts/selftest.sh - `skills/install-guard-hooks/references/settings.example.json` (reference): claude-code → .claude/skills/install-guard-hooks/references/settings.example.json; codex → .agents/skills/install-guard-hooks/references/settings.example.json; cursor → .agents/skills/install-guard-hooks/references/settings.example.json; gemini-cli → .agents/skills/install-guard-hooks/references/settings.example.json; antigravity-cli → .agents/skills/install-guard-hooks/references/settings.example.json; copilot → .agents/skills/install-guard-hooks/references/settings.example.json - `skills/install-guard-hooks/references/permissions.md` (reference): claude-code → .claude/skills/install-guard-hooks/references/permissions.md; codex → .agents/skills/install-guard-hooks/references/permissions.md; cursor → .agents/skills/install-guard-hooks/references/permissions.md; gemini-cli → .agents/skills/install-guard-hooks/references/permissions.md; antigravity-cli → .agents/skills/install-guard-hooks/references/permissions.md; copilot → .agents/skills/install-guard-hooks/references/permissions.md ### File: AGENTS.md ```markdown # AGENTS.md: hooks and permissions guard rails This project enforces its hard rules with hooks and permission rules, not with prose. Prose in this file guides you; the hooks decide. Follow both. ## When a hook blocks you - A blocked tool call comes back with a reason. Read it, then change approach. Do not retry the same command with different spelling, quoting, an env-var prefix, `sh -c`, a script file or another tool to get past it. - If the block looks wrong for this task, stop and tell the human what you tried and the reason you got. Only a human edits the hook scripts or `.claude/settings.json`. - A Stop hook that reports failing checks means you are not done. Fix the cause, not the check. ## Never, even if a hook would let it through - Rewrite shared history: no `git push --force` to `main`/`master`, no `git reset --hard` on work you did not create. - Skip verification: no `--no-verify`, no deleting or skipping tests to get green. - Read or print secrets: `.env`, `.env.*` (except `.env.example`), key files, tokens in shell history. - Delete outside the project folder, or delete the project folder itself. - Run migrations, `DROP`, `TRUNCATE` or bulk `DELETE` against a database the human has not named as disposable. ## Keep the loop fast - After each edit, the post-edit hook runs a quick check on the file you touched (syntax, lint or typecheck). Fix what it reports before moving to the next file. - The full test suite runs once when you finish. Do not run it after every small edit unless the human asks. ## Changing the guard rails - Use the `install-guard-hooks` skill to install, update or extend the hooks. - Every new block needs a test: try the forbidden action once and confirm it is denied with a clear reason. ``` ### File: CLAUDE.md ```markdown # CLAUDE.md @AGENTS.md ## Claude Code notes - Skills from this loadout live in `.claude/skills/`: `install-guard-hooks`. Use them when their description matches the task. - Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins. ``` ### File: GEMINI.md ```markdown # GEMINI.md @./AGENTS.md ## Gemini CLI notes - Skills from this loadout live in `.agents/skills/`: `install-guard-hooks`. Use them when their description matches the task. - Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins. ``` ### File: .cursor/rules/guard-rails.mdc ```markdown --- description: Hard limits that hooks enforce in Claude Code and Codex; Cursor must follow them by hand alwaysApply: true --- - No force-push to `main`/`master`, no `git reset --hard` on others' work, no `--no-verify`. - Never read or print `.env` / `.env.*` (except `.env.example`), keys or tokens. - Never delete outside the project folder. Never drop, truncate or bulk-delete a database the human has not called disposable. - If a command is refused, report the reason to the human. Do not rephrase the command to get it through. ``` ### File: skills/install-guard-hooks/SKILL.md ```markdown --- name: install-guard-hooks description: Install, update or test the project's guard-rail hooks for Claude Code (and Codex). Use when asked to add hooks, block dangerous commands, run tests before finishing, or when a hook misbehaves. --- # Install guard hooks Installs three hooks and the matching permission rules, then proves each block works. Requires `bash` and `jq` on the machine that runs the agent. | Hook | Event | What it does | |---|---|---| | `scripts/guard-bash.sh` | PreToolUse, Bash | Denies force-push, `reset --hard`, `clean -f`, `--no-verify`, `.env` access, recursive deletes outside the project, DROP/TRUNCATE/unbounded DELETE, download-piped-to-shell. Prints a reason. | | `scripts/post-edit-check.sh` | PostToolUse, Edit/Write | Fast check of the edited file: `bash -n`, `jq empty`, ruff or py_compile, eslint or `node --check`. Exit 2 shows the error to the agent. | | `scripts/stop-gate.sh` | Stop | Runs the test command once if the tree has changes. Exit 2 keeps the agent working. Skips when `stop_hook_active` is true. | ## Install (Claude Code) 1. Copy the three scripts from this skill's `scripts/` folder to `.claude/hooks/` and make them executable: `mkdir -p .claude/hooks && cp /scripts/{guard-bash,post-edit-check,stop-gate}.sh .claude/hooks/ && chmod +x .claude/hooks/*.sh` 2. Merge `references/settings.example.json` into `.claude/settings.json`. Keep existing keys; append to existing `permissions.deny` and `hooks` arrays rather than replacing them. Validate with `jq empty .claude/settings.json`. 3. If the test command is not `npm test`, `pytest -q`, `cargo test -q` or `go test ./...`, write it on one line in `.claude/hooks/test-command`. 4. Tell the human to run `/hooks` and confirm the three hooks are listed with source "project settings". ## Install (Codex) Codex hooks are user-level. Show the human the PreToolUse block from `references/settings.example.json`, adapted for `~/.codex/hooks.json` with an absolute script path, and let them add it. Do not edit files in their home folder yourself. ## Prove it 1. Run `bash /scripts/selftest.sh`. It must print `ok:`. 2. In a live session, attempt one forbidden action (for example `git push --force origin scratch`). It must be denied with a reason that starts "Blocked by guard-bash". A hook you have not seen block something is not installed. 3. Report which checks were verified and which were skipped (for example, no eslint in the project). ## Extend - Add a rule to `guard-bash.sh` as a `deny ""` line, then add a deny and an allow case to `selftest.sh`. - Reasons must say what to do instead. The agent reads them. - Keep the post-edit check under a few seconds. Slow checks belong in the Stop gate. - Read `references/permissions.md` before changing permission rules: deny beats allow, exit 1 does not block, and deny rules alone are not a sandbox. ``` ### File: skills/install-guard-hooks/scripts/guard-bash.sh ```markdown #!/usr/bin/env bash # PreToolUse hook for the Bash tool (Claude Code; Codex hooks use the same JSON shape). # Reads the tool call as JSON on stdin. Prints a "deny" decision with a reason, or nothing to defer # to the normal permission flow. Needs jq. Register it with onFailure "block" so a crash fails closed. set -u input=$(cat) cmd=$(printf '%s' "$input" | jq -r '.tool_input.command // empty') [ -z "$cmd" ] && exit 0 project="${CLAUDE_PROJECT_DIR:-$(printf '%s' "$input" | jq -r '.cwd // empty')}" project="${project%/}" flat=$(printf '%s' "$cmd" | tr '\n\t' ' ') lower=$(printf '%s' "$flat" | tr '[:upper:]' '[:lower:]') deny() { jq -n --arg r "Blocked by guard-bash: $1" \ '{hookSpecificOutput: {hookEventName: "PreToolUse", permissionDecision: "deny", permissionDecisionReason: $r}}' exit 0 } # 1. Shared git history and skipped checks. if [[ "$lower" =~ git[[:space:]].*push ]]; then if [[ "$lower" =~ --force([[:space:]]|$) || "$lower" =~ [[:space:]]-[a-z]*f([[:space:]]|$) || "$lower" =~ [[:space:]]\+[a-z0-9/_.-]+ ]]; then deny "force-push rewrites shared history. Push a new commit, or ask the human." fi if [[ "$lower" =~ --force-with-lease && "$lower" =~ (^|[[:space:]:/])(main|master)([[:space:]]|$) ]]; then deny "force-push to main/master. Ask the human." fi fi [[ "$lower" =~ git[[:space:]]+reset[[:space:]].*--hard ]] && deny "git reset --hard discards work. Use git stash or a new branch, or ask the human." [[ "$lower" =~ git[[:space:]]+clean[[:space:]]+-[a-z]*f ]] && deny "git clean -f deletes untracked files. List them with git clean -n and ask the human." [[ "$lower" =~ --no-verify ]] && deny "--no-verify skips the project's checks. Fix what the checks report." # 2. Secrets. .env.example / .sample / .template are fine. if [[ "$flat" =~ (^|[[:space:]/=\'\"])\.env(\.[A-Za-z0-9_-]+)?([[:space:]\'\";|]|$) ]]; then m="${BASH_REMATCH[0]}" [[ "$m" =~ \.env\.(example|sample|template) ]] || deny "commands may not touch .env files; they hold secrets. Use .env.example for names." fi # 3. Recursive deletes outside the project, of the project itself, or via ~, $HOME or .. read -r -a words <<< "$flat" in_rm=0; recursive=0; targets=() for w in "${words[@]}"; do case "$w" in rm|*/rm) in_rm=1; recursive=0; continue ;; ';'|'&&'|'||'|'|') in_rm=0; continue ;; esac [ "$in_rm" = 1 ] || continue if [[ "$w" == -* ]]; then [[ "$w" =~ ^-[a-zA-Z]*[rR] || "$w" == "--recursive" ]] && recursive=1; continue; fi [ "$recursive" = 1 ] && targets+=("$w") done for t in "${targets[@]:-}"; do [ -z "$t" ] && continue t="${t%\"}"; t="${t#\"}"; t="${t%\'}"; t="${t#\'}" case "$t" in '~'*|'$HOME'*|'${HOME}'*) deny "recursive delete under the home directory ($t)." ;; *..*) deny "recursive delete with .. in the path ($t). Use a path inside the project." ;; .|./|'*'|./'*') deny "recursive delete of the whole project folder ($t)." ;; /*) if [ -z "$project" ] || [[ "$t" != "$project"/* ]]; then deny "recursive delete outside the project ($t)."; fi ;; esac done # 4. Destructive SQL from the shell. if [[ "$lower" =~ (drop[[:space:]]+(table|database|schema)|truncate[[:space:]]+) ]]; then deny "DROP/TRUNCATE from the shell. Write a migration file and ask the human to run it." fi if [[ "$lower" =~ delete[[:space:]]+from[[:space:]] && ! "$lower" =~ [[:space:]]where[[:space:]] ]]; then deny "DELETE without WHERE. Add a WHERE clause or ask the human." fi # 5. Downloaded code piped straight into a shell. if [[ "$lower" =~ (curl|wget)[^\|]*\|[[:space:]]*(sudo[[:space:]]+)?(ba|z|da)?sh([[:space:]]|$) ]]; then deny "piping a download into a shell. Download, read, then run it, or ask the human." fi exit 0 ``` ### File: skills/install-guard-hooks/scripts/post-edit-check.sh ```markdown #!/usr/bin/env bash # PostToolUse hook for Edit|Write: a fast check on the one file that changed. # Exit 2 sends stderr back to the agent so it fixes the file before moving on. Missing tools are skipped. set -u input=$(cat) file=$(printf '%s' "$input" | jq -r '.tool_input.file_path // .tool_input.path // empty') [ -n "$file" ] && [ -f "$file" ] || exit 0 have() { command -v "$1" >/dev/null 2>&1; } root="${CLAUDE_PROJECT_DIR:-$PWD}" out="" case "$file" in *.sh|*.bash) out=$(bash -n "$file" 2>&1) ;; *.json) if have jq; then out=$(jq empty "$file" 2>&1); fi ;; *.py) if have ruff; then out=$(ruff check --quiet "$file" 2>&1) elif have python3; then out=$(python3 -m py_compile "$file" 2>&1); fi ;; *.ts|*.tsx|*.js|*.jsx|*.mjs|*.cjs) if [ -x "$root/node_modules/.bin/eslint" ]; then out=$("$root/node_modules/.bin/eslint" --no-warn-ignored "$file" 2>&1) elif [[ "$file" =~ \.(js|mjs|cjs)$ ]] && have node; then out=$(node --check "$file" 2>&1); fi ;; esac status=$? if [ $status -ne 0 ]; then printf 'post-edit check failed for %s:\n%s\n' "$file" "$(printf '%s' "$out" | tail -n 30)" >&2 exit 2 fi exit 0 ``` ### File: skills/install-guard-hooks/scripts/stop-gate.sh ```markdown #!/usr/bin/env bash # Stop hook: run the project's tests once when the agent says it is done. # Exit 2 keeps the agent working and shows it the failures. Respects stop_hook_active so it never loops. set -u input=$(cat) [ "$(printf '%s' "$input" | jq -r '.stop_hook_active // false')" = "true" ] && exit 0 root="${CLAUDE_PROJECT_DIR:-$(printf '%s' "$input" | jq -r '.cwd // empty')}" cd "${root:-.}" || exit 0 git rev-parse --is-inside-work-tree >/dev/null 2>&1 || exit 0 [ -z "$(git status --porcelain 2>/dev/null)" ] && exit 0 # nothing changed, nothing to gate test_cmd="${GUARD_TEST_CMD:-}" [ -z "$test_cmd" ] && [ -f .claude/hooks/test-command ] && test_cmd=$(head -n 1 .claude/hooks/test-command) if [ -z "$test_cmd" ]; then if [ -f package.json ] && jq -e '.scripts.test' package.json >/dev/null 2>&1; then test_cmd="npm test --silent" elif [ -f pyproject.toml ] && command -v pytest >/dev/null 2>&1; then test_cmd="pytest -q" elif [ -f Cargo.toml ]; then test_cmd="cargo test -q" elif [ -f go.mod ]; then test_cmd="go test ./..." else exit 0; fi fi runner=(bash -c "$test_cmd") command -v timeout >/dev/null 2>&1 && runner=(timeout "${GUARD_TEST_TIMEOUT:-600}" bash -c "$test_cmd") if ! out=$("${runner[@]}" 2>&1); then printf 'Tests failed (%s). You are not done; fix the cause:\n%s\n' "$test_cmd" "$(printf '%s' "$out" | tail -n 40)" >&2 exit 2 fi exit 0 ``` ### File: skills/install-guard-hooks/scripts/selftest.sh ```markdown #!/usr/bin/env bash # Self-test for the guard hooks. Feeds sample hook input to each script and checks the decision. # Run from anywhere: bash path/to/scripts/selftest.sh Prints "ok: N cases" or the first failures. set -u here="$(cd "$(dirname "$0")" && pwd)" tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT export CLAUDE_PROJECT_DIR="$tmp/project"; mkdir -p "$CLAUDE_PROJECT_DIR" fails=0; n=0 bash_call() { jq -nc --arg c "$1" --arg d "$CLAUDE_PROJECT_DIR" '{hook_event_name:"PreToolUse",tool_name:"Bash",cwd:$d,tool_input:{command:$c}}'; } expect_guard() { # expect_guard deny|allow "command" n=$((n+1)) out=$(bash_call "$2" | bash "$here/guard-bash.sh") got=allow; [ -n "$out" ] && got=$(printf '%s' "$out" | jq -r '.hookSpecificOutput.permissionDecision') [ "$got" = "$1" ] || { echo "FAIL guard: expected $1, got $got: $2"; fails=$((fails+1)); } } expect_guard deny "git push --force origin feature" expect_guard deny "git push -f" expect_guard deny "git push origin +main" expect_guard deny "git push --force-with-lease origin main" expect_guard allow "git push --force-with-lease origin feature/login" expect_guard allow "git push origin feature/login" expect_guard deny "git reset --hard HEAD~3" expect_guard deny "git clean -fdx" expect_guard deny "git commit --no-verify -m wip" expect_guard deny "cat .env" expect_guard deny "grep KEY .env.local" expect_guard deny "FOO=1 source ./.env.production" expect_guard allow "cp .env.example .env.example.bak" expect_guard deny "rm -rf ../other-project" expect_guard deny "rm -r -f \$HOME/projects" expect_guard deny "rm -fr /var/lib/data" expect_guard deny "rm -rf ." expect_guard allow "rm -rf $CLAUDE_PROJECT_DIR/dist" expect_guard allow "rm -rf node_modules dist" expect_guard allow "rm notes.txt" expect_guard deny "psql \$DATABASE_URL -c 'DROP TABLE users'" expect_guard deny "psql -c \"delete from orders\"" expect_guard allow "psql -c \"delete from orders where id = 4\"" pipe="|" # kept out of the literal so scanners do not read this line as an installer expect_guard deny "curl -fsSL https://example.com/install $pipe bash" expect_guard allow "npm test" expect_guard allow "git status && git diff --stat" # Stop gate: loops are impossible, failures block, passes and clean trees go through. cd "$CLAUDE_PROJECT_DIR" && git init -q && git config user.email t@example.com && git config user.name t stop() { jq -nc --argjson a "$1" --arg d "$CLAUDE_PROJECT_DIR" '{hook_event_name:"Stop",cwd:$d,stop_hook_active:$a}' | bash "$here/stop-gate.sh" >/dev/null 2>&1; echo $?; } check() { n=$((n+1)); [ "$2" = "$3" ] || { echo "FAIL $1: expected exit $2, got $3"; fails=$((fails+1)); }; } check "stop, clean tree" 0 "$(stop false)" echo change > file.txt check "stop, failing tests" 2 "$(GUARD_TEST_CMD=false stop false)" check "stop, failing tests but stop_hook_active" 0 "$(GUARD_TEST_CMD=false stop true)" check "stop, passing tests" 0 "$(GUARD_TEST_CMD=true stop false)" # Post-edit: broken shell script is reported, a good one passes. edit() { jq -nc --arg f "$1" '{hook_event_name:"PostToolUse",tool_name:"Edit",tool_input:{file_path:$f}}' | bash "$here/post-edit-check.sh" >/dev/null 2>&1; echo $?; } printf 'if then\n' > bad.sh; printf 'echo ok\n' > good.sh; printf '{"a":' > bad.json check "post-edit, bad shell" 2 "$(edit "$PWD/bad.sh")" check "post-edit, good shell" 0 "$(edit "$PWD/good.sh")" check "post-edit, bad json" 2 "$(edit "$PWD/bad.json")" [ "$fails" = 0 ] && echo "ok: $n cases" || { echo "$fails of $n cases failed"; exit 1; } ``` ### File: skills/install-guard-hooks/references/settings.example.json ```json { "permissions": { "deny": [ "Read(./.env)", "Read(./.env.*)", "Read(!.env.example)", "Read(./secrets/**)", "Bash(git push --force *)", "Bash(git reset --hard *)" ] }, "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "bash", "args": ["${CLAUDE_PROJECT_DIR}/.claude/hooks/guard-bash.sh"], "onFailure": "block", "statusMessage": "Checking command against guard rails" } ] } ], "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "bash", "args": ["${CLAUDE_PROJECT_DIR}/.claude/hooks/post-edit-check.sh"], "timeout": 60 } ] } ], "Stop": [ { "hooks": [ { "type": "command", "command": "bash", "args": ["${CLAUDE_PROJECT_DIR}/.claude/hooks/stop-gate.sh"], "timeout": 900 } ] } ] } } ``` ### File: skills/install-guard-hooks/references/permissions.md ```markdown # Permissions and hooks: what actually holds (Claude Code, October 2026) Facts from the Claude Code permissions and hooks reference. Check `claude --version` before relying on a version-gated item. ## Order of evaluation - Deny rules beat allow rules. An allow rule cannot carve an exception out of a deny rule. - A PreToolUse hook that denies, or exits 2, blocks the call even if an allow rule matches. - A hook that returns "allow" does not bypass a matching deny or ask rule. - Exception: an installed mod that handles `tool.check` answers after rules and hooks and can replace their answer. Review mods before installing them; a mod can switch your guard rails off. ## Exit codes - Exit 0: success. JSON on stdout is applied. - Exit 2: blocking error. stderr is the reason shown to the agent. - Any other exit code: non-blocking error. The tool call goes ahead. Do not use `exit 1` to enforce a policy. - `onFailure: "block"` (v2.1.295+) makes a crash, a missing script, invalid JSON or a timeout block the call. Use it on every policy hook. It has no effect on Stop hooks. ## Matching - Deny and ask rules match past any leading `VAR=value` assignment (fixed in v2.1.289). - Allow rules only skip a short built-in list of safe variables, so `FOO=bar npm test` is not covered by `Bash(npm test *)`. - Environment runners (`npx`, `docker exec`, `devbox run`, `mise exec`) run whatever follows them. Allow the exact inner command. - Hook `if` filters are best-effort. Enforce hard rules with permission rules or with a hook that inspects the whole command. ## Deny rules are not a sandbox - `Read(./.env)` stops the Read tool. A shell command, a script, or an `@import` can still reach the file. Pair Read deny rules with the Bash guard hook, and with the sandbox's denied read paths where available. - Cover `.env`, `.env.*` and any secrets folder. Carve out `.env.example` with a `!` rule in the same file. ## Settings files merge - Permission rules merge across user, project and local settings. An allow rule in `~/.claude/settings.json` applies in every repo. - Hooks merge too; the same handler defined twice runs once. - Project `.claude/settings.json` hooks run in `claude -p` sessions without a trust prompt. Use `--bare` for scripted runs in repos you do not control. ## Stop hooks - The Stop input has `stop_hook_active: true` when the agent is already continuing because of a Stop hook. Exit 0 then, or the agent can loop. - Claude Code also caps consecutive Stop-hook continuations at 8. ## Codex - Codex reads hooks from `~/.codex/hooks.json` or a `[hooks]` table in `~/.codex/config.toml`, with the same event names. - A PreToolUse hook blocks with exit 2 or `permissionDecision: "deny"`. Test the Bash input shape with one harmless call before relying on it. ``` ## Discord bot (TypeScript) (`discord-bot-ts` v1.1.0) discord.js v14 rules and an add-a-slash-command skill for building a Discord bot that registers commands properly and never leaks its token. - URL: https://setupbay.com/loadouts/discord-bot-ts/ - JSON: https://setupbay.com/api/loadouts/discord-bot-ts.json - Categories: bots - Stacks: discord, nodejs, typescript - Licence: MIT - First listed: 2026-10-15; updated: 2026-10-16 - Verified install (Level 1): verified (checked 2026-10-19; 9 passed, 0 failed, 1 not applicable) - Agent tests: untested - Last checked: 2026-10-16 - Needs env: DISCORD_TOKEN, DISCORD_CLIENT_ID, DISCORD_GUILD_ID ### Install paths - `AGENTS.md` (instructions): claude-code → AGENTS.md; codex → AGENTS.md; cursor → AGENTS.md; gemini-cli → AGENTS.md; antigravity-cli → AGENTS.md; copilot → AGENTS.md - `CLAUDE.md` (adapter): claude-code → CLAUDE.md - `GEMINI.md` (adapter): gemini-cli → GEMINI.md - `.cursor/rules/discord-commands.mdc` (rules): cursor → .cursor/rules/discord-commands.mdc - `skills/add-slash-command/SKILL.md` (skill): claude-code → .claude/skills/add-slash-command/SKILL.md; codex → .agents/skills/add-slash-command/SKILL.md; cursor → .agents/skills/add-slash-command/SKILL.md; gemini-cli → .agents/skills/add-slash-command/SKILL.md; antigravity-cli → .agents/skills/add-slash-command/SKILL.md; copilot → .agents/skills/add-slash-command/SKILL.md ### File: AGENTS.md ````markdown # AGENTS.md: Discord bot (TypeScript, discord.js v14) ## Layout ``` src/ index.ts creates the Client, loads commands and events, logs in deploy-commands.ts registers slash commands with Discord (run by hand, not on every start) commands/.ts one slash command per file: exports `data` (SlashCommandBuilder) and `execute(interaction)` events/.ts one gateway event per file: exports `name`, `once?`, `execute(...)` lib/ shared helpers (embeds, db, permissions) ``` Run with `npm run dev` (tsx watch) locally. `npm run deploy` runs `deploy-commands.ts`. ## Command file shape Each file in `src/commands/` exports `data` and `execute`, nothing else: ```ts import { SlashCommandBuilder, type ChatInputCommandInteraction } from "discord.js"; export const data = new SlashCommandBuilder() .setName("roll") // lowercase, 1–32 chars, no spaces .setDescription("Roll a dice") // required, 1–100 chars .addIntegerOption((o) => o.setName("sides").setDescription("Number of sides").setMinValue(2).setMaxValue(1000)); export async function execute(interaction: ChatInputCommandInteraction) { const sides = interaction.options.getInteger("sides") ?? 6; const result = 1 + Math.floor(Math.random() * sides); await interaction.reply({ content: `🎲 ${result} (d${sides})` }); } ``` ## Token and secrets - `DISCORD_TOKEN`, `DISCORD_CLIENT_ID`, `DISCORD_GUILD_ID` come from `.env` (git-ignored). `.env.example` lists them with dummy values. - Never print the token, commit it, or paste it into an embed or error message. If it leaks, the human must reset it in the Developer Portal → Bot → Reset Token. Discord also auto-revokes tokens it finds in public repos. ## Intents - Request the minimum: `GatewayIntentBits.Guilds` covers slash commands. - `GuildMembers`, `GuildPresences` and `MessageContent` are **privileged**: they must be switched on in the Developer Portal and are reviewed once a bot is in 100+ servers. Prefer slash commands over reading message content. ## Interactions - Discord gives you **3 seconds** to respond. If work might take longer (API calls, database, AI), call `await interaction.deferReply()` first, then `await interaction.editReply(...)`. - Private replies: `interaction.reply({ content, flags: MessageFlags.Ephemeral })`. (`ephemeral: true` is deprecated.) - Every `execute` is wrapped by the loader in try/catch. On error: log it, then reply or follow up with a short ephemeral "Something went wrong" — never the stack trace. - Check permissions for moderation commands with `.setDefaultMemberPermissions(...)` on the builder *and* re-check in code. - Validate options: string lengths, number ranges (`.setMinValue/.setMaxValue`), and never pass user text into shell commands or eval. ## Registering commands - During development register to one guild (`Routes.applicationGuildCommands(clientId, guildId)`) — updates are instant. - Global registration (`Routes.applicationCommands(clientId)`) is for release. Do not register on every bot start; there are rate limits. - After changing a command's `data`, remind the human to run `npm run deploy`. ## Style - TypeScript strict, ES modules, `async/await`. No `any` on interaction types: use `ChatInputCommandInteraction`. - Keep command files small; move logic into `lib/` when two commands share it. - Rate-limit costly commands per user (a simple in-memory cooldown map is fine to start). ## Before you say "done" `npm run build` (tsc) passes, the new command is in `commands/`, and you have told the human whether to re-run deploy. ```` ### File: CLAUDE.md ```markdown # CLAUDE.md @AGENTS.md ## Claude Code notes - Skills from this loadout live in `.claude/skills/`: `add-slash-command`. Use them when their description matches the task. - Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins. ``` ### File: GEMINI.md ```markdown # GEMINI.md @./AGENTS.md ## Gemini CLI notes - Skills from this loadout live in `.agents/skills/`: `add-slash-command`. Use them when their description matches the task. - Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins. ``` ### File: .cursor/rules/discord-commands.mdc ````markdown --- description: Shape of a discord.js v14 slash command file globs: src/commands/**/*.ts alwaysApply: false --- Each file exports `data` and `execute`, nothing else: ```ts import { SlashCommandBuilder, MessageFlags, type ChatInputCommandInteraction } from "discord.js"; export const data = new SlashCommandBuilder() .setName("roll") // lowercase, 1–32 chars, no spaces .setDescription("Roll a dice") // required, 1–100 chars .addIntegerOption((o) => o.setName("sides").setDescription("Number of sides").setMinValue(2).setMaxValue(1000)); export async function execute(interaction: ChatInputCommandInteraction) { const sides = interaction.options.getInteger("sides") ?? 6; const result = 1 + Math.floor(Math.random() * sides); await interaction.reply({ content: `🎲 ${result} (d${sides})` }); } ``` - If `execute` awaits anything slow, `deferReply()` first and `editReply()` after. - Use `flags: MessageFlags.Ephemeral` for private replies, not `ephemeral: true`. - Required options must be added before optional ones. - Do not register commands from here; that is `src/deploy-commands.ts`. ```` ### File: skills/add-slash-command/SKILL.md ```markdown --- name: add-slash-command description: Add a new slash command to a discord.js v14 bot, register it and document it. Use when the user asks for a new bot command, e.g. "add a /poll command". --- # Add a slash command 1. **Clarify in one line** if needed: command name, options (name, type, required?), who can use it, public or private reply. Otherwise choose sensible defaults and state them. 2. **Check the name is free:** look in `src/commands/` and in the `data.setName(...)` calls. 3. **Create `src/commands/.ts`** following the command file shape in AGENTS.md: - `SlashCommandBuilder` with name, description, typed options with limits. - Moderation or admin commands: `.setDefaultMemberPermissions(PermissionFlagsBits.)` and `.setContexts(InteractionContextType.Guild)` so they cannot run in DMs. - `execute`: validate, `deferReply()` if anything is slow, do the work, reply. - Handle the expected failures (missing permission, bad input, external API down) with a friendly ephemeral message. 4. **Check the loader** in `src/index.ts` picks up new files automatically. If commands are listed by hand, add it there and in `deploy-commands.ts`. 5. **Type-check:** `npm run build` or `npx tsc --noEmit`. 6. **Register:** tell the human to run `npm run deploy` (guild registration is instant). Only run it yourself if they ask and `.env` is already set up — it uses the bot token. 7. **Document:** add the command to the commands table in `README.md` (name, options, who can use it). 8. **Report:** the file created, the command signature (`/poll question: duration:`), and how to try it. ``` ## Godot 4 game jam (`godot-4-game-jam` v1.0.0) GDScript conventions, jam-scope discipline and a ship-to-itch.io skill so your agent helps you finish a Godot 4 game in 48 hours. - URL: https://setupbay.com/loadouts/godot-4-game-jam/ - JSON: https://setupbay.com/api/loadouts/godot-4-game-jam.json - Categories: gamedev - Stacks: godot, gdscript - Licence: MIT - First listed: 2026-10-15; updated: 2026-10-15 - Verified install (Level 1): verified (checked 2026-10-19; 9 passed, 0 failed, 1 not applicable) - Agent tests: untested - Last checked: 2026-10-15 - Needs env: BUTLER_API_KEY ### Install paths - `AGENTS.md` (instructions): claude-code → AGENTS.md; codex → AGENTS.md; cursor → AGENTS.md; gemini-cli → AGENTS.md; antigravity-cli → AGENTS.md; copilot → AGENTS.md - `CLAUDE.md` (adapter): claude-code → CLAUDE.md - `GEMINI.md` (adapter): gemini-cli → GEMINI.md - `.cursor/rules/gdscript.mdc` (rules): cursor → .cursor/rules/gdscript.mdc - `skills/godot-jam-ship/SKILL.md` (skill): claude-code → .claude/skills/godot-jam-ship/SKILL.md; codex → .agents/skills/godot-jam-ship/SKILL.md; cursor → .agents/skills/godot-jam-ship/SKILL.md; gemini-cli → .agents/skills/godot-jam-ship/SKILL.md; antigravity-cli → .agents/skills/godot-jam-ship/SKILL.md; copilot → .agents/skills/godot-jam-ship/SKILL.md ### File: AGENTS.md ````markdown # AGENTS.md: Godot 4 game jam This is a Godot 4 project made for a game jam. Finishing beats polish. Polish beats features. ## Jam rules (follow these over any instinct to add things) 1. **Core loop first.** Until the game can be started, played, won or lost, and restarted, only work on that. 2. **Keep a cut list.** When the human asks for something big, offer the smallest version that sells the idea, and add the rest to `CUTLIST.md` instead of building it. 3. **Feature freeze** when the human says so (default: 75% of the way through the jam). After that: bugs, juice (screen shake, sound, particles), menus, and the build. Nothing new. 4. **Ship a build early.** Get a web export on itch.io (draft page) on day one so the final upload is boring. 5. Never refactor working code in the last few hours unless it fixes a crash. ## Project layout ``` scenes/ one folder per thing: player/, enemies/, ui/, levels/ (each .tscn next to its .gd) autoload/ global singletons (GameState, Audio) — keep these few and small assets/ art/, audio/, fonts/ — imported files, never edited by code ``` - Commit `.tscn`, `.tres`, `.gd`, `project.godot`, `export_presets.cfg` and the `*.uid` / `*.import` files. Ignore `.godot/` and build output. ## GDScript conventions (Godot 4) - Static typing everywhere: `var speed: float = 200.0`, `func take_damage(amount: int) -> void:`. Use `:=` when the type is obvious. - `snake_case` for files, functions and variables; `PascalCase` for `class_name` and nodes; `UPPER_SNAKE` for constants. - Use `@export` for tunable values so the human can tweak them in the inspector instead of asking you. - Use `@onready var sprite: Sprite2D = $Sprite2D` for child references. No `get_node()` with long paths across the tree. - Signals for "something happened" (`signal died`, `health_changed.emit(hp)`), direct calls for "do this". Children signal up; parents call down. - Connect signals in code with callables: `button.pressed.connect(_on_start_pressed)`. - Physics and movement in `_physics_process(delta)`; visuals and input polling in `_process(delta)` or `_unhandled_input`. - Use groups (`add_to_group("enemies")`) instead of searching the tree. - Use `await get_tree().create_timer(0.5).timeout` for simple delays; `Tween` (`create_tween()`) for movement and juice. - Godot 3 syntax is wrong here: no `onready`, `export`, `yield`, `KinematicBody2D`, or `connect("signal", self, "method")`. ## Editing scenes - Prefer creating nodes in the editor (tell the human what to add) or in code. If you must edit a `.tscn` by hand, keep `ext_resource` ids consistent and do not reorder sections. - Input actions belong in Project Settings → Input Map (`project.godot`), never hard-coded key codes. ## Before you say "done" - Run the project headless to catch script errors: `godot --headless --quit` (or ask the human to press F5). - Say what the human should test by hand, in one or two lines. ```` ### File: CLAUDE.md ```markdown # CLAUDE.md @AGENTS.md ## Claude Code notes - Skills from this loadout live in `.claude/skills/`: `godot-jam-ship`. Use them when their description matches the task. - Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins. ``` ### File: GEMINI.md ```markdown # GEMINI.md @./AGENTS.md ## Gemini CLI notes - Skills from this loadout live in `.agents/skills/`: `godot-jam-ship`. Use them when their description matches the task. - Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins. ``` ### File: .cursor/rules/gdscript.mdc ```markdown --- description: Godot 4 GDScript style and API rules globs: "**/*.gd" alwaysApply: false --- - Godot 4 syntax only: `@export`, `@onready`, `await`, `signal.emit()`, `signal.connect(callable)`, `CharacterBody2D`/`3D`. - Type every variable, parameter and return value. `-> void` on functions that return nothing. - `CharacterBody2D`: set `velocity`, then call `move_and_slide()` with no arguments. - Use `Input.get_vector("move_left", "move_right", "move_up", "move_down")` for movement; action names come from the Input Map. - Expose tuning values with `@export` (and `@export_range` where sensible) instead of magic numbers. - Prefer signals and groups to absolute node paths. Avoid `get_parent().get_parent()`. - Free nodes with `queue_free()`, never `free()`, during gameplay. - Keep scripts under ~200 lines; split behaviour into child nodes/components when they grow. ``` ### File: skills/godot-jam-ship/SKILL.md ````markdown --- name: godot-jam-ship description: Export a Godot 4 project to the web and publish it to itch.io. Use when the user wants to build, export, upload, publish or submit their game jam entry. --- # Ship a Godot 4 jam build to itch.io ## 0. Preconditions (check, then tell the human what is missing) - Godot 4 is on the PATH (`godot --version`) and the **export templates for that exact version** are installed (Editor → Manage Export Templates). Headless export fails without them. - `export_presets.cfg` contains a preset named `Web`. If not, ask the human to add one in Project → Export (Add… → Web) and save; do not invent the file from scratch. - `butler` is installed and logged in (`butler login`, or `BUTLER_API_KEY` set) if publishing. - The itch.io project page exists (it can be a draft). You need `user/game-slug`. ## 1. Pick threading - **Thread Support off** (default for Godot 4.3+ Web preset): works anywhere, including itch.io, with no special headers. Use this unless the human needs threads. - **Thread Support on**: needs cross-origin isolation (SharedArrayBuffer). On itch.io tick "SharedArrayBuffer support" in the embed options, or the game shows a blank screen. ## 2. Export ```sh mkdir -p build/web godot --headless --export-release "Web" build/web/index.html ``` - The entry file must be `index.html` for itch.io. - Check `build/web` contains `index.html`, `.js`, `.wasm` and `.pck` files. If the `.pck` is huge, look for uncompressed audio or unused assets and mention it. ## 3. Smoke test locally ```sh npx serve build/web # or: python3 -m http.server -d build/web 8000 ``` Ask the human to open it and play for 30 seconds. Web builds can behave differently from the editor (audio needs a click to start; mouse capture needs a user gesture). ## 4. Publish ```sh butler push build/web user/game-slug:html5 --userversion "jam-$(date +%Y%m%d-%H%M)" butler status user/game-slug:html5 ``` - First push only: the human must set "Kind of project" to HTML on the itch page and tick "This file will be played in the browser" for the html5 upload, and set the viewport size to the project's window size. ## 5. Optional desktop builds If presets exist: `godot --headless --export-release "Windows Desktop" build/win/game.exe` then `butler push build/win user/game-slug:windows`. Same for `Linux` and `macOS` (macOS builds are unsigned — tell the human players will need to right-click → Open). ## 6. Report Tell the human: the itch.io URL, the channel(s) pushed, the build version string, and anything that still needs a click on the itch dashboard. Do not submit to the jam itself — that is the human's button. ```` ## MCP server (TypeScript) (`mcp-server-typescript` v1.0.0) Rules and an add-a-tool skill for building a Model Context Protocol server in TypeScript that agents can actually use well — clear tools, safe inputs, no stdout noise. - URL: https://setupbay.com/loadouts/mcp-server-typescript/ - JSON: https://setupbay.com/api/loadouts/mcp-server-typescript.json - Categories: ai-agents - Stacks: mcp, typescript, nodejs - Licence: MIT - First listed: 2026-10-15; updated: 2026-10-15 - Verified install (Level 1): verified (checked 2026-10-19; 9 passed, 0 failed, 1 not applicable) - Agent tests: untested - Last checked: 2026-10-15 ### Install paths - `AGENTS.md` (instructions): claude-code → AGENTS.md; codex → AGENTS.md; cursor → AGENTS.md; gemini-cli → AGENTS.md; antigravity-cli → AGENTS.md; copilot → AGENTS.md - `CLAUDE.md` (adapter): claude-code → CLAUDE.md - `GEMINI.md` (adapter): gemini-cli → GEMINI.md - `.cursor/rules/mcp-tools.mdc` (rules): cursor → .cursor/rules/mcp-tools.mdc - `skills/add-mcp-tool/SKILL.md` (skill): claude-code → .claude/skills/add-mcp-tool/SKILL.md; codex → .agents/skills/add-mcp-tool/SKILL.md; cursor → .agents/skills/add-mcp-tool/SKILL.md; gemini-cli → .agents/skills/add-mcp-tool/SKILL.md; antigravity-cli → .agents/skills/add-mcp-tool/SKILL.md; copilot → .agents/skills/add-mcp-tool/SKILL.md ### File: AGENTS.md ````markdown # AGENTS.md: MCP server (TypeScript) This repository is a Model Context Protocol server built with the official TypeScript SDK (`@modelcontextprotocol/sdk`). Check the installed SDK version in `package.json` before writing imports — APIs and import paths have changed between majors. ## Layout ``` src/index.ts creates the server, registers tools/resources/prompts, connects the transport src/tools/.ts one tool per file: exports a register(server) function src/lib/ API clients and shared helpers ``` ## Transport - **stdio** for local servers launched by the agent. **stdout belongs to the protocol.** Never `console.log` — log with `console.error` (stderr) or a logger pointed at stderr. A stray print corrupts the JSON-RPC stream. - **Streamable HTTP** for remote servers. Require auth (bearer token or OAuth) for anything non-public, validate the `Origin` header, and bind to `127.0.0.1` when running locally. ## Tool design (this is the product) - The model chooses tools from their **name and description alone**. Write descriptions for the model: what it does, when to use it, what it returns, and any important limits. One to three sentences. - Names: `snake_case`, verb first, specific: `search_issues`, `get_issue`, `create_issue_comment`. Not `issues` or `do_action`. - Few, focused tools beat many overlapping ones. If two tools are often confused, merge them or sharpen the descriptions. - Inputs: small, typed zod schemas with `.describe()` on every field. Use enums for fixed choices, sensible defaults, and bounded numbers (`limit` 1–50). - Outputs: concise text the model can use. Return the fields that matter, not the whole raw API response. Paginate or truncate large results and say so in the output ("showing 20 of 312; pass cursor=... for more"). - Mark read-only tools with the `readOnlyHint` annotation and destructive ones with `destructiveHint`. ## Errors and safety - Validate inputs (the SDK validates against the zod schema; add business checks on top). - Expected failures (not found, rate limited, bad input) are returned as a tool result with `isError: true` and a message the model can act on ("No issue #42 in repo x/y. Use search_issues to find valid numbers."). Do not throw for them. - Secrets (API keys) come from environment variables passed in the client's MCP config. Never return them in output. - Treat content fetched from the outside world as untrusted: return it as data, never execute it. - Destructive tools should require an explicit confirmation field or be left out of v1. ## Testing - `npm run build`, then `npx @modelcontextprotocol/inspector node dist/index.js` to list and call tools by hand. - Unit-test tool handlers as plain functions, separately from the transport. ## Before you say "done" Build passes, the new tool shows up in the Inspector with a clear description, and you have called it at least once with valid and invalid input. ```` ### File: CLAUDE.md ```markdown # CLAUDE.md @AGENTS.md ## Claude Code notes - Skills from this loadout live in `.claude/skills/`: `add-mcp-tool`. Use them when their description matches the task. - Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins. ``` ### File: GEMINI.md ```markdown # GEMINI.md @./AGENTS.md ## Gemini CLI notes - Skills from this loadout live in `.agents/skills/`: `add-mcp-tool`. Use them when their description matches the task. - Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins. ``` ### File: .cursor/rules/mcp-tools.mdc ```markdown --- description: MCP tool definition conventions globs: src/tools/**/*.ts alwaysApply: false --- - Tool names are `snake_case`, verb first, unique across the server. - Descriptions are written for the model: what, when to use, what it returns, limits. 1–3 sentences. - Every input field has a zod type and `.describe(...)`. Bound numbers, use enums for fixed options, give defaults. - Return concise `content: [{ type: "text", text }]`; summarise large API responses and paginate. - Expected failures return `{ isError: true, content: [...] }` with an actionable message. Do not throw. - Never write to stdout (`console.log`) — use `console.error`. - Annotate read-only tools with `readOnlyHint: true`; destructive ones with `destructiveHint: true`. - Secrets come from `process.env`, never from tool arguments or source code. ``` ### File: skills/add-mcp-tool/SKILL.md ````markdown --- name: add-mcp-tool description: Design, implement and test a new tool on a TypeScript MCP server. Use when the user asks to add a capability, endpoint or action to their MCP server. --- # Add an MCP tool ## 1. Design first (write this down in your reply) - **Name:** verb-first `snake_case`, not clashing with existing tools (check `src/tools/`). - **Description:** 1–3 sentences for the model — what it does, when to use it instead of the other tools, what it returns. - **Inputs:** each field with type, constraints and description. Keep it to what the model can reasonably know. - **Output:** the few fields the model needs, formatted as short text or compact JSON. - **Failure cases:** list them and the message each returns. - **Side effects:** read-only, or does it change something? Destructive tools need a confirmation input or a human decision first. If an existing tool almost does this, propose extending it instead of adding a near-duplicate. ## 2. Implement Create `src/tools/.ts` with a `register(server)` function, following the patterns already in the repo and the SDK version installed. The shape (adjust to the installed SDK's API): ```ts import { z } from "zod"; import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; export function register(server: McpServer) { server.registerTool( "get_weather", { title: "Get weather", description: "Current weather for a city. Use for present conditions only; there is no forecast. Returns temperature (°C), conditions and wind.", inputSchema: { city: z.string().min(1).max(100).describe("City name, e.g. 'Leeds' or 'Leeds, UK'") }, annotations: { readOnlyHint: true }, }, async ({ city }) => { const result = await lookupWeather(city); if (!result) { return { isError: true, content: [{ type: "text", text: `No city called "${city}" found. Try adding the country.` }] }; } return { content: [{ type: "text", text: `${result.name}: ${result.tempC}°C, ${result.summary}, wind ${result.windKph} km/h` }] }; }, ); } ``` Register it in `src/index.ts`. Put API calls in `src/lib/` with timeouts. ## 3. Test 1. `npm run build` (and `npm test` if there are tests; add one for the handler logic). 2. `npx @modelcontextprotocol/inspector node dist/index.js` → Tools → list → call with valid input, then invalid input. 3. Confirm nothing is written to stdout except protocol messages. ## 4. Report The tool signature, its description, sample output, and how to reload it in the human's client (most clients need the MCP server restarted to see new tools). ```` ## Next.js + Supabase SaaS (`nextjs-supabase-saas` v1.0.0) Rules, an RLS audit skill and a read-only Supabase MCP config for vibe-coding a Next.js App Router SaaS without leaking your database. - URL: https://setupbay.com/loadouts/nextjs-supabase-saas/ - JSON: https://setupbay.com/api/loadouts/nextjs-supabase-saas.json - Categories: web-app - Stacks: nextjs, react, typescript, supabase, postgres - Licence: MIT - First listed: 2026-10-15; updated: 2026-10-15 - Verified install (Level 1): verified (checked 2026-10-19; 10 passed, 0 failed, 0 not applicable) - Agent tests: untested - Last checked: 2026-10-15 - Needs env: NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY ### Install paths - `AGENTS.md` (instructions): claude-code → AGENTS.md; codex → AGENTS.md; cursor → AGENTS.md; gemini-cli → AGENTS.md; antigravity-cli → AGENTS.md; copilot → AGENTS.md - `CLAUDE.md` (adapter): claude-code → CLAUDE.md - `GEMINI.md` (adapter): gemini-cli → GEMINI.md - `.cursor/rules/supabase-migrations.mdc` (rules): cursor → .cursor/rules/supabase-migrations.mdc - `skills/supabase-rls-audit/SKILL.md` (skill): claude-code → .claude/skills/supabase-rls-audit/SKILL.md; codex → .agents/skills/supabase-rls-audit/SKILL.md; cursor → .agents/skills/supabase-rls-audit/SKILL.md; gemini-cli → .agents/skills/supabase-rls-audit/SKILL.md; antigravity-cli → .agents/skills/supabase-rls-audit/SKILL.md; copilot → .agents/skills/supabase-rls-audit/SKILL.md - `mcp.json` (mcp): claude-code → .mcp.json; cursor → .cursor/mcp.json; antigravity-cli → .agents/mcp_config.json ### File: AGENTS.md ```markdown # AGENTS.md: Next.js + Supabase SaaS You are working on a Next.js (App Router) SaaS backed by Supabase (Postgres, Auth, Storage). Treat the database as production unless told otherwise. ## Stack and layout - Next.js App Router in `app/`. TypeScript strict mode. No Pages Router code. - Supabase clients live in `lib/supabase/`: - `server.ts` creates a server client with `@supabase/ssr` and the Next.js `cookies()` store. - `client.ts` creates a browser client. Only use it inside `"use client"` components. - `middleware.ts` (or `proxy.ts` on newer Next.js) refreshes the auth session cookie on each request. - Schema lives in `supabase/migrations/`. Generated types live in `lib/database.types.ts`. ## Server vs client - Components are Server Components by default. Add `"use client"` only for state, effects or browser APIs. - Fetch data in Server Components or Route Handlers, not in `useEffect`, unless it is genuinely live data. - Mutations go through Server Actions or Route Handlers. Validate every input with `zod` on the server, even if the form validated it already. - Never import `lib/supabase/server.ts` or anything using secret env vars from a client component. ## Auth - Get the user on the server with `supabase.auth.getUser()` (it verifies the JWT with Supabase). Do not trust `getSession()` on the server for authorisation decisions. - Protect pages by checking the user in the layout or page, and redirect if missing. Middleware alone is not enough. - Authorisation belongs in RLS policies. App code checks are a convenience, not the security boundary. ## Keys and environment - `NEXT_PUBLIC_SUPABASE_URL` and the publishable (anon) key are safe in the browser *only because RLS is on*. - The secret / `service_role` key bypasses RLS. It must only be used in server-only code for admin jobs, never prefixed `NEXT_PUBLIC_`, never logged, never committed. - Keep `.env.local` out of git. Add any new variable to `.env.example` with a dummy value. ## Database changes - Every schema change is a new migration: `supabase migration new `. Never edit an applied migration. - Every new table in an exposed schema gets `alter table ... enable row level security;` in the same migration, plus explicit policies for each operation it needs (select, insert, update, delete). - Prefer `(select auth.uid())` in policies over bare `auth.uid()` so Postgres can cache it per statement. - Add indexes on columns used in policies (for example `user_id`, `org_id`). - After a schema change, regenerate types: `supabase gen types typescript --local > lib/database.types.ts`. ## Payments (if present) - Stripe webhooks are verified with the signing secret before any database write. - Entitlements (plan, seats) are written by the webhook handler, never by the client. ## Before you say "done" 1. `npm run lint` and `npm run build` pass. 2. No secret key reachable from client bundles (`grep -r SERVICE_ROLE app components` is empty). 3. Any new table has RLS enabled and at least one policy. Run the `supabase-rls-audit` skill if unsure. 4. Summarise what changed, any migration added, and anything the human must do (env vars, dashboard settings). ## Do not - Do not disable RLS to "make it work". Fix the policy instead. - Do not run destructive SQL (`drop`, `truncate`, `delete` without `where`) against a remote project. - Do not add a new auth library. Supabase Auth is the auth system. ``` ### File: CLAUDE.md ```markdown # CLAUDE.md @AGENTS.md ## Claude Code notes - Skills from this loadout live in `.claude/skills/`: `supabase-rls-audit`. Use them when their description matches the task. - MCP servers for this project are in `.mcp.json`. If a server is not connected, tell the human rather than working around it. - Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins. ``` ### File: GEMINI.md ```markdown # GEMINI.md @./AGENTS.md ## Gemini CLI notes - Skills from this loadout live in `.agents/skills/`: `supabase-rls-audit`. Use them when their description matches the task. - Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins. ``` ### File: .cursor/rules/supabase-migrations.mdc ````markdown --- description: Rules for writing Supabase SQL migrations safely globs: supabase/migrations/**/*.sql alwaysApply: false --- # Supabase migrations - One concern per migration file. Name it for what it does: `add_projects_table`, not `update`. - Never edit a migration that has been applied anywhere. Write a new one. - Every `create table` in `public` (or any exposed schema) is followed in the same file by: - `alter table enable row level security;` - explicit `create policy` statements for each operation the app needs. - Write policies with a `to` role (`authenticated` or `anon`) and both `using` and, for writes, `with check`. - Use `(select auth.uid())` inside policies, not bare `auth.uid()`. - Index foreign keys and every column referenced by a policy. - `security definer` functions must set `search_path = ''` and fully qualify table names. - Destructive changes (`drop column`, `drop table`, type changes) need a comment explaining the data impact, and should be split into expand → migrate data → contract steps when the table has real data. Example: ```sql create table public.projects ( id uuid primary key default gen_random_uuid(), owner_id uuid not null references auth.users (id) on delete cascade, name text not null check (char_length(name) between 1 and 120), created_at timestamptz not null default now() ); alter table public.projects enable row level security; create index projects_owner_id_idx on public.projects (owner_id); create policy "Owners can read their projects" on public.projects for select to authenticated using ((select auth.uid()) = owner_id); create policy "Owners can create projects" on public.projects for insert to authenticated with check ((select auth.uid()) = owner_id); ``` ```` ### File: skills/supabase-rls-audit/SKILL.md ````markdown --- name: supabase-rls-audit description: Audit Supabase row level security. Use when asked to check database security, before launch, after adding tables, or when someone worries that users can see each other's data. --- # Supabase RLS audit Goal: find every way a signed-in or anonymous user could read or change rows they should not, and report it in plain English with a fix for each. ## 1. Collect the facts Use whichever source is available, in this order: 1. The Supabase MCP server (read-only) — run the SQL below with its query tool. 2. A local database: `supabase db dump --local --schema public` or `psql` against the local URL. 3. The migration files in `supabase/migrations/` (read them in order; later files win). ```sql -- Tables in exposed schemas and whether RLS is on select n.nspname as schema, c.relname as table, c.relrowsecurity as rls_enabled, c.relforcerowsecurity as rls_forced from pg_class c join pg_namespace n on n.oid = c.relnamespace where c.relkind = 'r' and n.nspname in ('public') order by 1, 2; -- Every policy select schemaname, tablename, policyname, cmd, roles, qual as using_expr, with_check from pg_policies where schemaname in ('public') order by tablename, cmd; -- Views (they bypass RLS unless created with security_invoker) select table_schema, table_name from information_schema.views where table_schema = 'public'; -- Security definer functions callable through the API select p.proname, p.prosecdef, p.proconfig from pg_proc p join pg_namespace n on n.oid = p.pronamespace where n.nspname = 'public' and p.prosecdef; ``` ## 2. Check each table against these rules Flag as **Critical**: - RLS disabled on any table in `public`. - A policy for `anon` or `public` roles that is `using (true)` on a table holding user data. - An `update` policy without `with check`, letting users move rows to another owner. - A view in `public` without `security_invoker = true` that selects from a protected table. Flag as **High**: - RLS enabled but no policies (the app is probably using the secret key to get round it — find out where). - Policies that trust a column the user can write (for example `role` or `is_admin` on their own profile row). - `security definer` functions without `set search_path = ''`. - Storage buckets that are public but hold private uploads. Flag as **Medium**: - Bare `auth.uid()` instead of `(select auth.uid())` (performance, not security). - Policy columns without indexes. ## 3. Check the app code - Search for the secret / service role key: `grep -rn "SERVICE_ROLE\|sb_secret_" --include=*.ts --include=*.tsx .` Any hit outside server-only files is **Critical**. - Check that no `NEXT_PUBLIC_` variable holds a secret. ## 4. Report Write a short report: ``` RLS audit — Critical: High: Medium: [Critical] public.invoices — RLS is disabled. Anyone with the publishable key can read every invoice. Fix: new migration with `alter table public.invoices enable row level security;` and an owner-only select policy. ``` Then offer to write the fix as a **new migration**. Do not apply changes to a remote database yourself. ```` ### File: mcp.json ```json { "mcpServers": { "supabase": { "type": "http", "url": "https://mcp.supabase.com/mcp?project_ref=YOUR_PROJECT_REF&read_only=true" } } } ``` ## Secure before you ship (`secure-before-you-ship` v1.0.0) A launch-check skill and always-on security rules that catch leaked keys, open databases and missing auth before your vibe-coded app goes live. - URL: https://setupbay.com/loadouts/secure-before-you-ship/ - JSON: https://setupbay.com/api/loadouts/secure-before-you-ship.json - Categories: security, web-app - Stacks: any, javascript, typescript, python - Licence: MIT - First listed: 2026-10-15; updated: 2026-10-15 - Verified install (Level 1): verified (checked 2026-10-19; 8 passed, 0 failed, 2 not applicable) - Agent tests: untested - Last checked: 2026-10-15 ### Install paths - `AGENTS.md` (instructions): claude-code → AGENTS.md; codex → AGENTS.md; cursor → AGENTS.md; gemini-cli → AGENTS.md; antigravity-cli → AGENTS.md; copilot → AGENTS.md - `CLAUDE.md` (adapter): claude-code → CLAUDE.md - `GEMINI.md` (adapter): gemini-cli → GEMINI.md - `.cursor/rules/no-secrets.mdc` (rules): cursor → .cursor/rules/no-secrets.mdc - `skills/launch-check/SKILL.md` (skill): claude-code → .claude/skills/launch-check/SKILL.md; codex → .agents/skills/launch-check/SKILL.md; cursor → .agents/skills/launch-check/SKILL.md; gemini-cli → .agents/skills/launch-check/SKILL.md; antigravity-cli → .agents/skills/launch-check/SKILL.md; copilot → .agents/skills/launch-check/SKILL.md - `skills/launch-check/references/checklist.md` (reference): claude-code → .claude/skills/launch-check/references/checklist.md; codex → .agents/skills/launch-check/references/checklist.md; cursor → .agents/skills/launch-check/references/checklist.md; gemini-cli → .agents/skills/launch-check/references/checklist.md; antigravity-cli → .agents/skills/launch-check/references/checklist.md; copilot → .agents/skills/launch-check/references/checklist.md ### File: AGENTS.md ```markdown # AGENTS.md: security baseline These rules apply to every change in this repository, whatever the stack. ## Secrets - Never hard-code API keys, tokens, passwords or connection strings. Read them from environment variables. - Never put a secret in a variable the browser can see: `NEXT_PUBLIC_*`, `VITE_*`, `PUBLIC_*`, `EXPO_PUBLIC_*`, or anything bundled into client JavaScript. If the front end needs a third-party API, call it through a server route. - Never log secrets, full request headers, or whole environment objects. - Keep `.env`, `.env.local` and similar files out of git. Keep `.env.example` up to date with dummy values. - If you find a secret committed to git, stop and tell the human. Deleting the line is not enough — it must be rotated with the provider. ## Auth and access - Every route, server action and API handler that reads or changes user data checks who the user is *on the server*. - Check authorisation on the resource, not just login: "is this user allowed to touch *this* row?" - Admin features check an admin role stored server-side, never a flag sent by the client. - Database access rules (Supabase RLS, Firebase Security Rules, Postgres grants) are the real boundary. Do not turn them off to make something work. ## Input and output - Validate all input on the server with a schema (zod, valibot, pydantic). Client validation is for UX only. - Use parameterised queries or the ORM. Never build SQL with string concatenation. - Do not render user content as raw HTML (`dangerouslySetInnerHTML`, `v-html`, `set:html`, `innerHTML`) unless it has been sanitised. - File uploads: check type and size server-side, store outside the web root or in object storage, never trust the filename. ## Cost and abuse - Any endpoint that calls a paid API (LLMs, email, SMS, maps) needs auth or rate limiting, and ideally both. - Set spending caps or budget alerts on paid providers where they exist. ## Dependencies - Prefer well-known packages. Check that a package name is real and spelled correctly before installing it. - Do not add a dependency for something the platform already does. ## When unsure Ask the human, or run the `launch-check` skill and report what it finds. ``` ### File: CLAUDE.md ```markdown # CLAUDE.md @AGENTS.md ## Claude Code notes - Skills from this loadout live in `.claude/skills/`: `launch-check`. Use them when their description matches the task. - Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins. ``` ### File: GEMINI.md ```markdown # GEMINI.md @./AGENTS.md ## Gemini CLI notes - Skills from this loadout live in `.agents/skills/`: `launch-check`. Use them when their description matches the task. - Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins. ``` ### File: .cursor/rules/no-secrets.mdc ```markdown --- description: Never expose or hard-code secrets alwaysApply: true --- - Read secrets from environment variables. Never write a real key, token or password into code, tests, docs or examples. - Client-exposed prefixes (`NEXT_PUBLIC_`, `VITE_`, `PUBLIC_`, `EXPO_PUBLIC_`) are public. Never put a secret behind one. - Calls to paid or secret-key APIs go through server code, never directly from the browser. - Never log tokens, cookies, auth headers or whole `process.env` / `os.environ` objects. - When adding a variable, add a dummy entry to `.env.example` and make sure `.env*` (except the example) is git-ignored. - If you spot a secret already committed, stop and tell the human that it needs rotating with the provider. ``` ### File: skills/launch-check/SKILL.md ````markdown --- name: launch-check description: Pre-launch security and readiness audit for web apps. Use when the user says they are about to launch, deploy, go live, share the link, or asks "is my app safe?". --- # Launch check Produce a plain-English, severity-ranked fix list that a non-expert can act on. **Report first. Do not change code until the human picks which fixes to apply.** ## Steps 1. **Map the app (2 minutes, no more).** Identify the framework, where server code runs, the database and auth provider, the hosting platform, and every third-party API it calls. Read `package.json` / `requirements.txt` / `pyproject.toml`, the env example file, and the routes or API folder. 2. **Work through `references/checklist.md`.** For each item decide: pass, fail, or can't tell. Prefer evidence from the code. Useful searches: - Secrets in code: `git grep -nE "(sk_live|sk_test|sb_secret_|service_role|AKIA[0-9A-Z]{16}|ghp_|xox[bp]-|-----BEGIN)"` - Secrets in history: `git log -p --all -S "sk_live" | head` (repeat for other patterns that hit) - Client-exposed env: `git grep -nE "(NEXT_PUBLIC_|VITE_|PUBLIC_|EXPO_PUBLIC_)[A-Z_]*(SECRET|PRIVATE|SERVICE|TOKEN)"` - Committed env files: `git ls-files | grep -E "(^|/)\.env"` - Raw HTML: `git grep -nE "dangerouslySetInnerHTML|v-html|set:html|innerHTML\s*="` - String-built SQL: `git grep -nE "(query|execute|raw)\(.*(\+|\$\{|f\")"` - Server routes without an auth check: list every API route and note which ones read the user. 3. **Check the database rules** if there is one. Supabase: every public table has RLS enabled with real policies. Firebase: rules are not `allow read, write: if true`. Plain Postgres/MySQL: the app user is not a superuser. 4. **Check abuse and cost.** List every endpoint that triggers a paid API. Note whether it requires auth and is rate limited. 5. **Write the report** in this format: ``` Launch check — — Verdict: Not ready / Ready with fixes / Ready CRITICAL (fix before anyone else sees the link) 1. — Why it matters: Fix: HIGH (fix before launch day) ... MEDIUM (fix in the first week) ... Couldn't check: ``` Keep each finding to three or four lines. Do not pad the report with passes; list passes as a single line count. 6. **Offer the fixes.** Ask which to apply. Rotated keys, dashboard settings and DNS changes are jobs for the human — explain exactly where to click, but do not pretend you did them. ```` ### File: skills/launch-check/references/checklist.md ```markdown # Launch checklist Severity in brackets is the default; raise it if the data is sensitive. ## Secrets - [Critical] No live secret keys in source code or config files. - [Critical] No secrets in client-exposed env vars or the built front-end bundle. - [Critical] No `.env` files tracked by git. If one ever was, the keys in it need rotating. - [High] Secrets in git history have been rotated (removing the commit is not enough). - [Medium] `.env.example` exists and lists every variable with a dummy value. ## Authentication - [Critical] Every API route / server action that touches user data checks the session on the server. - [Critical] Admin pages and endpoints check a server-side role, not a client flag or a hidden URL. - [High] Password reset and magic-link flows expire and are single use (default on most providers — confirm it is not disabled). - [Medium] Email confirmation is required before an account can do anything costly. ## Data access - [Critical] Database rules are on: Supabase RLS on every public table, Firebase rules not open, no public buckets with private files. - [Critical] Users cannot read or change another user's rows by changing an ID in the request (test one by hand). - [High] Update endpoints cannot change ownership or role fields. - [High] Queries are parameterised; no string-built SQL. ## Abuse and cost - [Critical] Endpoints that call paid APIs (LLM, email, SMS) need auth. - [High] Those endpoints are rate limited per user or IP. - [High] Provider spending limits or budget alerts are set. - [Medium] Sign-up has some bot friction (captcha, email confirmation or invite). ## Input and output - [High] Server-side validation on every input. - [High] No unsanitised user HTML rendered. - [Medium] Uploads checked for type and size server-side. - [Medium] Error responses do not leak stack traces or SQL. ## Platform - [High] HTTPS only. Cookies are `Secure`, `HttpOnly` and `SameSite=Lax` or stricter. - [Medium] Security headers set: `Content-Security-Policy` (even a basic one), `X-Content-Type-Options: nosniff`, `Referrer-Policy`, `frame-ancestors` / `X-Frame-Options`. - [Medium] CORS is not `*` on endpoints that use cookies. - [Medium] Debug mode, test routes and seed endpoints are off in production. ## Dependencies - [High] `npm audit --omit=dev` / `pip-audit` shows no critical issues in runtime dependencies. - [Medium] Lockfile committed. - [Medium] No unfamiliar or misspelt packages (check anything you do not recognise on the registry). ## Readiness (not security, but people notice) - [Medium] Privacy policy and terms exist if you collect personal data (UK GDPR applies to UK users). - [Medium] Error tracking or at least server logs are on. - [Medium] Database backups are on and you know how to restore one. ``` ## Vibe-coding guard rails (`vibe-coding-guardrails` v1.0.0) A stack-agnostic working style for coding agents — plan first, small diffs, never delete tests to go green — plus handoff notes and up-to-date docs via MCP. - URL: https://setupbay.com/loadouts/vibe-coding-guardrails/ - JSON: https://setupbay.com/api/loadouts/vibe-coding-guardrails.json - Categories: workflow - Stacks: any - Licence: MIT - First listed: 2026-10-15; updated: 2026-10-15 - Verified install (Level 1): verified (checked 2026-10-19; 9 passed, 0 failed, 1 not applicable) - Agent tests: untested - Last checked: 2026-10-15 ### Install paths - `AGENTS.md` (instructions): claude-code → AGENTS.md; codex → AGENTS.md; cursor → AGENTS.md; gemini-cli → AGENTS.md; antigravity-cli → AGENTS.md; copilot → AGENTS.md - `CLAUDE.md` (adapter): claude-code → CLAUDE.md - `GEMINI.md` (adapter): gemini-cli → GEMINI.md - `.cursor/rules/guardrails.mdc` (rules): cursor → .cursor/rules/guardrails.mdc - `skills/plan-then-build/SKILL.md` (skill): claude-code → .claude/skills/plan-then-build/SKILL.md; codex → .agents/skills/plan-then-build/SKILL.md; cursor → .agents/skills/plan-then-build/SKILL.md; gemini-cli → .agents/skills/plan-then-build/SKILL.md; antigravity-cli → .agents/skills/plan-then-build/SKILL.md; copilot → .agents/skills/plan-then-build/SKILL.md - `skills/session-handoff/SKILL.md` (skill): claude-code → .claude/skills/session-handoff/SKILL.md; codex → .agents/skills/session-handoff/SKILL.md; cursor → .agents/skills/session-handoff/SKILL.md; gemini-cli → .agents/skills/session-handoff/SKILL.md; antigravity-cli → .agents/skills/session-handoff/SKILL.md; copilot → .agents/skills/session-handoff/SKILL.md - `mcp.json` (mcp): claude-code → .mcp.json; cursor → .cursor/mcp.json; antigravity-cli → .agents/mcp_config.json ### File: AGENTS.md ```markdown # AGENTS.md: working agreement How to work in this repository, whatever the stack. Project-specific rules, if any, take precedence. ## Before you start - Read the README and any `NOTES.md` handoff file first. - For anything bigger than a small fix (more than ~3 files, a new feature, a refactor, a dependency change), use the `plan-then-build` skill: write a short plan and wait for the human to agree. - If the request is ambiguous, ask one focused question rather than guessing big. ## While you work - **Small steps.** Make one change that works, verify it, then the next. Prefer several small diffs to one huge one. - **Stay in scope.** Do not reformat, rename or "tidy" code you were not asked to touch. Mention improvements instead. - **Follow what is there.** Match the existing structure, naming, libraries and patterns before introducing new ones. - **Check, don't guess, APIs.** If you are not certain a function or option exists in the installed version, look it up: check `package.json`/lockfile for the version, read the library's docs (the Context7 MCP server helps), or read the source in `node_modules`. - **Commit after each working step** if the human uses git that way, with a message saying what and why. ## Hard rules - Never delete, skip or weaken a test to make it pass. If a test is wrong, say so and explain why before changing it. - Never silence errors to make something "work": no empty `catch`, no `// @ts-ignore`, no `# type: ignore`, no `eslint-disable` without a reason in the comment. - Never add a dependency without saying so and why. Prefer what the platform or existing deps already provide. - Never run destructive commands (`rm -rf`, `git reset --hard`, `git push --force`, dropping databases) without explicit permission. - Never commit secrets or `.env` files. - Never claim something works without running it. If you could not run it, say "not run" plainly. ## When you finish - Run the project's checks (lint, type-check, tests, build — whatever exists). - Summarise in a few lines: what changed, how you verified it, anything left undone or risky, and what the human should try. - For long sessions, use `session-handoff` to update `NOTES.md`. ``` ### File: CLAUDE.md ```markdown # CLAUDE.md @AGENTS.md ## Claude Code notes - Skills from this loadout live in `.claude/skills/`: `plan-then-build`, `session-handoff`. Use them when their description matches the task. - MCP servers for this project are in `.mcp.json`. If a server is not connected, tell the human rather than working around it. - Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins. ``` ### File: GEMINI.md ```markdown # GEMINI.md @./AGENTS.md ## Gemini CLI notes - Skills from this loadout live in `.agents/skills/`: `plan-then-build`, `session-handoff`. Use them when their description matches the task. - Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins. ``` ### File: .cursor/rules/guardrails.mdc ```markdown --- description: Hard guard rails for agent changes alwaysApply: true --- - Never delete, skip or weaken tests to get a green run. Explain if you think a test is wrong. - No empty catch blocks, `@ts-ignore`, `type: ignore` or lint disables without a written reason. - Do not add dependencies without saying which and why. - Do not run destructive shell or git commands without explicit permission. - Do not touch files unrelated to the task. Mention suggested clean-ups instead. - Verify before claiming success; say "not run" if you could not run something. - For multi-file or architectural changes, propose a short plan first. ``` ### File: skills/plan-then-build/SKILL.md ````markdown --- name: plan-then-build description: Write a short implementation plan and get approval before building. Use for new features, refactors, multi-file changes, dependency changes, or whenever the request is big or vague. --- # Plan, then build ## 1. Look before planning (keep it quick) Read the files you expect to change and their neighbours. Find the existing pattern for this kind of change (how other routes, components or commands are structured). Check installed versions of anything you will rely on. ## 2. Write the plan Keep it under ~20 lines. Use this shape: ``` Goal: Approach: Changes: 1. — 2. — New dependencies: none | () Out of scope: Risks / questions: How I'll verify: ``` If there is a real choice to make (two reasonable approaches), give both in one line each with your recommendation. ## 3. Stop and wait Ask: "Shall I go ahead?" Do not start editing until the human agrees or adjusts the plan. If they say "just do it" for this kind of task in future, you may skip waiting for similar small tasks in the same session. ## 4. Build in the order of the plan - Do the steps in order, verifying as you go. - If you discover the plan is wrong (a hidden dependency, a bigger change than expected), stop, explain, and re-plan. Do not quietly expand the scope. ## 5. Close out Report against the plan: each step done or not, how it was verified, and anything that changed from the plan. ```` ### File: skills/session-handoff/SKILL.md ````markdown --- name: session-handoff description: Write or update NOTES.md so the next session or another agent can continue the work. Use at the end of a long session, before context runs out, or when the user says they are stopping for now. --- # Session handoff Update (or create) `NOTES.md` at the repository root. Replace the "Current state" section; append to "Log". Keep the whole file short enough to read in a minute. Do not include secrets, tokens or personal data. ```markdown # Notes ## Current state (updated ) - Working on: - Done this session: - In progress: - Next steps: - Decisions: - Gotchas: ## How to run ## Log - : ``` Then: 1. Run `git status` and mention any uncommitted changes. Suggest a commit message, but do not commit unless asked. 2. Tell the human, in two or three lines, where things stand and what the next session should start with. ```` ### File: mcp.json ```json { "mcpServers": { "context7": { "type": "http", "url": "https://mcp.context7.com/mcp" } } } ``` ## AI code review rules (`ai-code-review-rules` v1.0.0) Review-only rule files for Claude Code Review, Cursor Bugbot and Copilot, built from one list: severity, a nit cap, what to skip and what to always check. - URL: https://setupbay.com/loadouts/ai-code-review-rules/ - JSON: https://setupbay.com/api/loadouts/ai-code-review-rules.json - Categories: workflow, ai-agents - Stacks: github - Licence: MIT - First listed: 2026-10-17; updated: 2026-10-17 - Verified install (Level 1): verified (checked 2026-10-19; 8 passed, 0 failed, 2 not applicable) - Agent tests: untested - Last checked: 2026-10-17 - Credits: @Cisco_research: Code Review reads REVIEW.md from the default branch (https://x.com/Cisco_research/status/2111019382038012147); @FastfixAI: .cursor/BUGBOT.md for Bugbot (https://x.com/FastfixAI/status/2096752814303174784); Claude Code docs: customise Code Review (https://code.claude.com/docs/en/code-review-customize); Cursor docs: Bugbot (https://cursor.com/docs/bugbot) ### Install paths - `AGENTS.md` (instructions): claude-code → AGENTS.md; codex → AGENTS.md; cursor → AGENTS.md; gemini-cli → AGENTS.md; antigravity-cli → AGENTS.md; copilot → AGENTS.md - `CLAUDE.md` (adapter): claude-code → CLAUDE.md - `GEMINI.md` (adapter): gemini-cli → GEMINI.md - `skills/set-up-review-rules/SKILL.md` (skill): claude-code → .claude/skills/set-up-review-rules/SKILL.md; codex → .agents/skills/set-up-review-rules/SKILL.md; cursor → .agents/skills/set-up-review-rules/SKILL.md; gemini-cli → .agents/skills/set-up-review-rules/SKILL.md; antigravity-cli → .agents/skills/set-up-review-rules/SKILL.md; copilot → .agents/skills/set-up-review-rules/SKILL.md - `skills/set-up-review-rules/references/review-rules-template.md` (reference): claude-code → .claude/skills/set-up-review-rules/references/review-rules-template.md; codex → .agents/skills/set-up-review-rules/references/review-rules-template.md; cursor → .agents/skills/set-up-review-rules/references/review-rules-template.md; gemini-cli → .agents/skills/set-up-review-rules/references/review-rules-template.md; antigravity-cli → .agents/skills/set-up-review-rules/references/review-rules-template.md; copilot → .agents/skills/set-up-review-rules/references/review-rules-template.md - `skills/set-up-review-rules/references/copilot-review-instructions.md` (reference): claude-code → .claude/skills/set-up-review-rules/references/copilot-review-instructions.md; codex → .agents/skills/set-up-review-rules/references/copilot-review-instructions.md; cursor → .agents/skills/set-up-review-rules/references/copilot-review-instructions.md; gemini-cli → .agents/skills/set-up-review-rules/references/copilot-review-instructions.md; antigravity-cli → .agents/skills/set-up-review-rules/references/copilot-review-instructions.md; copilot → .agents/skills/set-up-review-rules/references/copilot-review-instructions.md ### File: AGENTS.md ```markdown # AGENTS.md: rules for AI code reviewers This repository is reviewed by AI reviewers (Claude Code Review, Cursor Bugbot, GitHub Copilot code review) as well as people. Review rules live in review-only files, separate from coding instructions, and are kept short and testable. ## Which file each reviewer reads | Reviewer | Reads | Notes | |---|---|---| | Claude Code Review (service) | `REVIEW.md` (root, plus subdirectory files) and CLAUDE.md files | Read from the base or default branch, never from the PR. Merge rule changes first. Protect the default branch or subdirectory files and severity overrides are ignored | | Claude Code `/code-review` (local) | CLAUDE.md only | Does not read `REVIEW.md` | | Cursor Bugbot | `.cursor/BUGBOT.md` (root always; nested ones for changed paths) | `.cursor/rules` does not apply to Bugbot | | Copilot code review | `.github/copilot-instructions.md`, `.github/instructions/*.instructions.md` | Use `excludeAgent: "coding-agent"` for review-only instruction files | ## Writing review rules - Define severity for this repo: what counts as blocking (wrong behaviour, data leak, unsafe migration) and what is a nit at most. - Cap nits (for example "at most five per review"). - List what not to report: anything CI enforces (lint, format, types), generated paths, lockfiles, vendored code. - List what to always check, as concrete, checkable rules ("new API routes have an integration test"). - Require evidence: behaviour claims must cite `path:line`, not infer from names. - One rule per line. No style essays. Under ~60 lines per file. - When a reviewer is repeatedly wrong about something, add a rule; when a rule never fires, delete it. ## When you are the author Before opening a PR, read the review files above and check your diff against the "always check" rules yourself. Use the `set-up-review-rules` skill to create or change these files. ``` ### File: CLAUDE.md ```markdown # CLAUDE.md @AGENTS.md ## Claude Code notes - Skills from this loadout live in `.claude/skills/`: `set-up-review-rules`. Use them when their description matches the task. - Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins. ``` ### File: GEMINI.md ```markdown # GEMINI.md @./AGENTS.md ## Gemini CLI notes - Skills from this loadout live in `.agents/skills/`: `set-up-review-rules`. Use them when their description matches the task. - Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins. ``` ### File: skills/set-up-review-rules/SKILL.md ```markdown --- name: set-up-review-rules description: Create or tune review-only instruction files for Claude Code Review, Cursor Bugbot and Copilot code review from one rule list. Use when setting up AI code review or when reviews are noisy or miss team rules. --- # Set up review rules 1. **Collect evidence.** Read the last 10–20 AI review comments if available (`gh pr list --state merged --limit 20`, then `gh pr view --comments`). Note false positives, noise categories and real misses. 2. **Write one rule list** with four sections: severity definitions, nit cap, do not report, always check. Start from `references/review-rules-template.md`. Every rule must come from evidence or a known team requirement. 3. **Generate the files** for the reviewers the team uses: - Claude Code Review: root `REVIEW.md`; subdirectory `REVIEW.md` only for path-specific checks. - Cursor Bugbot: `.cursor/BUGBOT.md` with the same content. - Copilot: `.github/instructions/code-review.instructions.md` using `references/copilot-review-instructions.md`. 4. **Keep coding rules out.** Rules that also apply while writing code belong in `AGENTS.md`, not in review files. 5. **Land it.** Open a PR with only these files. Remind the human that Claude Code Review reads `REVIEW.md` from the default branch, so the new rules apply to PRs opened after the merge, and that branch protection is needed for subdirectory files and severity overrides to count. 6. **Re-check** after a week of reviews: delete rules that never fired, sharpen rules that were misapplied. ``` ### File: skills/set-up-review-rules/references/review-rules-template.md ```markdown # Review instructions ## What blocking means here Blocking: incorrect logic, unscoped database queries, secrets or personal data in code, logs or errors, migrations that are not backward compatible, removed authorisation checks. Style, naming and refactoring suggestions are nits at most. ## Cap the nits Report at most five nits per review. ## Do not report - Anything CI already enforces: lint, formatting, type errors, spelling - Generated files under `` and lockfiles - Test code that deliberately breaks production rules ## Always check - - - ## Evidence Behaviour claims need a path:line citation from the source, not an inference from a name. ``` ### File: skills/set-up-review-rules/references/copilot-review-instructions.md ````markdown # Copilot review-only instructions Save as `.github/instructions/code-review.instructions.md`. `applyTo` limits which files the rules attach to; `excludeAgent: "coding-agent"` keeps the file away from the Copilot coding agent so it is used for review only. ```markdown --- applyTo: "**" excludeAgent: "coding-agent" --- ``` ```` ## Astro static site (`astro-static-site` v1.0.0) Astro conventions for fast, zero-JS-by-default sites with content collections, plus a skill for deploying to Cloudflare Pages with headers and redirects. - URL: https://setupbay.com/loadouts/astro-static-site/ - JSON: https://setupbay.com/api/loadouts/astro-static-site.json - Categories: web-app - Stacks: astro, typescript, cloudflare - Licence: MIT - First listed: 2026-10-15; updated: 2026-10-15 - Verified install (Level 1): verified (checked 2026-10-19; 9 passed, 0 failed, 1 not applicable) - Agent tests: untested - Last checked: 2026-10-15 ### Install paths - `AGENTS.md` (instructions): claude-code → AGENTS.md; codex → AGENTS.md; cursor → AGENTS.md; gemini-cli → AGENTS.md; antigravity-cli → AGENTS.md; copilot → AGENTS.md - `CLAUDE.md` (adapter): claude-code → CLAUDE.md - `GEMINI.md` (adapter): gemini-cli → GEMINI.md - `.cursor/rules/astro-components.mdc` (rules): cursor → .cursor/rules/astro-components.mdc - `skills/cloudflare-pages-deploy/SKILL.md` (skill): claude-code → .claude/skills/cloudflare-pages-deploy/SKILL.md; codex → .agents/skills/cloudflare-pages-deploy/SKILL.md; cursor → .agents/skills/cloudflare-pages-deploy/SKILL.md; gemini-cli → .agents/skills/cloudflare-pages-deploy/SKILL.md; antigravity-cli → .agents/skills/cloudflare-pages-deploy/SKILL.md; copilot → .agents/skills/cloudflare-pages-deploy/SKILL.md ### File: AGENTS.md ````markdown # AGENTS.md: Astro static site Static output (`output: "static"`, the default). The built site is plain HTML/CSS in `dist/`. ## Principles - **Ship no JavaScript unless a feature needs it.** `.astro` components render to HTML at build time. A UI framework component (React, Svelte, Vue) only runs in the browser with a `client:*` directive — use `client:visible` or `client:idle` over `client:load`, and only for genuinely interactive parts. - Small inline `