# Agent Loadout — full catalogue > Every loadout on https://loadout.jnw-it.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://loadout.jnw-it.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://loadout.jnw-it.com/api/v1/search?q=&agent=&tags=&verified=`. Setup for each agent: https://loadout.jnw-it.com/docs/#mcp Pages by agent: https://loadout.jnw-it.com/agents/claude-code/, https://loadout.jnw-it.com/agents/codex/, https://loadout.jnw-it.com/agents/cursor/, https://loadout.jnw-it.com/agents/gemini-cli/, https://loadout.jnw-it.com/agents/copilot/. By stack: https://loadout.jnw-it.com/stacks/. New and updated: https://loadout.jnw-it.com/new/ (feeds: https://loadout.jnw-it.com/feed.xml, https://loadout.jnw-it.com/rss.xml). ## 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://loadout.jnw-it.com/loadouts/discord-bot-ts/ - JSON: https://loadout.jnw-it.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-16; 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; 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; 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://loadout.jnw-it.com/loadouts/godot-4-game-jam/ - JSON: https://loadout.jnw-it.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-16; 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; 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; 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://loadout.jnw-it.com/loadouts/mcp-server-typescript/ - JSON: https://loadout.jnw-it.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-16; 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; 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; 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://loadout.jnw-it.com/loadouts/nextjs-supabase-saas/ - JSON: https://loadout.jnw-it.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-16; 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; 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; copilot → .agents/skills/supabase-rls-audit/SKILL.md - `mcp.json` (mcp): claude-code → .mcp.json; cursor → .cursor/mcp.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://loadout.jnw-it.com/loadouts/secure-before-you-ship/ - JSON: https://loadout.jnw-it.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-16; 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; 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; 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; 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://loadout.jnw-it.com/loadouts/vibe-coding-guardrails/ - JSON: https://loadout.jnw-it.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-16; 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; 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; 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; copilot → .agents/skills/session-handoff/SKILL.md - `mcp.json` (mcp): claude-code → .mcp.json; cursor → .cursor/mcp.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" } } } ``` ## 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://loadout.jnw-it.com/loadouts/astro-static-site/ - JSON: https://loadout.jnw-it.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-16; 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; 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; 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 `