A VS Code-like IDE that lives inside Frappe Desk, powered by the Monaco editor.
Open it at /app/frappe_vs, or from the Frappe VS workspace in the Desk
sidebar (System Manager only).
Frappe VS is a Frappe custom app (no React build, no Node toolchain required).
A single Desk Page mounts Monaco and talks to a small set of whitelisted Python
methods in frappe_vs/api.py.
| Mode | When | What it does | Status |
|---|---|---|---|
| A | developer_mode ON |
Full filesystem IDE over the bench (browse/edit/create/rename/delete files). | shipped (file ops) |
| B | developer_mode OFF (and as a safe console anytime) |
Create/edit DB-stored, framework-safe objects through the DocType API. | shipped |
The active mode is detected server-side (frappe.conf.developer_mode) and
returned by get_context. When developer_mode is on, the explorer also offers
a Files / Objects switch (both consoles available). The filesystem endpoints
(Mode A) are hard-gated by a server-side developer_mode check — the client is
never trusted.
A real file tree rooted at apps/ (toggle to the whole bench), with
open / edit / save / create / rename / delete in Monaco (language auto-detected
by extension). Backend (all System-Manager + developer_mode gated):
fs_list_dir · fs_read_file · fs_write_file · fs_create_file ·
fs_create_folder · fs_rename · fs_delete
Path safety (the security boundary, all server-side):
developer_modemust be ON, else every endpoint refuses.- Every path is resolved with
realpathand confined to the bench root —.., absolute paths, and symlinks that escape the bench are rejected. - Reads/writes are limited to an editable-extension allowlist plus a
secret-file denylist (
site_config.json,*.key/*.pem,.env, SSH keys, …) — protected files cannot be opened or deleted. Non-empty folder deletes and reads over 2 MB are refused.
Create and edit these objects in Monaco. Every save goes through doc.save() /
doc.insert(), so native validation and safe_exec checks always fire — no
raw DB writes, never ignore_permissions.
| Object type | Editor | Language |
|---|---|---|
| Server Script | field script |
python |
| Client Script | field script |
javascript |
| Print Format (custom) | field html |
html |
| Web Template | field template |
html |
| Notification | field message |
html |
| Web Page | field main_section_html |
html |
| Report (Query / Script) | query / report_script (by type) |
sql / python |
| Custom DocType | whole document | json |
| Page (custom) | whole document | json |
| Custom Field | whole document | json |
| Property Setter | whole document | json |
The mapping lives in frappe_vs/registry.py, which is
also the allow-list: any object type not listed is refused by every endpoint.
- Explorer groups objects by type, lazy-loaded and permission-filtered.
- “New …” scaffolds any creatable object from a template (a dialog built from each type's required fields) and opens it.
- Tabs with dirty dots, Ctrl/Cmd+S, light/dark theme.
- Everything permission-gated per record (
frappe.has_permission) on top of the app-wide System Manager restriction.
get_context · get_registry · list_records · get_source · save_source
· create_object
A real interactive PTY shell (vim/top/Ctrl-C all work), opened in the bench
directory with the virtualenv on PATH. It is bridged to xterm.js by a small
standalone server, frappe_vs/pty_server.py
(stdlib WebSocket + pty, no extra deps).
Security model:
- The server binds 127.0.0.1 only and is launched on demand by the
terminal_startendpoint (System-Manager +developer_modegated). - Each WebSocket connection must present a single-use token (issued by that endpoint, stored in redis with a 60s TTL, consumed on connect).
- The shell is full access (RCE) by design — reachable only on localhost, in
developer_mode, by a System Manager. For an HTTPS Desk you'd front the socket withwss://.
Loaded through its AMD loader from a CDN (jsDelivr) with a self-host fallback
served at /assets/frappe_vs/monaco/. See
frappe_vs/public/monaco/README.md to
vendor Monaco locally (run ./fetch_monaco.sh) for offline / air-gapped use.
- ✅ App scaffold + Desk Page + Monaco mount + mode detection.
- ✅ Mode B — safe object editor + “New” scaffolding (works on any site).
- ✅ Mode A file tree + read/edit/save/create/rename/delete,
developer_mode-gated, path-confined to the bench root. - ✅ Integrated terminal — real interactive PTY over a stdlib WebSocket server,
developer_mode-gated, 127.0.0.1-only, single-use token auth. - ⏳ Git diff + find-in-files + remaining VS Code polish.
MIT