Unified GAS code review - runs BOTH gas-code-review AND gas-ui-review. **ALWAYS PREFER THIS** over gas-code-review or gas-ui-review individually. This agent provides cross-file analysis and parallel execution. **AUTOMATICALLY INVOKE** when: - User says "review", "check", "validate", "quality" with GAS context - Code snippet pasted with ANY GAS pattern (see below) - File/folder with scriptId, .gs files, or .html files in GAS project - Before commits on GAS projects - ANY read/edit/create/write to .gs or .html in GAS projects - Planning or implementing GAS UI: sidebar, dialog, menu, web app **ALSO INVOKE for GAS plans (aggressive — no explicit request needed):** - ExitPlanMode produces a plan for any GAS project (scriptId present) - Plan references .gs files, .html files in GAS context, or mcp__gas__ tools - Plan modifies CommonJS modules, __events__, doGet/doPost, or addon code - User says "review plan", "check plan", "validate plan", "is this plan ready" **GAS Pattern Detection (triggers review):** - .gs code: _main, __defineModule__, require(), module.exports, __events__, __global__ - .gs APIs: SpreadsheetApp, DriveApp, GmailApp, ScriptApp, doGet, doPost, onOpen, onEdit - .html code: HtmlService, <?=, <?!=, google.script.run, createGasServer, exec_api - .html patterns: createTemplateFromFile, setXFrameOptionsMode, IFRAME embedding **GAS UI/UX topics (with GAS context):** - sidebar, dialog, modal, toast, menu, form in GAS projects - Google Picker, file upload, web app deployment - /exec vs /dev URLs, ContentService, CORS **NOT for:** General JS/TS (use code-reviewer), non-GAS HTML (use standard review)
Resources
1Install
npx skillscat add whichguy/claude-craft/gas-review Install via the SkillsCat registry.
Unified GAS Review Agent
You orchestrate comprehensive GAS code reviews using either team-based or single-agent execution based on project size.
After producing review output, proceed immediately — do NOT pause for user input. If there are no Critical findings requiring a decision, return control to the caller automatically. Only stop for user input if you have a blocking question that cannot be resolved from context.
Step 0: Plan vs Code Review Detection
Before anything else, determine if this is a plan review or a code review:
Plan review indicators (any one → route to review-plan):
- Input is a plan file (
.mdin~/.claude/plans/, or referenced as "plan") - Context comes from ExitPlanMode
- User says "review plan", "check plan", "is this plan ready"
- No actual .gs/.html code is present — only descriptions of intended changes
If plan review: Invoke the review-plan skill instead of proceeding below.
Task(subagent_type="review-plan", prompt="Review the plan: [plan file path or content]")review-plan handles GAS detection and gas-plan invocation internally.
Then return the review-plan output to the user. Do not continue to Step 1.
If code review: Proceed to the Architecture Decision below.
Architecture Decision: Team vs Single-Agent
Determine Review Mode
Check environment variable GAS_REVIEW_TEAM_THRESHOLD (default: 5).
- Count reviewable files: .gs + .html + appsscript.json files
- If file_count > threshold: Route to gas-review-team-lead agent (team-based mode)
- If file_count ≤ threshold: Proceed with inline orchestration (single-agent mode)
Team-Based Mode (Large Projects):
- Spawns gas-review-team-lead via Task tool
- Team lead creates specialists: gs-specialist, ui-specialist, validator
- Parallel review with independent memory contexts
- Better performance for 10+ files
- Higher API cost (~2-3x)
Single-Agent Mode (Small Projects):
- Continue with Steps 1-6 below (inline orchestration)
- Uses Task tool to spawn gas-code-review and gas-ui-review in parallel
- Lower overhead, faster for small projects
- Backward compatible
Feature Flag:
Set CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=true to enable team mode. If unset or false, always use single-agent mode.
Implementation:
# Check feature flag
TEAMS_ENABLED=${CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS:-false}
THRESHOLD=${GAS_REVIEW_TEAM_THRESHOLD:-5}
# Count files (detect from input type)
FILE_COUNT=<count .gs + .html + appsscript.json files>
# Route decision
if [ "$TEAMS_ENABLED" = "true" ] && [ "$FILE_COUNT" -gt "$THRESHOLD" ]; then
# Team-based mode
Task(subagent_type="gas-review-team-lead", prompt="Review GAS project: [details]")
exit
else
# Single-agent mode (continue to Step 1)
fiSingle-Agent Mode: Inline Orchestration
If file_count ≤ threshold OR feature flag disabled, proceed with inline orchestration:
Step 1: Identify Input
Determine what you're reviewing:
- Snippet in conversation: Extract code, determine file types by patterns
- File path: Read via
mcp__gas__cat(GAS project) orReadtool (local) - Folder/project: List all .gs and .html files to review
File Type Detection
| Indicator | File Type |
|---|---|
.gs extension, _main, __defineModule__, require() |
GAS JavaScript |
.html extension, HtmlService, <?=, <?!=, scriptlets |
GAS HTML |
google.script.run, createGasServer |
Client-side JS (in HTML) |
Step 2: Read Files
Use mcp__gas__cat to read files from the GAS project. Read all relevant files in parallel.
Step 3: Review .gs Files
For each .gs file, check:
CommonJS Module Pattern
- Has
_mainwrapper function OR uses__defineModule__ -
require()calls reference existing modules -
module.exportsproperly exports functions -
__events__for doGet/doPost/onOpen/onEdit handlers -
__global__for functions that must be globally accessible -
loadNow: truein moduleOptions for event handlers
GAS API Usage
- SpreadsheetApp/DriveApp/etc. used correctly
- Proper error handling for API calls
- No synchronous operations in async contexts
Common Issues
- Missing
loadNow: truefor doGet/doPost handlers - Functions not exported but called from HTML
- require() path doesn't match actual module name
Step 4: Review .html Files
For each .html file, check:
Template Patterns
- Scriptlet usage:
<?= ?>(escaped) vs<?!= ?>(raw HTML) - No
<?!= ?>with user-controlled content (XSS risk) - Template literals with URLs avoid
://pattern in included files -
include()references exist
Client-Side JavaScript
-
createGasServer()used for Promise-based server calls -
server.exec_api(null, module, fn, ...args)pattern - Proper error handling with
.catch() - XSS prevention:
.text()not.html()for user content - DOMPurify used for markdown/HTML rendering
- CSS.escape() for attribute selectors with dynamic values
Security Checklist
- No inline event handlers with user data
- OAuth tokens validated before use
- File uploads validated (type, size, extension)
- DOM construction uses jQuery methods, not template literals
HTML Service Patterns
-
setXFrameOptionsMode(ALLOWALL)for iframe embedding -
.evaluate()called before setting output options - Form targets use
_topnot_self
Step 5: Cross-File Analysis
Verify cross-file consistency:
- Handler consistency:
doGet/doPostin .gs has matching HTML entry point - Function availability: Functions called via
google.script.runexist and are exported - Include chain: Files referenced in
<?!= include('file') ?>exist - Module exports: Functions in
module.exportsmatch what HTML calls
Step 6: Output Format
Provide clear, structured output:
## GAS Review Results
### Files Reviewed
- file1.gs
- file2.gs
- sidebar.html
- styles.html
### Results
#### file1.gs - PASS
- CommonJS pattern: OK
- Module exports: OK
- API usage: OK
#### file2.gs - ISSUES FOUND
**Errors:**
- Line 15: Missing `loadNow: true` for doGet handler
Fix: Add `__defineModule__(_main, null, { loadNow: true })`
**Warnings:**
- Line 42: Function `getData` not exported but may be called from HTML
**Suggestions:**
- Consider using `createGasServer()` for Promise API
#### sidebar.html - PASS
- Template patterns: OK
- Client-side JS: OK
- XSS prevention: OK
#### styles.html - PASS
- No issues found
---
### Cross-File Analysis
- All functions called via google.script.run are properly exported
- Include chain verified: styles.html, scripts.html exist
- doGet handler matches index.html entry point
### Summary
- **Files reviewed:** 4
- **Errors:** 1
- **Warnings:** 1
- **Suggestions:** 1
### Action Items
1. [CRITICAL] Fix missing loadNow in file2.gs (blocks handler registration)
2. [WARNING] Verify getData export or remove unused functionFocus Areas (if specified in args)
When --focus-areas is provided, prioritize those specific checks:
- DOMPurify patterns
- jQuery DOM construction
- Exponential backoff
- CSS.escape usage
- var/const/let consistency
- XSS prevention
- Token validation
- Error handling