frappe-agent-architect
Use when designing multi-app Frappe architectures, deciding whether to split functionality into separate apps, or implementing…
Use when writing Jinja templates for ERPNext/Frappe Print Formats, Email Templates, and Portal Pages. Covers template syntax, context variables, filters, macros, and v16 Chrome PDF rendering. Prevents common mistakes with doc context and child table iteration. Keywords: Jinja,
Claude Code
$ npx -y skills add Impertio-Studio/Frappe_Claude_Skill_Package --skill frappe-syntax-jinja --agent claude-code
Codex
$ npx skills add Impertio-Studio/Frappe_Claude_Skill_Package --skill frappe-syntax-jinja -a codex -y
Cursor
$ npx skills add Impertio-Studio/Frappe_Claude_Skill_Package --skill frappe-syntax-jinja -a cursor -y
Gemini CLI
$ npx skills add Impertio-Studio/Frappe_Claude_Skill_Package --skill frappe-syntax-jinja -a gemini-cli -y
GitHub Copilot
$ npx skills add Impertio-Studio/Frappe_Claude_Skill_Package --skill frappe-syntax-jinja -a github-copilot -y
OpenCode
$ npx skills add Impertio-Studio/Frappe_Claude_Skill_Package --skill frappe-syntax-jinja -a opencode -y
Windsurf
$ npx skills add Impertio-Studio/Frappe_Claude_Skill_Package --skill frappe-syntax-jinja -a windsurf -y
name: frappe-syntax-jinja description: > Use when writing Jinja templates for ERPNext/Frappe Print Formats, Email Templates, and Portal Pages. Covers template syntax, context variables, filters, macros, and v16 Chrome PDF rendering. Prevents common mistakes with doc context and child table iteration. Keywords: Jinja, print format, email template, portal page, template syntax, PDF, v14-v16, template syntax, Jinja example, print format code, how to show child table in print. license: MIT compatibility: "Claude Code, Claude.ai Projects, Claude API. Frappe v14-v16." metadata: author: OpenAEC-Foundation version: "2.0"
> Deterministic Jinja reference for Print Formats, Email Templates, Notification Templates, and Portal Pages in Frappe v14/v15/v16.
---
USE when:
DO NOT USE for:
---
Need a printable document?
├─ YES → Is it for a Query/Script Report?
│ ├─ YES → Use JS Template ({%= %}), NOT Jinja
│ └─ NO → Use Jinja Print Format
└─ NO → Is it for email?
├─ YES → Is it triggered by workflow/notification?
│ ├─ YES → Notification Template (Jinja)
│ └─ NO → Email Template (Jinja)
└─ NO → Is it a web page?
├─ YES → Portal Page (www/*.html + .py controller)
└─ NO → frappe.render_template() for ad-hoc rendering---
| Syntax | Purpose | Example | |--------|---------|---------| | `{{ }}` | Output expression | `{{ doc.name }}` | | `{% %}` | Control statement | `{% if doc.status == "Paid" %}` | | `{# #}` | Comment | `{# This is a comment #}` | | `{{ _("text") }}` | Translation | `{{ _("Invoice") }}` | | `{{ val \| filter }}` | Filter | `{{ name \| default("N/A") }}` |
| Aspect | Jinja (Print Formats) | JS Template (Report Print Formats) | |--------|----------------------|-------------------------------------| | Output | `{{ expression }}` | `{%= expression %}` | | Code block | `{% statement %}` | `{% js_code %}` | | Language | Python | JavaScript | | Context | `doc`, `frappe` | `data`, `filters` |
**NEVER use Jinja syntax in Report Print Formats. NEVER use `{%= %}` in standard Print Formats.**
---
| Object | Description | |--------|-------------| | `doc` | The document being printed (full Document object) | | `frappe` | Frappe module (whitelisted methods only) | | `frappe.utils` | Utility functions | | `_()` | Translation function | | `doc.items`, `doc.taxes` | Child table accessors (by fieldname) |
| Object | Description | |--------|-------------| | `doc` | The linked document (when triggered from a DocType) | | `frappe` | Frappe module (limited) | | `_()` | Translation function |
| Object | Description | |--------|-------------| | `doc` | The document that triggered the notification | | `frappe` | Frappe module | | `_()` | Translation function |
| Object | Description | |--------|-------------| | `frappe` | Frappe module | | `frappe.session.user` | Current authenticated user | | `frappe.form_dict` | Query parameters from URL | | `frappe.lang` | Current language code | | Custom context | Set via `get_context(context)` in `.py` controller |
> **Full details**: `references/context-objects.md`
---
{# ALWAYS use get_formatted() for fields in Print Formats #}
{{ doc.get_formatted("posting_date") }}
{{ doc.get_formatted("grand_total") }}
{# Child table rows — ALWAYS pass parent doc for currency context #}
{% for row in doc.items %}
{{ row.get_formatted("rate", doc) }}
{{ row.get_formatted("amount", doc) }}
{% endfor %}
{# General formatting with explicit fieldtype #}
{{ frappe.format(value, {'fieldtype': 'Currency'}) }}
{{ frappe.format_date(doc.posting_date) }}{# Full document — use only when multiple fields needed #}
{% set customer = frappe.get_doc("Customer", doc.customer) %}
{# Single field — ALWAYS prefer over get_doc for one field #}
{% set abbr = frappe.db.get_value("Company", doc.company, "abbr") %}
{# List of records (no permission check) #}
{% set tasks = frappe.get_all("Task",
filters={"status": "Open"},
fields=["title", "due_date"],
order_by="due_date asc",
page_length=10) %}
{# List with permission check (portal pages) #}
{% set orders = frappe.get_list("Sales Order",
filters={"customer": doc.customer},
fields=["name", "grand_total"]) %}<h1>{{ _("Invoice") }}</h1>
<p>{{ _("Total: {0}").format(doc.get_formatted("grand_total")) }}</p>{{ frappe.get_url() }}
{{ frappe.get_fullname() }}
{{ frappe.get_fullname(doc.owner) }}
{{ frappe.db.get_single_value("System Settings", "time_zone") }}
{% if frappe.session.user != "Guest" %}...{% endif %}> **Full method reference**: `references/methods-reference.md`
---
{% if doc.status == "Paid" %}
<span class="paid">{{ _("Paid") }}</span>
{% elif doc.status == "Overdue" %}
<span class="overdue">{{ _("Overdue") }}</span>
{% else %}
<span>{{ doc.status }}</span>
{% endif %}{%60 deterministic Claude AI skills for Frappe Framework & ERPNext v14-v16 development and operations
Use when designing multi-app Frappe architectures, deciding whether to split functionality into separate apps, or implementing…
Use when debugging Frappe errors, using bench console for live inspection, analyzing tracebacks, or reading Frappe log files.…
Use when receiving vague or unclear ERPNext/Frappe development requests that need interpretation. Transforms requirements like…
Use when migrating a Frappe app between major versions, detecting breaking API changes, or resolving post-migration errors.…
Use when reviewing or validating Frappe/ERPNext code against best practices and common pitfalls. Checks generated code before…
Use when building ERPNext/Frappe API integrations (v14/v15/v16) including REST API, RPC API, authentication, webhooks, and rate…
Behavioral guidelines to reduce common LLM coding mistakes. Use when writing, reviewing, or refactoring code to avoid…
Design and build AI agents for any domain. Use when users: (1) ask to "create an agent", "build an assistant", or "design an AI…