Agent skill
rule-validator
Validate code compliance with Gemini mod rules (core, modules, features, UI, WebSocket, state)
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/rule-validator
SKILL.md
Gemini Rules Validator Skill
How to Use
When you want to validate code compliance:
/rule-validator src/features/myFeature
/rule-validator <file-or-folder>
/validate # Validate current selection
Validation Scope
1. Core Rules (src/*)
Applies to all code in the repo.
Rule 1: No Hardcoded Game Data
Forbidden patterns:
- Plant names:
'Carrot','Tomato', etc. - Item IDs: hardcoded numeric item IDs
- Pet/mutation/shop data as strings/numbers
- Sprite frame references as literals
Check for:
// ❌ BAD
const plantName = 'Carrot';
const itemId = 42;
const spriteName = 'plant_carrot_lvl1';
// ✅ GOOD
const plant = MGData.get('plants')['carrot'];
const item = MGData.get('items')[itemId];
const sprite = await MGSprite.show('plant', plantName);
What to report:
- File + line number
- The hardcoded value
- Suggested fix: "Use MGData.get(...) instead"
Rule 2: Boundaries (DOM, WebSocket, State)
Forbidden:
- DOM rendering outside
src/ui/ - Direct WebSocket sends (
websocket.send()outsidesrc/websocket/api.ts) - Direct state mutations (not via Store API)
- Ad-hoc globals (
window.myGlobal = ...as second source of truth)
Check for:
// ❌ BAD - in src/features/myFeature/index.ts
document.createElement('div'); // DOM in features
websocket.send(message); // Direct WS send
window.myState = value; // Ad-hoc global
atom.value = newValue; // Direct mutation
// ✅ GOOD
// In src/ui/components/...
const root = document.createElement('div');
// In src/websocket/api.ts
export function sendAction(...) { websocket.send(...) }
// In src/features/...
const unsub = await Store.subscribe('myAtom', callback);
What to report:
- File + line number
- Pattern detected
- Suggested fix: "Move DOM to src/ui/" or "Use Store API" etc.
Rule 3: Side Effects & Cleanup
Forbidden on import:
- Event listeners without cleanup
- Intervals/timeouts without cancellation
- WebSocket subscriptions without unsubscribe
- Audio playback on import
- Patches or monkey-patching
Check for:
// ❌ BAD - at module level
window.addEventListener('click', handler); // No cleanup
setInterval(() => {...}, 1000); // Runs forever
const unsub = Store.subscribe(...); // Unsub lost
// ✅ GOOD
let unsub: (() => void) | null = null;
export function init() {
window.addEventListener('click', handler);
unsub = () => window.removeEventListener('click', handler);
}
export function destroy() {
unsub?.();
unsub = null;
}
What to report:
- File + line number
- Effect type (listener, interval, etc.)
- Pattern: "Side effect at module level detected"
- Suggestion: "Wrap in init()/destroy() functions"
Rule 4: Storage Namespacing
Forbidden:
- Direct
GM_getValue/GM_setValuecalls - Non-namespaced keys
- Undefined storage keys
Check for:
// ❌ BAD
GM_setValue('myKey', value);
const key = 'random-key';
// ✅ GOOD
import { KEYS } from 'src/utils/storage';
GM_setValue(KEYS.MY_FEATURE, value); // Prefixed with gemini:
What to report:
- File + line number
- Key used (if visible)
- Suggestion: "Use KEYS from src/utils/storage"
Rule 5: Code Quality (Files < 500 lines)
Check for:
- Files exceeding 500 lines
- Functions exceeding 50 lines (warning threshold)
- Single-letter variable names (a, i, x outside loops)
- Magic numbers/strings without constants
What to report:
- File + line count
- Suggestion: "Split by responsibility"
- Magic numbers: "Extract to const CONSTANT_NAME"
Rule 6: TypeScript Strict (no any)
Forbidden:
anytype usage- Unconstrained generics
Check for:
// ❌ BAD
function handle(data: any) {}
// ✅ GOOD
function handle(data: unknown) {
if (typeof data === 'object' && data !== null) { ... }
}
What to report:
- File + line number
- The
anyusage - Suggestion: "Use
unknown+ type narrowing"
2. Feature Rules (src/features/*)
Feature Structure Check
Expected files:
src/features/myFeature/
├── types.ts # ✅ Required
├── index.ts # ✅ Required
├── state.ts # ⚠️ If persistent state
├── ui.ts # ⚠️ If visual elements
├── middleware.ts # ⚠️ If WS outgoing
├── handler.ts # ⚠️ If WS incoming
└── logic/ # 📁 Recommended
├── core.ts
└── helpers.ts
Check for:
- Missing
types.tsorindex.ts - Config without
enabled: boolean - Storage key not using FEATURE_KEYS prefix
Feature API Exposure
Check in src/features/index.ts:
// ✅ GOOD
export { MGMyFeature } from './myFeature';
export type { MyFeatureConfig } from './myFeature';
Check in src/api/index.ts:
// ✅ GOOD
Features: {
MyFeature: MGMyFeature,
}
Check in src/ui/loader/bootstrap.ts:
// ✅ GOOD
{ name: "MyFeature", init: MGMyFeature.init.bind(MGMyFeature) }
What to report:
- Feature not exported from index.ts
- Feature not in GeminiAPI
- Feature not initialized in bootstrap
3. Module Rules (src/modules/*)
Module Structure
Modules MUST:
- Always be active (no toggle)
- Export named exports (not default)
- Have proper initialization if needed
- Be listed in core module list
Check for:
- Modules with
enabledconfig (should be modules, not features) - Toggles in module structure
4. UI Rules (src/ui/*)
Component Factory Pattern
Check for factory violations:
// ❌ BAD
export function MyButton() { return <JSX>... }
// ✅ GOOD
export interface Options { label: string; onClick?: () => void }
export interface Handle { root: HTMLElement; destroy(): void }
export function create(options: Options): Handle { ... }
What to report:
- Missing Options/Handle interfaces
- No destroy() method
- Direct JSX exports
Shadow DOM Isolation
Check for:
- Direct DOM queries outside Shadow DOM boundary
- CSS not using CSS variables
- Hardcoded colors (should be theme tokens)
5. WebSocket Rules (src/websocket/*)
File Responsibilities
Check locations:
- Type definitions ONLY in
protocol.ts - Transport logic ONLY in
connection.ts - Public API ONLY in
api.ts - Handlers ONLY in
handlers/ - Middlewares ONLY in
middlewares/
What to report:
- Message type defined outside protocol.ts
- Logic mixed into wrong file
No Hardcoded Message Types
Check for:
// ❌ BAD
if (type === 'plant_action') { ... }
// ✅ GOOD
import { WS_TYPES } from './protocol';
if (type === WS_TYPES.PLANT_ACTION) { ... }
Validation Report Format
When violations are found, report as:
🚨 RULE VIOLATIONS FOUND (Gemini Mod)
[File: src/features/myFeature/index.ts]
├─ ❌ Rule 1: Hardcoded Game Data (line 42)
│ └─ Found: const plantName = 'Carrot'
│ └─ Fix: Use MGData.get('plants')['carrot']
│
├─ ⚠️ Rule 5: Code Quality (lines: 312)
│ └─ File exceeds 500 lines (actual: 612)
│ └─ Suggestion: Split by responsibility
│
└─ ❌ Rule 2: Boundaries (line 89)
└─ Found: Direct WebSocket send
└─ Fix: Use websocket/api.ts actions instead
✅ PASSED CHECKS:
├─ Feature structure (types.ts, index.ts present)
├─ Storage keys namespaced correctly
├─ TypeScript strict (no `any` found)
└─ Side effect cleanup present
📋 SUMMARY: 3 violations, 4 checks passed
💡 Next steps: Review suggested fixes above
Usage in Review Workflows
Before Commit
/rule-validator src/ # Validate entire src/
/rule-validator dist/ # Skip dist builds
Before PR
/rule-validator src/features/newFeature
/rule-validator src/ui/components/NewComponent
Full Repo Audit
/rule-validator . # Entire project
Configuration
Ignore Patterns (Optional)
Can skip certain paths:
dist/— Build outputnode_modules/— DependenciesGameSourceFiles/— Reference onlyGameFilesExample/— Examples only
Severity Levels
- 🚨 Error — Must fix before commit
- ⚠️ Warning — Consider fixing
- ℹ️ Info — Best practice suggestion
Common False Positives & How to Handle
| Detection | Reality | Action |
|---|---|---|
'Carrot' in comment |
Actually just documentation | Ignore |
any in test file |
Test-only, acceptable | Allow |
| 600-line file | Truly complex, can't split | Document why |
| WS send in tests | Mock data, OK | Allow |
When reporting: Flag but don't block if edge case is justified.
Rules Priority (Strict → Lenient)
🔴 Strict (Never compromise)
- No hardcoded game data (MGData required)
- No direct WebSocket sends
- No side effects on import
- TypeScript strict (no
any)
🟠 Medium (Be thoughtful)
- Storage namespacing
- File size (< 500 lines)
- Cleanup discipline
🟡 Low (Guidance only)
- Code organization
- Naming conventions
- Documentation
Integration with /clear Workflow
When you /clear before starting a new task:
/rule-validator src/ # Run full validation
→ Fix any violations
→ Commit with pre-commit-gate skill
→ Proceed with clean slate
This ensures you never accumulate debt across task boundaries.
Didn't find tool you were looking for?