SLOPSHOPPER

done-gate

A band above the prompt listing the files this turn edited and the checks still owed: format, lint, typecheck, tests.

bandguard
★ 21v0.2.0GPL-3.0updated 2026-10-19fcsouza/agent-skills/mods/done-gate
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · done-gate
› fix the failing auth test and add an audit log call ⏺ Read(src/auth.ts) ⎿ Read 6 lines ⏺ Update(src/auth.ts) ⎿ Added 2 lines, removed 1 line ⏺ Bash(bun test) ⎿ 3 pass, 1 fail ● Done. refresh now rejects expired claims and logs an audit event. ✻ Worked for 42s · done 4:20 PM ● 3 files edited ✗ lint ✗ test [ Dismiss ] ⟨Claude Code's own drawing⟩ ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts

Draws

Band
● 3 files edited ✗ lint ✗ test [ Dismiss ] ⟨Claude Code's own drawing⟩
README

Agent Skills

Production-grade skills for AI coding agents (OpenClaw, Claude Code, and others).

Built by Fabricio Cavalcante — Software Engineer & AI Specialist.

Available Plugins

Plugins are complete workflow bundles — skills + agents + hooks working together as an integrated system. Install a plugin to get the full experience.

PluginDescriptionPlatform
game-dev26 skills, 7 commands, 3 agents, 5 hooks — complete game development workflow with engineering, design, narrative, and infrastructureGame Dev

Claude Code Mods

Mods are plugins built on function hooks: they run inside Claude Code, guard tool calls and draw above the prompt. See mods/ for install steps.

ModDescription
commit-guardBlocks commits with machine paths or .env files, git add -A, and pushes to main
prod-guardHolds Dokploy MCP writes until you press Proceed
bun-onlyRewrites npm, npx, yarn and pnpm to bun
done-gateShows edited files and the checks still owed
worktreesShows git worktrees, their changes, and the count
usage-ringsContext and plan usage, coloured by level
pr-statusThe current branch's PR: CI checks and review
sql-guardHolds writes to non-local databases until you press Proceed
pino-guardBlocks pino transports that break bundled logging

Available Skills

Skills are individual, cherry-pickable modules. Install only what you need.

Core

SkillDescriptionPlatform
claude-agent-sdkBuild production AI agents with the Claude Agent SDK — query(), hooks, subagents, custom tools, MCP servers, sessions, permissions, hostingClaude Code / API
database-performance-tuningDiagnose and fix slow databases like a DBA — pg_stat_statements, EXPLAIN plans, index design, query rewrites, vacuum and bloat, safe online rollout. Ships a read-only diagnostic scriptPostgreSQL / MySQL
foundry-vtt-module-devBuild, extend, and maintain Foundry VTT v14 modules — TypeDataModel, ApplicationV2 (detached windows), ActorSheetV2, hooks, sockets, dice, canvas/PIXI, Scene Levels, Regions as templates, ActiveEffects V2, v13→v14 migration, boilerplate filesFoundry VTT
foundry-vtt-system-devBuild Foundry VTT v14 game systems — system.json documentTypes, Actor/Item TypeDataModel, dice mechanics, combat/initiative, ActiveEffect V2 subtypes, data migration, character sheets, status effects, macros, enrichersFoundry VTT
openclaw-genieComprehensive OpenClaw gateway skill — installation, configuration, 38+ channels, memory, tools, hooks, deployment, multi-agentOpenClaw
nuvemshop-sdkPrepare, audit, implement, homologate, and publish Nuvemshop/Tiendanube apps — OAuth, API, NubeSDK, Nexo, Nimbus, webhooks, and App Store approvalNuvemshop
react-animationsReact animation patterns and utilitiesReact

Game Dev — Design

SkillDescription
game-design-fundamentalsCore loops, MDA framework, progression curves
game-economy-designVirtual economies, currencies, loot tables
level-designLevels, environments, difficulty curves
procedural-genDungeon gen, noise terrain, wave function collapse
quest-mission-designQuests, objectives, quest trees
skill-progression-treesSkill trees, talent trees, unlock graphs
ui-ux-gameHUD, menus, onboarding, accessibility

Game Dev — Engineering

