frappe-agent-architect
Use when designing multi-app Frappe architectures, deciding whether to split functionality into separate apps, or implementing cross-app communication…
Use when implementing server-side features via Setup > Server Script: document validation, auto-fill, API endpoints, scheduled tasks, permission queries. Covers sandbox-safe coding, script type selection, testing, migration to controllers. Keywords: how to implement server
$ npx -y skills add Impertio-Studio/Frappe_Claude_Skill_Package --skill frappe-impl-serverscripts --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/frappe-impl-serverscriptsContext preview
The summary Claude sees to decide when to auto-load this skill.
Use when implementing server-side features via Setup > Server Script: document validation, auto-fill, API endpoints, scheduled tasks, permission queries. Covers sandbox-safe coding, script type selection, testing, migration to controllers. Keywords: how to implement server
name: frappe-impl-serverscripts description: > Use when implementing server-side features via Setup > Server Script: document validation, auto-fill, API endpoints, scheduled tasks, permission queries. Covers sandbox-safe coding, script type selection, testing, migration to controllers. Keywords: how to implement server script, which script type, sandbox limitation, Document Event, API script, Scheduler Event, Permission Query, migrate to controller, no-code automation, run code on save, auto-fill field, server-side validation, scheduled script. license: MIT compatibility: "Claude Code, Claude.ai Projects, Claude API. Frappe v14-v16." metadata: author: OpenAEC-Foundation version: "2.0"
Step-by-step workflows for building server-side features without a custom app. For exact syntax, see `frappe-syntax-serverscripts`.
**Version**: v14/v15/v16 | **v15+ Note**: Server Scripts disabled by default — enable with `bench set-config server_script_enabled true`
ALL IMPORTS BLOCKED — RestrictedPython sandbox import json → ImportError: __import__ not found from frappe.utils → ImportError import requests → ImportError SOLUTION: Use pre-loaded namespace: frappe.utils.nowdate() frappe.utils.flt() frappe.parse_json(data) json.loads() (json IS available) frappe.as_json(obj) json.dumps() frappe.make_get_request(url) (replaces requests.get)
**Rule**: If you need `import` statements beyond `json`, ALWAYS use a Controller instead.
1. Enable server scripts: `bench set-config server_script_enabled true` 2. Navigate to **Setup > Server Script** (or awesomebar: "New Server Script") 3. Select **Script Type** (see decision tree below) 4. Configure type-specific settings (DocType, event, API method, cron) 5. Write script in the editor 6. Save — script is active immediately 7. Test by triggering the configured event 8. Use "Compare Versions" button to diff changes
WHAT DO YOU NEED?
│
├── React to document save/submit/cancel?
│ └── Document Event
│ └── Select DocType + Event (Before Save, After Save, etc.)
│
├── Create a REST API endpoint?
│ └── API
│ └── Set method name + guest access setting
│ └── Endpoint: /api/method/{method_name}
│
├── Run task on schedule (daily/hourly/cron)?
│ └── Scheduler Event
│ └── Set cron pattern or frequency
│
└── Filter list views per user/role?
└── Permission Query
└── Select DocType — set `conditions` variable> See [references/decision-tree.md](references/decision-tree.md) for complete decision tree.
**Goal**: Validate Sales Order before save.
**Step 1**: Choose event — "Before Save" maps to `validate` hook.
**Step 2**: Write sandbox-safe script:
# Type: Document Event | Event: Before Save | DocType: Sales Order
errors = []
if not doc.customer:
errors.append("Customer is required")
if doc.delivery_date and doc.delivery_date < frappe.utils.today():
errors.append("Delivery date cannot be in the past")
for item in doc.items:
if item.qty <= 0:
errors.append(f"Row {item.idx}: Quantity must be positive")
if errors:
frappe.throw("<br>".join(errors), title="Validation Error")**Rules**:
**Goal**: Auto-calculate totals and set derived fields.
# Type: Document Event | Event: Before Save | DocType: Purchase Order
doc.total_qty = sum(item.qty or 0 for item in doc.items)
doc.total_amount = sum((item.qty or 0) * (item.rate or 0) for item in doc.items)
if doc.total_amount > 50000:
doc.requires_approval = 1
doc.approval_status = "Pending"
if doc.supplier and not doc.supplier_name:
doc.supplier_name = frappe.db.get_value("Supplier", doc.supplier, "supplier_name")**Rule**: ALWAYS modify `doc` fields directly in Before Save — they are automatically persisted.
**Goal**: Create a ToDo when a new Lead is inserted.
# Type: Document Event | Event: After Insert | DocType: Lead
frappe.get_doc({
"doctype": "ToDo",
"allocated_to": doc.lead_owner or doc.owner,
"reference_type": "Lead",
"reference_name": doc.name,
"description": f"Follow up with new lead: {doc.lead_name}",
"date": frappe.utils.add_days(frappe.utils.today(), 1),
"priority": "High" if doc.status == "Hot" else "Medium"
}).insert(ignore_permissions=True)**Rules**:
**Goal**: Create authenticated REST API returning customer data.
# Type: API | Method: get_customer_dashboard | Allow Guest: No
# Endpoint: /api/method/get_customer_dashboard
customer = frappe.form_dict.get("customer")
if not customer:
frappe.throw("Parameter 'customer' is required")
# ALWAYS check permissions
if not frappe.has_permission("Customer", "read", customer):
frappe.throw("Access denied", frappe.PermissionError)
orders = frappe.db.count("Sales Order", {"customer": customer, "docstatus": 1})
revenue = frappe.db.get_value("Sales Invoice",
filters={"customer": customer, "docstatus": 1},
fieldname="sum(grand_total)") or 0
frappe.response["message"] = {
"customer": customer,
"total_orders": orders,
"total_revenue": revenue
}**Rules**:
60 deterministic Claude AI skills for Frappe Framework & ERPNext v14-v16 development and operations
Repo: Impertio-Studio/Frappe_Claude_Skill_Package
Use when designing multi-app Frappe architectures, deciding whether to split functionality into separate apps, or implementing cross-app communication…
Use when debugging Frappe errors, using bench console for live inspection, analyzing tracebacks, or reading Frappe log files. Prevents wasted debugging time…
Use when receiving vague or unclear ERPNext/Frappe development requests that need interpretation. Transforms requirements like 'make invoice auto-calculate' or…
Use when migrating a Frappe app between major versions, detecting breaking API changes, or resolving post-migration errors. Prevents failed migrations from…
Use when reviewing or validating Frappe/ERPNext code against best practices and common pitfalls. Checks generated code before deployment, validates against all…
Use when building ERPNext/Frappe API integrations (v14/v15/v16) including REST API, RPC API, authentication, webhooks, and rate limiting. Covers external API…