Skip to content
AI & Agents
Skill

/frappe-core-files

Use when handling file uploads, attachments, private/public file access, or S3 storage configuration. Prevents broken file URLs, permission leaks on private files, and failed uploads from incorrect MIME handling. Covers File DocType, frappe.get_file, upload API, private vs

From plugin
frappe-claude-skill-package
17961 skills
Install
$ npx -y skills add Impertio-Studio/Frappe_Claude_Skill_Package --skill frappe-core-files --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-core-files

Context preview

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

Use when handling file uploads, attachments, private/public file access, or S3 storage configuration. Prevents broken file URLs, permission leaks on private files, and failed uploads from incorrect MIME handling. Covers File DocType, frappe.get_file, upload API, private vs

SKILL.md

frappe-core-files.SKILL.md
name: frappe-core-files
description: >
  Use when handling file uploads, attachments, private/public file access, or S3 storage configuration.
  Prevents broken file URLs, permission leaks on private files, and failed uploads from incorrect MIME handling.
  Covers File DocType, frappe.get_file, upload API, private vs public directories, S3 integration, file URL patterns, attach field types.
  Keywords: file, upload, attachment, File DocType, private, public, S3, file_url, get_file, attach, upload not working, file missing, broken file link, download file, image not showing, attachment error..
license: MIT
compatibility: "Claude Code, Claude.ai Projects, Claude API. Frappe v14-v16."
metadata:
  author: OpenAEC-Foundation
  version: "2.0"

Frappe File Management

Quick Reference

| Action | Method | Notes | |--------|--------|-------| | Save file from bytes | `save_file(fname, content, dt, dn)` | Returns File doc | | Save file from URL | `save_url(file_url, fname, dt, dn)` | Creates File doc from URL | | Read file content | `frappe.get_file(fname)` | Returns `[filename, content]` | | Get file path | `get_file_path(file_name)` | Resolves to absolute path | | Upload via HTTP | `POST /api/method/upload_file` | Multipart form upload | | Delete file | `frappe.delete_doc("File", name)` | Removes doc + filesystem file | | Attach print | `frappe.attach_print(dt, dn, print_format)` | Returns `{"fname", "fcontent"}` | | Get cached doc | `frappe.get_cached_doc("File", name)` | Read-only, cached |

---

Decision Tree

What file operation do you need?
│
├─ Upload a file from user input?
│  ├─ Via web form → Attach field type (auto-handles upload)
│  └─ Via API → POST /api/method/upload_file
│
├─ Create a file programmatically?
│  ├─ From bytes/content → save_file(fname, content, dt, dn)
│  ├─ From external URL → save_url(file_url, fname, dt, dn)
│  └─ Full control → frappe.get_doc({"doctype": "File", ...}).insert()
│
├─ Read file content?
│  ├─ By filename → frappe.get_file(fname)
│  └─ By File doc → file_doc.get_content()
│
├─ Public or private?
│  ├─ Public (anyone with link) → is_private=0, URL: /files/fname
│  └─ Private (permission-based) → is_private=1, URL: /private/files/fname
│
└─ Generate PDF attachment?
   └─ frappe.attach_print(doctype, name, print_format)

---

File DocType: Core Fields

| Field | Type | Description | |-------|------|-------------| | `file_name` | Data | Filename without path | | `file_url` | Data | URL path (e.g., `/files/report.pdf`) | | `file_type` | Data | Extension (PDF, PNG, DOCX, etc.) | | `is_private` | Check | 0 = public, 1 = private | | `is_folder` | Check | True for folder entries | | `folder` | Link → File | Parent folder | | `attached_to_doctype` | Link → DocType | Parent document type | | `attached_to_name` | Data | Parent document name | | `attached_to_field` | Data | Field name on parent | | `content_hash` | Data | SHA-256 for deduplication | | `file_size` | Int | Size in bytes |

---

File URL Patterns

| Type | URL Pattern | Filesystem Path | |------|------------|-----------------| | Public | `/files/{filename}` | `{site}/public/files/{filename}` | | Private | `/private/files/{filename}` | `{site}/private/files/{filename}` | | Remote | `https://...` | Not stored locally | | API | `/api/method/{path}` | Generated dynamically |

Valid URL prefixes: `http://`, `https://`, `/api/method/`, `/files/`, `/private/files/`.

ALWAYS use `/private/files/` for sensitive documents. Public files are accessible to anyone with the URL, including unauthenticated users.

---

Permission Model

Frappe files use a three-tier permission model:

1. **Administrator** — unrestricted access to all files 2. **Public files** (`is_private=0`) — readable by anyone with the URL (no authentication required for read) 3. **Private files** (`is_private=1`) — access requires:

  • User is the file owner, OR
  • User has explicit share on the file, OR
  • User has read permission on the `attached_to_doctype`/`attached_to_name` document

NEVER store sensitive data as public files. ALWAYS set `is_private=1` for documents containing personal data, financial records, or confidential information.

---

Programmatic File Operations

Save File from Content

from frappe.utils.file_manager import save_file

# Save a generated CSV
csv_content = "Name,Amount\nACME,1000\nGlobex,2000"
file_doc = save_file(
    fname="report.csv",
    content=csv_content.encode("utf-8"),
    dt="Sales Invoice",           # attach to this DocType
    dn="SINV-00001",              # attach to this document
    folder="Home/Attachments",    # optional folder
    is_private=1,                 # private file
)
# file_doc.file_url → "/private/files/report.csv"

Save File from URL

from frappe.utils.file_manager import save_url

file_doc = save_url(
    file_url="https://example.com/logo.png",
    filename="company-logo.png",
    dt="Company",
    dn="My Company",
    folder="Home",
    is_private=0,
)

Read File Content

# By filename
filename, content = frappe.get_file("report.csv")

# By File document
file_doc = frappe.get_doc("File", {"file_name": "report.csv"})
content_bytes = file_doc.get_content()

Create File Document Directly

file_doc = frappe.get_doc({
    "doctype": "File",
    "file_name": "generated-report.pdf",
    "attached_to_doctype": "Sales Invoice",
    "attached_to_name": "SINV-00001",
    "is_private": 1,
    "content": pdf_bytes,  # raw bytes — written to disk on insert
}).insert(ignore_permissions=True)

Generate and Attach PDF

# Create PDF attachment dict (for use with sendmail)
pdf_attachment = frappe.attach_print(
    "Sales Invoice",
    "SINV-00001",
    print_format="Standard",
)
# Returns: {"fname": "Sales Invoice - SINV-00001.pdf", "fcontent": <bytes>}

# Save PDF as file attachment
from frappe.utils.file_manager import save_file

pdf = frappe.get_print("Sales Invoice", "SIN
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
15d ago
Added

Repo: Impertio-Studio/Frappe_Claude_Skill_Package