Token导航 LogoToken导航TokenDH.com
开发敏感数据github未标认证来源可访问许可证需确认审计异常

frappe-impl-whitelistedfrappe impl 已列入白名单

Agent Skill

frappe-impl-whitelisted 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

629

周安装

27

GitHub Stars

87

下载量

220
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:frappe-impl-whitelisted(frappe impl 已列入白名单)
来源仓库:https://github.com/openaec-foundation/erpnext_anthropic_claude_development_skill_package
仓库路径:skills/frappe-impl-whitelisted
安装命令:
npx skills add https://github.com/openaec-foundation/erpnext_anthropic_claude_development_skill_package --skill frappe-impl-whitelisted
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/openaec-foundation/erpnext_anthropic_claude_development_skill_package --skill frappe-impl-whitelisted

简介

frappe-impl-whitelisted 用于处理 GitHub 仓库、Issue、Pull Request 等协作信息,适合整理代码变更与项目状态。

  • 适用于围绕仓库状态、代码协作事项进行信息梳理的场景。
  • 通过 npx skills add 命令从指定 GitHub 仓库安装并使用。
  • 安装前需确认权限范围和维护状态,注意可能触发联网或命令执行操作。
  • 适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。

SKILL.md

Frappe Whitelisted Methods Implementation Workflow

Step-by-step workflows for building API endpoints. For decorator syntax, see frappe-syntax-whitelisted.

Version: v14/v15/v16 (version-specific features noted)


Master Decision: What Type of Endpoint?

WHAT ARE YOU BUILDING?
│
├─► Public API (no login required)?
│   └─► allow_guest=True + STRICT input validation + rate limiting
│
├─► Authenticated API for logged-in users?
│   └─► Default @frappe.whitelist() + document permission checks
│
├─► Admin-only API?
│   └─► frappe.only_for("System Manager")
│
├─► Document-specific method (called from form)?
│   └─► Controller method + frm.call() from JS
│
├─► Standalone utility API?
│   └─► Separate api.py + frappe.call() from JS
│
├─► External webhook receiver?
│   └─► allow_guest=True + signature verification
│
└─► Background job trigger?
    └─► Authenticated API that calls frappe.enqueue()

Workflow 1: Design the Endpoint

Step 1: Choose Location

WHERE SHOULD THE CODE LIVE?
│
├─► Related to a DocType, called from its form?
│   └─► doctype/xxx/xxx.py (controller method)
│       Client: frm.call('method_name', args)
│
├─► Related to a DocType, standalone?
│   └─► doctype/xxx/xxx_api.py or myapp/api/module.py
│       Client: frappe.call('myapp.api.module.method')
│
├─► General app utility?
│   └─► myapp/api.py (small app) or myapp/api/module.py (large app)
│
└─► External integration?
    └─► myapp/integrations/service_name.py

Step 2: Choose Permission Model

WHO CAN CALL THIS API?
│
├─► Anyone (public) → allow_guest=True
│   ⚠️ MUST validate ALL input, sanitize for XSS, rate limit
│
├─► Any logged-in user → Default (no allow_guest)
│   Still check document permissions per record!
│
├─► Specific role(s) → frappe.only_for("Role")
│
└─► Document-level → frappe.has_permission(doctype, ptype, doc)

Step 3: Choose HTTP Method

WHAT DOES THE API DO?
│
├─► Read-only → methods=["GET"]
├─► Creates/modifies data → methods=["POST"]
└─► Both or default → omit methods parameter (all allowed)

Workflow 2: Implement an Authenticated API

Step-by-Step

Step 1: Create the function

# myapp/api.py
import frappe
from frappe import _

@frappe.whitelist()
def get_customer_balance(customer):
    """Get outstanding balance for a customer."""
    # 1. Permission check
    if not frappe.has_permission("Customer", "read", customer):
        frappe.throw(_("Not permitted"), frappe.PermissionError)

    # 2. Validate input
    if not customer or not frappe.db.exists("Customer", customer):
        frappe.throw(_("Customer not found"), frappe.DoesNotExistError)

    # 3. Fetch and return
    balance = frappe.db.sql("""
        SELECT COALESCE(SUM(outstanding_amount), 0)
        FROM `tabSales Invoice`
        WHERE customer = %s AND docstatus = 1
    """, customer)[0][0]

    return {"customer": customer, "balance": balance}

