Architecture
The repositories behind Community Scripts and a map of every engine file, what it holds and who loads it.
Community Scripts is split across several repositories. The application scripts say what an application needs; one shared engine does the work.
| Repository | Holds |
|---|---|
| core | The engine: Bash libraries, dialogs, host backends, in-container bootstrap, helper functions, telemetry client, header banners |
| ProxmoxVE | The released application scripts (ct/, install/), VM scripts (vm/) and tools (tools/) |
| DevScripts | New application scripts while they are being tested |
| Incus | The application scripts for Incus hosts, plus Incus-only VMs and tools |
No script repository contains engine code. Each script loads the engine from
core when it starts.
How a run flows
ct/<app>.sh host
└─ core/build.func find both roots, prefetch, detect platform
├─ ui/build-ui.func dialogs; loads api, core, error handler, dev mode
└─ pve/backend.func or incus/build.func on Incus
└─ build_container create and start the container
└─ lxc/install.func + install/<app>-install.sh container
└─ core/core.func, core/error_handler.func, lib/tools.funcThe ct script never chooses a platform. core/build.func detects the host
once and loads the matching backend; the dialogs and the in-container
bootstrap are shared. The step-by-step order is on
Runtime, and how files are found is on
Loading.
Why the engine is separate
The engine and the scripts are resolved independently: a local checkout wins, then the Git origin of that checkout, then the published default. A fork of an application script therefore runs against the released engine, and an engine branch can be tested with the released scripts, without touching the other side.
It is also why DevScripts and Incus are repositories of their own and not branches of ProxmoxVE. A new script is tested in DevScripts against the same engine every other script uses and then moved to ProxmoxVE.
The engine's files
The engine consists of 36 .func files in nine folders. Paths are always
written with the folder, because several folders contain a file of the same
name.
core/ — runs everywhere
| File | Holds | Loaded by | Docs |
|---|---|---|---|
core/build.func | Entry point of every ct script: the two source roots, _cs_source_func, prefetch, host probes, platform dispatch | the first lines of a ct script | Loading |
core/core.func | Colours, msg_*, $STD/silent, prompts, host checks, cleanup_lxc, the update entry point | ui/build-ui.func, incus/core.func, lxc/install.func, add-on scripts | core.func |
core/error_handler.func | catch_errors, the ERR/EXIT/signal handlers, failure explanation and hints | ui/build-ui.func, lxc/install.func, add-on scripts | Error handling |
core/dev-mode.func | parse_dev_mode, the dev context block, step timing, the dev-mode picker | ui/build-ui.func; lxc/install.func when dev_mode is set | Dev mode |
host/ — host-side helpers
| File | Holds | Loaded by | Docs |
|---|---|---|---|
host/source-origin.func | Turns a checkout's Git remote and branch into a raw-content URL | core/build.func, only from a local engine checkout | Loading |
host/validate.func | validate_mac_address, validate_vlan_tag, validate_mtu | ui/build-ui.func, pve/vm-core.func, incus/vm-core.func | Wizard |
host/preflight.func | Optional pre-flight checks for kernel keys, storage, bridge, DNS, quorum, LXC stack and templates | run_preflight in ui/build-ui.func, only with ENABLE_PREFLIGHT=1 | below |
ui/ — the install dialogs
| File | Holds | Loaded by | Docs |
|---|---|---|---|
ui/build-ui.func | Loader of the dialog parts; variables, maxkeys_check | core/build.func, incus/build.func | Wizard |
ui/menu.func | install_script, start, the settings and diagnostics menus, the update path and its guards | ui/build-ui.func | Wizard, Updates |
ui/advanced.func | advanced_settings, the Advanced Install dialogs | ui/build-ui.func | Wizard |
ui/defaults.func | base_settings, default.vars and app defaults files, storage selection for defaults | ui/build-ui.func | Wizard |
ui/validate.func | Input validation and IP helpers, SSH key installation | ui/build-ui.func | Wizard |
pve/ and incus/ — platform backends
| File | Holds | Loaded by | Docs |
|---|---|---|---|
pve/backend.func | build_container, create_lxc_container, storage and template handling, the recovery menu, description | core/build.func on everything that is not Incus | Platforms |
pve/vm-core.func | Entry point of VM scripts on Proxmox VE: messages, dialogs and qm handling | vm/*.sh scripts | VM paths |
pve/vm-app.func | build_app_vm: runs a container install script inside a VM image | nothing in the engine; a script has to source it itself | VM paths |
incus/build.func | Incus entry: loads the shared dialogs and replaces the Proxmox-specific hooks | core/build.func on Incus hosts and in Incus containers | Platforms |
incus/core.func | Incus variants of the message, execution and error functions | incus/build.func, incus/tools.func, incus/vm-core.func | Platforms |
incus/backend.func | Container creation and install on Incus | incus/build.func | Platforms |
incus/tools.func | Compatibility aliases and Incus overrides on top of lib/tools.func | incus/build.func | Platforms |
incus/vm-core.func | VM creation on Incus (incus_vm_create) | pve/vm-core.func when it runs on an Incus host | VM paths |
vm/ — shared VM helpers
| File | Holds | Loaded by | Docs |
|---|---|---|---|
vm/common.func | VM helpers that call neither qm nor incus: host tools, release assets, checksums | pve/vm-core.func, incus/vm-core.func | VM paths |
vm/cloud-init.func | Cloud-Init setup for Proxmox VE VMs | load_cloud_init_functions in pve/vm-core.func | VM paths |
lxc/ — inside the container
| File | Holds | Loaded by | Docs |
|---|---|---|---|
lxc/install.func | The in-container bootstrap for all distributions: setting_up_container, network_check, update_os, motd_ssh, customize, the pkg_* and svc_* wrappers | the install script, from FUNCTIONS_FILE_PATH | Containers |
lxc/platform.func | detect_lxc_platform, community_scripts_dir | core/build.func | Loading |
lib/ — install helpers
Scripts load lib/tools.func (or lib/alpine.func on Alpine) and get all
parts.
| File | Holds | Loaded by | Docs |
|---|---|---|---|
lib/tools.func | Loader of the five parts below | start on the host, update_os in the container, add-on scripts | Libraries |
lib/system.func | Packages, repositories, OS probes, services, temporary files | lib/tools.func | System helpers |
lib/forge.func | GitHub, GitLab and Codeberg releases, tags and branches | lib/tools.func | Releases |
lib/runtime.func | Language runtimes and application installers | lib/tools.func | Runtimes |
lib/db.func | Databases and search engines | lib/tools.func | Databases |
lib/hwaccel.func | GPU detection and hardware acceleration | lib/tools.func | Hardware acceleration |
lib/alpine.func | Helper set for Alpine containers | update_os on Alpine | Alpine helpers |
api/ — telemetry and error texts
| File | Holds | Loaded by | Docs |
|---|---|---|---|
api/api.func | Loader of the four parts below; telemetry URL and payload version | ui/build-ui.func, VM cores, add-on scripts | Telemetry |
api/exitcodes.func | explain_exit_code, categorize_error | api/api.func; lxc/install.func in the container | Exit codes |
api/errorlog.func | The .errinfo capture format, log filtering, build_error_string | api/api.func; lxc/install.func in the container | Error handling |
api/sysinfo.func | Which repository the script came from, and host facts | api/api.func | Telemetry |
api/telemetry.func | post_to_api, post_update_to_api, payload and delivery | api/api.func | Telemetry |
Pre-flight checks
host/preflight.func is not loaded in a normal run. It defines twelve checks
that collect results instead of stopping at the first problem, and assign each
failure an exit code:
| Check | Fails with |
|---|---|
| Kernel key limits for UID 100000 | 107 (unreadable), 108 (near the limit) |
A storage with rootdir content | 119 |
A storage with vztmpl content | 120 |
Free space for var_disk | 214 |
A vmbr* bridge | 116 (a missing vmbr0 alone is a warning) |
| DNS resolution | 222 |
| Enterprise repository without subscription | warning only |
| Cluster quorum | 210 |
pve-container and lxc-pve installed | 231 |
| A container ID can be allocated | 109 |
| Template server reachable, or local templates present | 222 |
A template for var_os and var_version | 225 |
On current main setting ENABLE_PREFLIGHT=1 loads the file but the checks
are not executed by the install flow: the wrapper in ui/build-ui.func looks
for a function named run_preflight_full, and the file defines run_preflight.
The kernel key check that always runs is maxkeys_check in ui/build-ui.func.
Rules that follow from this layout
- A ct script loads
core/build.funcand nothing else from the engine. - An install script sources
FUNCTIONS_FILE_PATHand nothing else. - Load
lib/tools.func,ui/build-ui.funcandapi/api.func, not their parts. The loaders set the order the parts depend on. - Inside the engine, load files with
_cs_source_func "<folder>/<file>", never with a fixed URL.
The technical reference lists load guards and the variables that make up the contract between host and container.