SkillDescription
betterauth-integrationAuth, OAuth, JWT, RBAC
bullmq-game-queuesJob queues, async events, scheduled tasks
elevenlabs-sound-musicSFX generation, adaptive music, voice acting
game-backend-architectureGame servers, WebSocket, rooms, tick loops
game-state-syncClient-server sync, rollback netcode, delta compression
gameplay-analyticsRetention analytics, funnels, D1/D7/D30
matchmaking-systemMatchmaking, lobbies, ELO, skill-based queues
postgres-game-schemaGame DB schemas, Drizzle ORM, inventory
redis-game-patternsCaching, leaderboards, pub/sub, rate limiting
stripe-game-paymentsIn-app purchases, subscriptions, webhooks

Game Dev — Infrastructure

SkillDescription
ci-cd-gameCI/CD pipelines, GitHub Actions, deployment
claude-code-game-workflowEntry point for AI agents on game projects
cursor-codex-integrationCursor IDE, .cursorrules, Codex setup
monitoring-game-opsMonitoring, logging, telemetry, alerts

Game Dev — Narrative

SkillDescription
character-design-narrativeCharacters, NPCs, dialogue, archetypes
quest-narrative-coherenceNarrative coherence check, lore validation
story-structure-gameBranching narratives, player agency, story arcs
worldbuildingLore, factions, geography, world bibles

Structure

All skills follow a flat layout:

skills/<skill-name>/
├── README.md           # Overview and installation instructions
├── SKILL.md            # Main skill file (YAML frontmatter + body)
├── boilerplate/        # Starter code to copy and customize (optional)
├── templates/          # Document and config templates (optional)
├── references/         # Deep-dive reference files (optional)
└── ARCHITECTURE.md     # System design decisions (optional)
  • SKILL.md is always the entry point — read this first
  • boilerplate/ files are starter code, copy and customize
  • templates/ are document/config templates to fill in
  • ARCHITECTURE.md explains system design decisions

Installation

game-dev plugin (Claude Code)

/plugin marketplace add fcsouza/agent-skills
/plugin install game-dev@fcsouza-agent-skills

See plugins/game-dev/README.md for the full skill index, commands, and agents.

Individual skills (cherry-pick)

# Install a specific skill
npx skills add fcsouza/agent-skills --skill game-design-fundamentals

# Install all game-dev engineering skills at once
npx skills add fcsouza/agent-skills --skill betterauth-integration --skill postgres-game-schema --skill game-backend-architecture

# List all available skills
npx skills add fcsouza/agent-skills --list

Manual

# Plugin (full bundle)
cp -r plugins/game-dev/ .claude/plugins/game-dev/

# Individual skill
cp -r skills/<skill-name>/ .claude/skills/<skill-name>/

# For OpenClaw
cp -r skills/<skill-name>/ ~/.openclaw/workspace/skills/<skill-name>/

License

GPL-3.0

