Token导航 LogoToken导航

Agent Skill · 开发

erpnext-syntax-hooks(erpnext 语法挂钩)

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

erpnext-syntax-hooks 是开发类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为需要联网;许可证信息还不明确,第三方扫描已通过,按安装量在开发类的 21,746 个 Skill 里排第 13,096。

总安装 1,011周安装 43GitHub Stars 87下载 354核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

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

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

命令行安装

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

skills.shnpx skills
npx skills add https://github.com/openaec-foundation/erpnext_anthropic_claude_development_skill_package --skill erpnext-syntax-hooks

这个 Skill 是做什么的

开发类 Skill 面向写代码、改代码和排查问题,一般会读写仓库文件,部分还会执行构建或测试命令。

定义 hooks.py 中各类钩子的配置语法,包括文档事件与定时任务注册格式。适用于 Codex、Claude、Cursor、Gemini CLI 中扩展系统行为而不修改核心代码。提供 doc_events 与 scheduler_events 的完整键名与回调函数签名示例。

使用前应验证钩子函数路径是否存在,避免因导入失败导致启动错误。erpnext-syntax-hooks 属于开发类 Skill,可作为该场景下的辅助能力补充。

来源仓库内路径:skills/erpnext-syntax-hooks

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/openaec-foundation/erpnext_anthropic_claude_de…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要需要联网,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

erpnext-syntax-hooks 怎么安装?

在终端执行 npx skills add https://github.com/openaec-foundation/erpnext_anthropic_claude_development_…。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

erpnext-syntax-hooks 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

erpnext-syntax-hooks 需要什么权限?

权限级别是需要联网。该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

erpnext-syntax-hooks 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

erpnext-syntax-hooks 用的人多吗?

公开数据是累计安装 1,011 次,近一周安装 43 次,下载 354 次,GitHub 87 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

erpnext-syntax-hooks 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 第三方扫描已通过,常见的高风险行为没有命中。

先想清楚的地方

  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理开发类任务、又不想每次都手写提示词的人。

不太适合

  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

开发类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
skill-vetter

技能审查员 · OpenClaw

8,779,018986操作浏览器MIT-0通过
ontology

本体论 · OpenClaw

6,636,960576只读MIT-0通过
entra-app-registration

内部应用程序注册 · Codex、Claude

6,631,872764接触敏感数据未明确通过
entra-app-registration

内部应用程序注册 · Codex、Claude

3,757,680201接触敏感数据未明确通过
nano-banana-pro

纳米香蕉专业版 · OpenClaw

3,526,898364接触敏感数据MIT-0有提醒
erpnext-syntax-hooks

erpnext 语法挂钩 · 本页

1,01187需要联网未明确通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

ERPNext Syntax: Hooks (hooks.py)

Hooks in hooks.py enable custom apps to extend Frappe/ERPNext functionality.

Quick Reference

doc_events - Document Lifecycle

# In hooks.py
doc_events = {
    "*": {
        "after_insert": "myapp.events.log_all_inserts"
    },
    "Sales Invoice": {
        "validate": "myapp.events.si_validate",
        "on_submit": "myapp.events.si_on_submit"
    }
}
# In myapp/events.py
import frappe

def si_validate(doc, method=None):
    """doc = document object, method = event name"""
    if doc.grand_total < 0:
        frappe.throw("Total cannot be negative")

scheduler_events - Periodic Tasks

# In hooks.py
scheduler_events = {
    "daily": ["myapp.tasks.daily_cleanup"],
    "hourly_long": ["myapp.tasks.heavy_sync"],
    "cron": {
        "0 9 * * 1-5": ["myapp.tasks.weekday_morning"]
    }
}
# In myapp/tasks.py
def daily_cleanup():
    """No arguments - called automatically"""
    frappe.db.delete("Log", {"creation": ["<", one_month_ago()]})

extend_bootinfo - Client Data Injection

# In hooks.py
extend_bootinfo = "myapp.boot.extend_boot"
# In myapp/boot.py
def extend_boot(bootinfo):
    """bootinfo = dict that goes to frappe.boot"""
    bootinfo.my_setting = frappe.get_single("My Settings").value
// Client-side
console.log(frappe.boot.my_setting);

