← Back to list

erpnext-code-validator
by OpenAEC-Foundation
28 deterministic Claude AI skills for flawless ERPNext/Frappe v14-16 development. Agent Skills standard compliant.
⭐ 1🍴 1📅 Jan 23, 2026
SKILL.md
name: erpnext-code-validator description: "Intelligent agent for validating ERPNext/Frappe code against best practices and common pitfalls. Use when reviewing generated code, checking for errors before deployment, or validating code quality. Triggers: review this code, check my script, validate before deployment, is this correct, find bugs, check for errors, will this work."
ERPNext Code Validator Agent
This agent validates ERPNext/Frappe code against established patterns, common pitfalls, and version compatibility requirements.
Purpose: Catch errors BEFORE deployment, not after
When to Use This Agent
┌─────────────────────────────────────────────────────────────────────┐
│ CODE VALIDATION TRIGGERS │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ► Code has been generated and needs review │
│ "Check this Server Script before I save it" │
│ └── USE THIS AGENT │
│ │
│ ► Code is causing errors │
│ "Why isn't this working?" │
│ └── USE THIS AGENT │
│ │
│ ► Pre-deployment validation │
│ "Is this production-ready?" │
│ └── USE THIS AGENT │
│ │
│ ► Code review for best practices │
│ "Can this be improved?" │
│ └── USE THIS AGENT │
│ │
└─────────────────────────────────────────────────────────────────────┘
Validation Workflow
┌─────────────────────────────────────────────────────────────────────┐
│ CODE VALIDATOR WORKFLOW │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ STEP 1: IDENTIFY CODE TYPE │
│ ══════════════════════════ │
│ • Client Script (JavaScript) │
│ • Server Script (Python sandbox) │
│ • Controller (Python full) │
│ • hooks.py configuration │
│ • Jinja template │
│ • Whitelisted method │
│ │
│ STEP 2: RUN TYPE-SPECIFIC CHECKS │
│ ═════════════════════════════════ │
│ • Apply checklist for identified code type │
│ • Check syntax patterns │
│ • Verify API usage │
│ │
│ STEP 3: CHECK UNIVERSAL RULES │
│ ══════════════════════════════ │
│ • Error handling present │
│ • User feedback appropriate │
│ • Security considerations │
│ • Performance implications │
│ │
│ STEP 4: VERIFY VERSION COMPATIBILITY │
│ ════════════════════════════════════ │
│ • v14/v15/v16 specific features │
│ • Deprecated patterns │
│ • Version-specific behaviors │
│ │
│ STEP 5: GENERATE VALIDATION REPORT │
│ ══════════════════════════════════ │
│ • Critical errors (must fix) │
│ • Warnings (should fix) │
│ • Suggestions (nice to have) │
│ • Corrected code (if errors found) │
│ │
└─────────────────────────────────────────────────────────────────────┘
→ See references/workflow.md for detailed validation steps.
Critical Checks by Code Type
Server Script Checks
┌─────────────────────────────────────────────────────────────────────┐
│ ⚠️ SERVER SCRIPT CRITICAL CHECKS │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ [FATAL] Import statements │
│ ═══════════════════════════ │
│ ❌ import json → Use frappe.parse_json() │
│ ❌ from frappe.utils import X → Use frappe.utils.X() │
│ ❌ import requests → IMPOSSIBLE in Server Script │
│ │
│ [FATAL] Undefined variables │
│ ════════════════════════════ │
│ ❌ self.field → Use doc.field │
│ ❌ document.field → Use doc.field │
│ │
│ [FATAL] Wrong event handling │
│ ═══════════════════════════════ │
│ ❌ try/except for validation → Just frappe.throw() │
│ │
│ [ERROR] Event name mismatch │
│ ═══════════════════════════ │
│ ❌ Event "Before Save" code in "After Save" script │
│ │
│ [WARNING] Missing validation │
│ ═══════════════════════════════ │
│ ⚠️ No null/empty checks before operations │
│ │
└─────────────────────────────────────────────────────────────────────┘
Client Script Checks
┌─────────────────────────────────────────────────────────────────────┐
│ CLIENT SCRIPT CRITICAL CHECKS │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ [FATAL] Wrong API usage │
│ ═════════════════════════ │
│ ❌ frappe.db.get_value() → Server-side only! │
│ ❌ frappe.get_doc() → Server-side only! │
│ ✓ frappe.call() for server data │
│ │
│ [FATAL] Missing async handling │
│ ══════════════════════════════ │
│ ❌ let result = frappe.call() → Returns undefined │
│ ✓ frappe.call({callback: fn}) → Use callback │
│ ✓ await frappe.call({async:false}) → Or async/await │
│ │
│ [ERROR] Field refresh issues │
│ ════════════════════════════ │
│ ❌ frm.set_value() without refresh │
│ ✓ frm.set_value() then frm.refresh_field() │
│ │
│ [WARNING] Form state checks │
│ ═══════════════════════════ │
│ ⚠️ Not checking frm.doc.__islocal for new docs │
│ ⚠️ Not checking frm.doc.docstatus for submitted docs │
│ │
└─────────────────────────────────────────────────────────────────────┘
Controller Checks
┌─────────────────────────────────────────────────────────────────────┐
│ CONTROLLER CRITICAL CHECKS │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ [FATAL] Wrong lifecycle usage │
│ ═════════════════════════════ │
│ ❌ Modifying self.field in on_update → Changes NOT saved! │
│ ✓ Use frappe.db.set_value() in on_update │
│ │
│ [FATAL] Missing super() call │
│ ════════════════════════════ │
│ ❌ def validate(self): pass → Breaks parent validation │
│ ✓ def validate(self): super().validate() │
│ │
│ [ERROR] Transaction assumptions │
│ ═══════════════════════════════ │
│ ❌ Assuming rollback on error in on_update │
│ (only validate and before_* roll back on error) │
│ │
│ [ERROR] Circular save │
│ ══════════════════════ │
│ ❌ self.save() inside lifecycle hooks │
│ ❌ doc.save() for same document in hooks │
│ │
└─────────────────────────────────────────────────────────────────────┘
→ See references/checklists.md for complete checklists.
Validation Report Format
## Code Validation Report
### Code Type: [Server Script / Client Script / Controller / etc.]
### Target DocType: [DocType name]
### Event/Trigger: [Event name]
---
### 🔴 CRITICAL ERRORS (Must Fix)
| Line | Issue | Fix |
|------|-------|-----|
| 3 | Import statement in Server Script | Use frappe.utils.X() directly |
### 🟡 WARNINGS (Should Fix)
| Line | Issue | Recommendation |
|------|-------|----------------|
| 12 | No null check before .lower() | Add: if value: value.lower() |
### 🔵 SUGGESTIONS (Nice to Have)
| Line | Suggestion |
|------|------------|
| 8 | Consider using frappe.db.get_value for single field |
---
### Corrected Code
```python
# [Corrected version with all critical errors fixed]
Version Compatibility
| Version | Status |
|---|---|
| v14 | ✅ Compatible |
| v15 | ✅ Compatible |
| v16 | ✅ Compatible |
## Universal Validation Rules
These apply to ALL code types:
### Security Checks
| Check | Severity | Description |
|-------|----------|-------------|
| SQL Injection | CRITICAL | Raw user input in SQL queries |
| Permission bypass | CRITICAL | Missing permission checks before operations |
| XSS vulnerability | HIGH | Unescaped user input in HTML |
| Sensitive data exposure | HIGH | Logging passwords/tokens |
### Error Handling Checks
| Check | Severity | Description |
|-------|----------|-------------|
| Silent failures | HIGH | Catching exceptions without handling |
| Missing user feedback | MEDIUM | Errors not communicated to user |
| Generic error messages | LOW | "An error occurred" without details |
### Performance Checks
| Check | Severity | Description |
|-------|----------|-------------|
| Query in loop | HIGH | frappe.db.* inside for loop |
| Unbounded query | MEDIUM | SELECT without LIMIT |
| Unnecessary get_doc | LOW | get_doc when get_value suffices |
→ See [references/examples.md](references/examples.md) for validation examples.
## Version-Specific Validations
### v16 Features (Fail on v14/v15)
```python
# These ONLY work on v16+
extend_doctype_class = {} # hooks.py - v16 only
naming_rule = "UUID" # DocType - v16 only
pdf_renderer = "chrome" # Print Format - v16 only
Deprecated Patterns (Warn)
# DEPRECATED - still works but should update
frappe.bean() # Use frappe.get_doc()
frappe.msgprint(raise_exception=True) # Use frappe.throw()
job_name parameter # Use job_id (v15+)
Version-Specific Behaviors
| Behavior | v14 | v15/v16 |
|---|---|---|
| Scheduler tick | 240s | 60s |
| Background job dedup | job_name | job_id |
Quick Validation Commands
Server Script Quick Check
- ❌ Any
importstatements? → FATAL - ❌ Any
self.references? → FATAL (usedoc.) - ❌ Any
try/except? → WARNING (usually wrong) - ✅ Uses
frappe.throw()for validation errors? → GOOD - ✅ Uses
doc.fieldfor document access? → GOOD
Client Script Quick Check
- ❌ Any
frappe.db.*calls? → FATAL (server-side only) - ❌ Any
frappe.get_doc()calls? → FATAL (server-side only) - ❌
frappe.call()without callback? → FATAL (async issue) - ✅ Uses
frm.doc.fieldfor field access? → GOOD - ✅ Uses
frm.refresh_field()after changes? → GOOD
Controller Quick Check
- ❌ Modifying
self.*inon_update? → ERROR (won't save) - ❌ Missing
super().method()calls? → WARNING - ❌
self.save()in lifecycle hook? → FATAL (circular) - ✅ Imports at top of file? → GOOD (controllers allow imports)
- ✅ Error handling with try/except? → GOOD (controllers allow this)
Integration with Other Skills
This validator uses knowledge from:
| Skill | What It Provides |
|---|---|
erpnext-syntax-* | Correct syntax patterns |
erpnext-impl-* | Correct implementation patterns |
erpnext-errors-* | Error handling patterns |
erpnext-database | Query patterns and pitfalls |
erpnext-permissions | Permission check patterns |
erpnext-api-patterns | API response patterns |
Validation Depth Levels
| Level | Checks | Use When |
|---|---|---|
| Quick | Fatal errors only | Initial scan |
| Standard | + Warnings | Pre-deployment |
| Deep | + Suggestions + Optimization | Production review |
Default: Standard level for most validations.
Score
Total Score
75/100
Based on repository quality metrics
✓SKILL.md
SKILL.mdファイルが含まれている
+20
✓LICENSE
ライセンスが設定されている
+10
✓説明文
100文字以上の説明がある
+10
○人気
GitHub Stars 100以上
0/15
✓最近の活動
1ヶ月以内に更新
+10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
✓タグ
1つ以上のタグが設定されている
+5
Reviews
💬
Reviews coming soon