Source 2 files
hooks/register.tsx 98 lines
1import type { EngineInterface, Register } from 'claude-code';
2
3import { type Check, checksIn, checksOffered, isCodeFile } from './checks';
4
5// Files edited since the checks last all passed, and when each check last passed.
6const edited = new Map<string, number>();
7const passedAt = new Map<Check, number>();
8let offered: Check[] = [];
9let editedAt = 0;
10
11const EDIT_TOOLS = new Set(['Edit', 'Write', 'MultiEdit', 'NotebookEdit']);
12
13// Check names for a narrow band.
14const SHORT: Record<Check, string> = { format: 'fmt', lint: 'lint', typecheck: 'tsc', test: 'test' };
15
16async function loadOffered($: EngineInterface): Promise<void> {
17  const cwd = await $.session.cwd();
18  const file = await $.fs.read(`${cwd}/package.json`).catch(() => null);
19  offered = file === null ? [] : checksOffered(file);
20}
21
22const missing = (): Check[] => offered.filter(check => (passedAt.get(check) ?? 0) < editedAt);
23
24export const register: Register = on => {
25  on('session.start', async ($, e, next) => {
26    const started = await next(e);
27    await loadOffered($);
28    return started;
29  });
30
31  on('tool.call', async ($, e, next) => {
32    const ran = await next(e);
33    if (ran.deny !== undefined || ran.isError === true) {
34      return ran;
35    }
36
37    if (EDIT_TOOLS.has(e.tool)) {
38      const input = e as { file_path?: unknown; notebook_path?: unknown };
39      const path = String(input.file_path ?? input.notebook_path ?? '');
40      if (isCodeFile(path)) {
41        editedAt = await $.clock.now();
42        edited.set(path, editedAt);
43        $.ui.invalidate('ui.render');
44      }
45      return ran;
46    }
47
48    if (e.tool === 'Bash') {
49      const command = String((e as { command?: unknown }).command ?? '');
50      const checks = checksIn(command);
51      if (checks.length > 0) {
52        const at = await $.clock.now();
53        for (const check of checks) passedAt.set(check, at);
54        if (missing().length === 0) edited.clear();
55        $.ui.invalidate('ui.render');
56      }
57      if (/package\.json/.test(command)) await loadOffered($);
58    }
59    return ran;
60  }).catch(($, e, next) => next(e));
61
62  on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
63    const below = await next(e);
64    if (e.props.hasSurvey) {
65      return below;
66    }
67    const owed = missing();
68    if (edited.size === 0 || owed.length === 0) {
69      return below;
70    }
71
72    const { Box, Button, Text } = $.ui.resolve(e);
73    const narrow = (e.viewport?.columns ?? Number.POSITIVE_INFINITY) < 80;
74    return (
75      <Box flexDirection="column">
76        <Box gap={1} flexWrap="wrap">
77          <Text color="#f59e0b">●</Text>
78          <Text>{narrow ? `${edited.size} edited` : `${edited.size} file${edited.size === 1 ? '' : 's'} edited`}</Text>
79          {offered.map(check => (
80            <Text color={owed.includes(check) ? '#ef4444' : '#22c55e'}>
81              {owed.includes(check) ? '✗' : '✓'} {narrow ? SHORT[check] : check}
82            </Text>
83          ))}
84          <Button
85            key="dismiss"
86            label="Dismiss"
87            onPress={() => {
88              edited.clear();
89              $.ui.invalidate('ui.render');
90            }}
91          />
92        </Box>
93        {below}
94      </Box>
95    );
96  });
97};
98
hooks/checks.ts 40 lines
1// Which checks a project has, and which shell commands count as running them.
2
3export type Check = 'format' | 'lint' | 'typecheck' | 'test';
4
5export const CHECKS: readonly Check[] = ['format', 'lint', 'typecheck', 'test'];
6
7const CODE_FILE = /\.(ts|tsx|js|jsx|mjs|cjs|mts|cts|json|jsonc|css|scss|vue|svelte|astro)$/;
8
9export const isCodeFile = (path: string): boolean => CODE_FILE.test(path) && !/(^|\/)(bun\.lock|package-lock\.json)$/.test(path);
10
11const RUNS: Record<Check, RegExp> = {
12  format: /\b(bun run (format|fmt)\b|ultracite (fix|format)\b|biome (format|check)\b.*--write)/,
13  lint: /\b(bun run (lint|lint:\S+|check)\b|ultracite (lint|check)\b|biome (lint|check)\b|eslint\b)/,
14  typecheck: /\b(bun run (typecheck|type-check|tsc|check-types|types)\b|tsc\b|bunx tsc\b|vue-tsc\b)/,
15  test: /\b(bun (run )?test\b|vitest\b|jest\b|playwright test\b)/,
16};
17
18/** The checks a command line runs. */
19export function checksIn(command: string): Check[] {
20  return CHECKS.filter(check => RUNS[check].test(command));
21}
22
23/** The checks a package.json offers through its scripts. */
24export function checksOffered(packageJson: string): Check[] {
25  let scripts: Record<string, unknown> = {};
26  try {
27    scripts = (JSON.parse(packageJson) as { scripts?: Record<string, unknown> }).scripts ?? {};
28  } catch {
29    return [];
30  }
31  const names = Object.keys(scripts);
32  const has = (pattern: RegExp) => names.some(name => pattern.test(name));
33  return CHECKS.filter(check => {
34    if (check === 'format') return has(/^(format|fmt)$/);
35    if (check === 'lint') return has(/^lint(:|$)|^check$/);
36    if (check === 'typecheck') return has(/^(typecheck|type-check|tsc|check-types|types)$/);
37    return has(/^test(:|$)/);
38  });
39}
40