Most Used doc_events

EventWhenUse Case
validateBefore every saveValidation, calculations
on_updateAfter every saveNotifications, sync
after_insertAfter new docCreation-only actions
on_submitAfter submitLedger entries
on_cancelAfter cancelReverse entries
on_trashBefore deleteCleanup

Complete list: See doc-events.md


Scheduler Event Types

EventFrequencyQueue/Timeout
hourlyEvery hourdefault / 5 min
dailyEvery daydefault / 5 min
weeklyEvery weekdefault / 5 min
monthlyEvery monthdefault / 5 min
hourly_longEvery hourlong / 25 min
daily_longEvery daylong / 25 min
cronCustom timingdefault / 5 min

Cron syntax and examples: See scheduler-events.md


Critical Rules

1. bench migrate after scheduler changes

# REQUIRED - otherwise changes won't be picked up
bench --site sitename migrate

2. No commits in doc_events

# ❌ WRONG
def on_update(doc, method=None):
    frappe.db.commit()  # Breaks transaction

# ✅ CORRECT - Frappe commits automatically
def on_update(doc, method=None):
    update_related_docs(doc)

3. Changes after on_update via db_set

# ❌ WRONG - change is lost
def on_update(doc, method=None):
    doc.status = "Processed"

# ✅ CORRECT
def on_update(doc, method=None):
    frappe.db.set_value(doc.doctype, doc.name, "status", "Processed")

4. Heavy tasks to _long queue

# ❌ WRONG - timeout after 5 min
scheduler_events = {
    "daily": ["myapp.tasks.process_all_records"]  # May take 20 min
}

# ✅ CORRECT - 25 min timeout
scheduler_events = {
    "daily_long": ["myapp.tasks.process_all_records"]
}

5. Tasks receive no arguments

# ❌ WRONG
def my_task(some_arg):
    pass

# ✅ CORRECT
def my_task():
    # Fetch data inside the function
    pass

Cron Syntax Cheatsheet

* * * * *
│ │ │ │ │
│ │ │ │ └── Day of week (0-6, Sun=0)
│ │ │ └──── Month (1-12)
│ │ └────── Day of month (1-31)
│ └──────── Hour (0-23)
└────────── Minute (0-59)
PatternMeaning
*/5 * * * *Every 5 minutes
0 9 * * *Daily at 09:00
0 9 * * 1-5Weekdays at 09:00
0 0 1 * *First day of month
0 17 * * 5Friday at 17:00

doc_events vs Controller Hooks

Aspectdoc_events (hooks.py)Controller Methods
Locationhooks.pydoctype/xxx/xxx.py
ScopeHook OTHER doctypesOnly OWN doctype
Multiple handlers✅ Yes (list)❌ No
PriorityAfter controllerFirst
Wildcard (*)✅ Yes❌ No

Use doc_events when:

  • Hooking other apps' DocTypes from your custom app
  • Reacting to ALL DocTypes (wildcard)
  • Registering multiple handlers

Use controller methods when:

  • Working on your own DocType
  • You want full lifecycle control

Reference Files

FileContents
doc-events.mdAll document events, signatures, execution order
scheduler-events.mdScheduler types, cron syntax, timeouts
bootinfo.mdextend_bootinfo, session hooks
overrides.mdOverride and extend patterns
permissions.mdPermission hooks
fixtures.mdFixtures configuration
examples.mdComplete hooks.py examples
anti-patterns.mdMistakes and corrections

Configuration Hooks

Override DocType Controller

# In hooks.py
override_doctype_class = {
    "Sales Invoice": "myapp.overrides.CustomSalesInvoice"
}
# In myapp/overrides.py
from erpnext.accounts.doctype.sales_invoice.sales_invoice import SalesInvoice

class CustomSalesInvoice(SalesInvoice):
    def validate(self):
        super().validate()  # CRITICAL: always call super()!
        self.custom_validation()

Warning: Last installed app wins when multiple apps override the same DocType.

Override Whitelisted Methods

# In hooks.py
override_whitelisted_methods = {
    "frappe.client.get_count": "myapp.overrides.custom_get_count"
}
# Method signature MUST be identical to original!
def custom_get_count(doctype, filters=None, debug=False, cache=False):
    # Custom implementation
    return frappe.db.count(doctype, filters)

Permission Hooks

# In hooks.py
permission_query_conditions = {
    "Sales Invoice": "myapp.permissions.si_query_conditions"
}
has_permission = {
    "Sales Invoice": "myapp.permissions.si_has_permission"
}
# In myapp/permissions.py
def si_query_conditions(user):
    """Returns SQL WHERE fragment for list filtering"""
    if not user:
        user = frappe.session.user

    if "Sales Manager" in frappe.get_roles(user):
        return ""  # No restrictions

    return f"`tabSales Invoice`.owner = {frappe.db.escape(user)}"

def si_has_permission(doc, user=None, permission_type=None):
    """Document-level permission check"""
    if permission_type == "write" and doc.status == "Closed":
        return False
    return None  # Fallback to default

Note: permission_query_conditions only works with get_list, NOT with get_all!

Fixtures

# In hooks.py
fixtures = [
    {"dt": "Custom Field", "filters": [["module", "=", "My App"]]},
    {"dt": "Property Setter", "filters": [["module", "=", "My App"]]},
    {"dt": "Role", "filters": [["name", "like", "MyApp%"]]}
]
# Export fixtures to JSON
bench --site sitename export-fixtures

Asset Includes

# In hooks.py

# Desk (backend) assets
app_include_js = "/assets/myapp/js/myapp.min.js"
app_include_css = "/assets/myapp/css/myapp.min.css"

# Website/Portal assets
web_include_js = "/assets/myapp/js/web.min.js"
web_include_css = "/assets/myapp/css/web.min.css"

# Form script extensions
doctype_js = {
    "Sales Invoice": "public/js/sales_invoice.js"
}

Install/Migrate Hooks

# In hooks.py
after_install = "myapp.setup.after_install"
after_migrate = "myapp.setup.after_migrate"
# In myapp/setup.py
def after_install():
    create_default_roles()

def after_migrate():
    clear_custom_cache()

Complete Decision Tree

What do you want to achieve?
│
├─► REACT to document events from OTHER apps?
│   └─► doc_events
│
├─► Run PERIODIC tasks?
│   └─► scheduler_events
│       ├─► < 5 min → hourly/daily/weekly/monthly
│       ├─► > 5 min → hourly_long/daily_long/etc.
│       └─► Specific time → cron
│
├─► Send DATA to CLIENT at page load?
│   └─► extend_bootinfo
│
├─► Modify CONTROLLER of existing DocType?
│   ├─► Frappe v16+ → extend_doctype_class (recommended)
│   └─► Frappe v14/v15 → override_doctype_class
│
├─► Modify API ENDPOINT?
│   └─► override_whitelisted_methods
│
├─► Customize PERMISSIONS?
│   ├─► List filtering → permission_query_conditions
│   └─► Document-level → has_permission
│
├─► EXPORT/IMPORT configuration?
│   └─► fixtures
│
├─► ADD JS/CSS to desk or portal?
│   ├─► Desk → app_include_js/css
│   ├─► Portal → web_include_js/css
│   └─► Form specific → doctype_js
│
└─► SETUP on install/migrate?
    └─► after_install, after_migrate

Version Differences

Featurev14v15v16
doc_events✅✅✅
scheduler_events✅✅✅
extend_bootinfo✅✅✅
override_doctype_class✅✅✅
extend_doctype_class❌❌✅
permission_query_conditions✅✅✅
has_permission✅✅✅
fixtures✅✅✅

Anti-Patterns Summary

❌ Wrong✅ Correct
frappe.db.commit() in handlerFrappe commits automatically
doc.field = x in on_updatefrappe.db.set_value()
Heavy task in dailyUse daily_long
Change scheduler without migrateAlways bench migrate
Sensitive data in bootinfoOnly public config
Override without super()Always super().method() first
get_all with permission_queryUse get_list
Fixtures without filtersFilter by module/app

Full anti-patterns: See anti-patterns.md

平台分布

Codex

36.37%
按下载量换算129

Claude

32.74%
按下载量换算116

Cursor

18.47%
按下载量换算65

Gemini CLI

9.31%
按下载量换算33

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills