Skip to content
AI & Agents
Skill

/frappe-syntax-hooks-events

Use when implementing document lifecycle hooks via doc_events in hooks.py, understanding event execution order, or extending/overriding document behavior from another app. Prevents silent hook failures from wrong event names, incorrect execution order assumptions, and broken

From plugin
frappe-claude-skill-package
17961 skills
Install
$ npx -y skills add Impertio-Studio/Frappe_Claude_Skill_Package --skill frappe-syntax-hooks-events --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/frappe-syntax-hooks-events

Context preview

The summary Claude sees to decide when to auto-load this skill.

Use when implementing document lifecycle hooks via doc_events in hooks.py, understanding event execution order, or extending/overriding document behavior from another app. Prevents silent hook failures from wrong event names, incorrect execution order assumptions, and broken

SKILL.md

frappe-syntax-hooks-events.SKILL.md
name: frappe-syntax-hooks-events
description: >
  Use when implementing document lifecycle hooks via doc_events in hooks.py, understanding event execution order, or extending/overriding document behavior from another app.
  Prevents silent hook failures from wrong event names, incorrect execution order assumptions, and broken override chains.
  Covers doc_events hook syntax, all document events (before_insert, validate, on_submit, etc.), event execution order, extend vs override behavior, cross-app doc_events.
  Keywords: doc_events, hooks.py, before_insert, validate, on_submit, on_cancel, lifecycle, document events, override, extend, event order, which event fires when, before_save vs validate, document event list..
license: MIT
compatibility: "Claude Code, Claude.ai Projects, Claude API. Frappe v14-v16."
metadata:
  author: OpenAEC-Foundation
  version: "2.0"

Document Lifecycle Hooks (doc_events)

Quick Reference: Event Execution Order

Insert (new document)

| Order | Event | Purpose | Can Raise? | |-------|---------------------|--------------------------------------|------------| | 1 | `before_insert` | Set defaults before naming | YES | | 2 | `before_naming` | Modify naming logic | YES | | 3 | `autoname` | Set the `name` property | YES | | 4 | `before_validate` | Auto-set missing values | YES | | 5 | `validate` | Validation logic — throw to abort | YES | | 6 | `before_save` | Final mutations before DB write | YES | | 7 | `db_insert` | *Internal* — writes row to DB | — | | 8 | `after_insert` | Post-insert logic (runs once ever) | YES | | 9 | `on_update` | Post-save logic (runs on every save) | YES | | 10 | `on_change` | Fires if any field value changed | YES |

Save (existing document)

| Order | Event | Purpose | |-------|-------------------|-----------------------------------| | 1 | `before_validate` | Auto-set missing values | | 2 | `validate` | Validation logic — throw to abort | | 3 | `before_save` | Final mutations before DB write | | 4 | `db_update` | *Internal* — updates row in DB | | 5 | `on_update` | Post-save logic | | 6 | `on_change` | Fires if any field value changed |

Submit

| Order | Event | Purpose | |-------|-------------------|------------------------------------| | 1 | `before_validate` | Auto-set missing values | | 2 | `validate` | Validation logic | | 3 | `before_save` | Final mutations before DB write | | 4 | `before_submit` | Pre-submit logic — throw to abort | | 5 | `db_update` | *Internal* — updates row in DB | | 6 | `on_submit` | Post-submit logic (GL entries etc) | | 7 | `on_update` | Post-save logic | | 8 | `on_change` | Fires if any field value changed |

Cancel

| Order | Event | Purpose | |-------|-------------------|-------------------------------------| | 1 | `before_cancel` | Pre-cancel validation | | 2 | `db_update` | *Internal* — updates row in DB | | 3 | `on_cancel` | Post-cancel logic (reverse GL etc) | | 4 | `on_change` | Fires if any field value changed |

Delete

| Order | Event | Purpose | |-------|----------------|--------------------------------| | 1 | `on_trash` | Pre-delete cleanup | | 2 | `after_delete` | Post-delete logic |

Other Operations

| Operation | Events (in order) | |------------------------|----------------------------------------------------------| | Rename | `before_rename` → `after_rename` | | Amend | `before_insert` chain runs on the new amended doc | | Update After Submit | `before_update_after_submit` → `db_update` → `on_update_after_submit` → `on_change` |

---

doc_events in hooks.py: Syntax

Basic Structure

# hooks.py
doc_events = {
    "Sales Invoice": {
        "on_submit": "myapp.events.sales_invoice.on_submit",
        "on_cancel": "myapp.events.sales_invoice.on_cancel",
    },
    "Purchase Order": {
        "validate": "myapp.events.purchase_order.validate",
    }
}

Wildcard: Apply to ALL DocTypes

doc_events = {
    "*": {
        "after_insert": "myapp.events.global_handler.after_insert_all",
        "on_update": "myapp.events.global_handler.track_changes",
    }
}

ALWAYS use `"*"` (string with asterisk) as the key. This fires the handler for every DocType.

Multiple Handlers per Event

doc_events = {
    "Sales Invoice": {
        "on_submit": [
            "myapp.events.accounting.create_gl_entries",
            "myapp.events.notifications.send_invoice_email",
        ]
    }
}

Handler Function Signature

# myapp/events/sales_invoice.py
def on_submit(doc, method=None):
    """
    doc    — the Document instance (e.g., Sales Invoice)
    method — string name of the event (e.g., "on_submit"), or None
    """
    if doc.grand_total > 10000:
        frappe.sendmail(...)

ALWAYS accept `method` as the second parameter (with default `None`). Frappe passes it automatically.

---

Decision Tree: Which Event to Use

"I need to validate data before saving"

→ Use `validate`. ALWAYS raise `frappe.throw()` here to block invalid saves.

"I need to set default values automatically"

→ Use `before_validate`. This runs before `validate`, so your

Read more
Ships withfrappe-claude-skill-package

60 deterministic Claude AI skills for Frappe Framework & ERPNext v14-v16 development and operations

Get the whole plugin
Stats
178
Stars
53
Forks
Maintained
Maintenance
Python
Language
2mo ago
Last commit
8mo ago
Created
14d ago
Added

Repo: Impertio-Studio/Frappe_Claude_Skill_Package