Step 2: Call from Client Script

frappe.call({
    method: 'myapp.api.get_customer_balance',
    args: { customer: 'CUST-00001' },
    callback(r) {
        if (r.message) console.log(r.message.balance);
    }
});

Step 3: Test with curl

# Authenticate first
curl -X POST https://site.com/api/method/login \
  -d 'usr=admin&pwd=password'

# Call the API
curl -X POST https://site.com/api/method/myapp.api.get_customer_balance \
  -H "Content-Type: application/json" \
  -d '{"customer": "CUST-00001"}' \
  --cookie cookies.txt

# Or use token auth
curl -X POST https://site.com/api/method/myapp.api.get_customer_balance \
  -H "Authorization: token api_key:api_secret" \
  -H "Content-Type: application/json" \
  -d '{"customer": "CUST-00001"}'

Workflow 3: Implement a Public (Guest) API

Step-by-Step

Step 1: Create with strict validation

@frappe.whitelist(allow_guest=True, methods=["POST"])
def submit_inquiry(name, email, phone=None, message=None):
    """Public contact form — strict validation required."""
    # 1. Validate required fields
    if not all([name, email]):
        frappe.throw(_("Name and email are required"))

    # 2. Validate email format
    if not frappe.utils.validate_email_address(email):
        frappe.throw(_("Invalid email address"))

    # 3. Sanitize ALL input
    name = frappe.utils.strip_html(name)[:100]
    email = email.strip().lower()[:200]
    phone = frappe.utils.strip_html(phone)[:20] if phone else None
    message = frappe.utils.strip_html(message)[:2000] if message else None

    # 4. Create record with ignore_permissions
    lead = frappe.get_doc({
        "doctype": "Lead",
        "lead_name": name, "email_id": email,
        "phone": phone, "notes": message, "source": "Website"
    })
    lead.insert(ignore_permissions=True)

    return {"success": True, "message": _("Thank you")}

Step 2: Add rate limiting (v15+)

from frappe.rate_limiter import rate_limit

@frappe.whitelist(allow_guest=True, methods=["POST"])
@rate_limit(limit=5, seconds=60)  # 5 calls per minute
def submit_inquiry(name, email, phone=None, message=None):
    ...

Critical Rules for Guest APIs

  • ALWAYS validate and sanitize every input parameter
  • ALWAYS use methods=["POST"] for data-writing endpoints
  • ALWAYS add rate limiting (v15+ decorator or manual cache-based throttle on v14)
  • NEVER expose internal error details — log with frappe.log_error(), show generic message
  • NEVER return sensitive data (internal IDs, file paths, stack traces)
  • NEVER pass raw user input to frappe.get_doc() — use explicit field mapping

Workflow 4: Implement a Controller Method

Step-by-Step

Step 1: Add method to DocType controller

# myapp/doctype/sales_order/sales_order.py
class SalesOrder(Document):
    @frappe.whitelist()
    def calculate_shipping(self, carrier):
        """Called from form via frm.call()."""
        if not self.shipping_address:
            frappe.throw(_("Shipping address required"))
        rate = get_shipping_rate(self.shipping_address, carrier)
        return {"carrier": carrier, "rate": rate}

Step 2: Call from form JS

frm.call('calculate_shipping', {
    carrier: 'FedEx'
}).then(r => {
    frm.set_value('shipping_amount', r.message.rate);
});

Key difference: Frappe automatically checks document permissions for controller methods called via frm.call(). No manual permission check needed for the document itself.


Workflow 5: Implement Error Handling

Standard Pattern

@frappe.whitelist()
def process_payment(invoice, amount):
    try:
        # Validate
        if not invoice:
            frappe.throw(_("Invoice required"), frappe.ValidationError)
        if not frappe.has_permission("Sales Invoice", "write", invoice):
            frappe.throw(_("Not permitted"), frappe.PermissionError)

        # Process
        result = do_payment(invoice, float(amount))
        return {"success": True, "data": result}

    except (frappe.ValidationError, frappe.PermissionError):
        raise  # Let Frappe handle (417 / 403)
    except frappe.DoesNotExistError:
        frappe.throw(_("Not found"), frappe.DoesNotExistError)  # 404
    except Exception:
        frappe.log_error(frappe.get_traceback(), "Payment Error")
        frappe.local.response["http_status_code"] = 500
        return {"success": False, "error": _("Internal error")}

HTTP Status Code Reference

CodeFrappe ExceptionWhen
200Success
403PermissionErrorAccess denied
404DoesNotExistErrorNot found
409DuplicateEntryErrorDuplicate
417ValidationErrorValidation failed
429Rate limit exceeded (v15+)
500ExceptionServer error

Workflow 6: File Upload Endpoint

@frappe.whitelist()
def upload_attachment(doctype, docname):
    """Handle file upload attached to a document."""
    if not frappe.has_permission(doctype, "write", docname):
        frappe.throw(_("Not permitted"), frappe.PermissionError)

    file = frappe.request.files.get('file')
    if not file:
        frappe.throw(_("No file provided"))

    file_doc = frappe.get_doc({
        "doctype": "File",
        "file_name": file.filename,
        "attached_to_doctype": doctype,
        "attached_to_name": docname,
        "content": file.read(),
        "is_private": 1
    })
    file_doc.insert(ignore_permissions=True)
    return {"file_url": file_doc.file_url}

Workflow 7: Background Job Endpoint

@frappe.whitelist()
def start_heavy_export(doctype, filters=None):
    """Trigger a background job — returns immediately."""
    frappe.only_for("System Manager")

    frappe.enqueue(
        "myapp.tasks.export_data",
        queue="long",
        timeout=1500,
        doctype=doctype,
        filters=filters,
        user=frappe.session.user
    )
    return {"status": "queued", "message": _("Export started")}

Client Integration Patterns

frappe.call() with Options

frappe.call({
    method: 'myapp.api.my_method',
    args: { param: 'value' },
    freeze: true,
    freeze_message: __('Processing...'),
    callback(r) { console.log(r.message); },
    error(r) { frappe.msgprint(__('Error')); }
});

Async/Await Pattern

const r = await frappe.call({
    method: 'myapp.api.get_data',
    args: { id: 123 }
});
console.log(r.message);

REST API from External System

# Token auth (recommended for integrations)
curl -H "Authorization: token api_key:api_secret" \
  https://site.com/api/method/myapp.api.method

# Bearer auth (OAuth)
curl -H "Authorization: Bearer access_token" \
  https://site.com/api/method/myapp.api.method

Security Rules (ALWAYS/NEVER)

  1. ALWAYS check permissions before accessing any document
  2. ALWAYS use parameterized queries — NEVER use f-strings in SQL
  3. ALWAYS validate and sanitize input for guest APIs
  4. ALWAYS check role with frappe.only_for() before using ignore_permissions=True
  5. NEVER expose internal errors — log details, return generic message
  6. NEVER use methods=["GET"] for endpoints that modify data
  7. NEVER trust data dicts from guest APIs — use explicit parameter names
  8. ALWAYS include X-Frappe-CSRF-Token header in fetch() calls from browser

Migration: Server Script API to Whitelisted Method

StepAction
1Copy Server Script logic to myapp/api/module.py
2Add @frappe.whitelist() decorator with same permission model
3Update all frappe.call() references to new dotted path
4Disable or delete the Server Script
5Run bench --site sitename migrate

Version Differences

Featurev14v15v16
@frappe.whitelist()YesYesYes
allow_guestYesYesYes
methods parameterYesYesYes
Type annotation validationNoYesYes
@rate_limit decoratorNoYesYes
API v2 endpointsNoYesYes

v15+ Type Validation

@frappe.whitelist()
def typed_api(customer: str, limit: int = 10) -> dict:
    """v15+ validates types from annotations automatically."""
    return {"customer": customer, "limit": limit}

Reference Files

FileContents
decision-tree.mdComplete API type and permission selection guide
workflows.mdStep-by-step implementation patterns (10+ workflows)
examples.mdProduction-ready code examples

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

37.39%
按下载量换算82

Claude

32.37%
按下载量换算71

Cursor

17.74%
按下载量换算39

Gemini CLI

9.29%
按下载量换算20

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

未通过

权限和风险

敏感数据

该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在 warning/failed 结果,不能写成本站确认安全。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills