17 KiB
17 KiB
🤖 AI Contribution Guidelines for ProxmoxVED
This documentation is intended for all AI assistants (GitHub Copilot, Claude, ChatGPT, etc.) contributing to this project.
🎯 Core Principles
1. Maximum Use of tools.func Functions
We have an extensive library of helper functions. NEVER implement your own solutions when a function already exists!
2. No Pointless Variables
Only create variables when they:
- Are used multiple times
- Improve readability
- Are intended for configuration
3. Consistent Script Structure
All scripts follow an identical structure. Deviations are not acceptable.
4. Bare-Metal Installation
We do NOT use Docker for our installation scripts. All applications are installed directly on the system.
📁 Script Types and Their Structure
CT Script (ct/AppName.sh)
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)
# Copyright (c) 2021-2026 community-scripts ORG
# Author: AuthorName (GitHubUsername)
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
# Source: https://application-url.com
APP="AppName"
var_tags="${var_tags:-tag1;tag2;tag3}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}"
var_disk="${var_disk:-8}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -d /opt/appname ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "appname" "owner/repo"; then
msg_info "Stopping Service"
systemctl stop appname
msg_ok "Stopped Service"
msg_info "Backing up Data"
cp -r /opt/appname/data /opt/appname_data_backup
msg_ok "Backed up Data"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "appname" "owner/repo"
# Build steps...
msg_info "Restoring Data"
cp -r /opt/appname_data_backup/. /opt/appname/data
rm -rf /opt/appname_data_backup
msg_ok "Restored Data"
msg_info "Starting Service"
systemctl start appname
msg_ok "Started Service"
msg_ok "Updated successfully!"
fi
exit
}
start
build_container
description
msg_ok "Completed Successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:PORT${CL}"
Install Script (install/AppName-install.sh)
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: AuthorName (GitHubUsername)
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
# Source: https://application-url.com
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Installing Dependencies"
$STD apt-get install -y \
dependency1 \
dependency2
msg_ok "Installed Dependencies"
# Runtime Setup (ALWAYS use our functions!)
NODE_VERSION="22" setup_nodejs
# or
PG_VERSION="16" setup_postgresql
# or
setup_uv
# etc.
fetch_and_deploy_gh_release "appname" "owner/repo"
msg_info "Setting up Application"
cd /opt/appname
# Build/Setup Schritte...
msg_ok "Set up Application"
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/appname.service
[Unit]
Description=AppName Service
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/appname
ExecStart=/path/to/executable
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now appname
msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
🔧 Available Helper Functions
Release Management
| Function | Description | Example |
|---|---|---|
fetch_and_deploy_gh_release |
Fetches and installs GitHub Release | fetch_and_deploy_gh_release "app" "owner/repo" |
check_for_gh_release |
Checks for new version | if check_for_gh_release "app" "owner/repo"; then |
Modes for fetch_and_deploy_gh_release:
# Tarball/Source (Standard)
fetch_and_deploy_gh_release "appname" "owner/repo"
# Binary (.deb)
fetch_and_deploy_gh_release "appname" "owner/repo" "binary"
# Prebuilt Archive
fetch_and_deploy_gh_release "appname" "owner/repo" "prebuild" "latest" "/opt/appname" "filename.tar.gz"
# Single Binary
fetch_and_deploy_gh_release "appname" "owner/repo" "singlefile" "latest" "/opt/appname" "binary-linux-amd64"
Clean Install Flag:
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "appname" "owner/repo"
Runtime/Language Setup
| Function | Variable(s) | Example |
|---|---|---|
setup_nodejs |
NODE_VERSION, NODE_MODULE |
NODE_VERSION="22" setup_nodejs |
setup_uv |
UV_PYTHON |
UV_PYTHON="3.12" setup_uv |
setup_go |
GO_VERSION |
GO_VERSION="1.22" setup_go |
setup_rust |
RUST_VERSION, RUST_CRATES |
RUST_CRATES="monolith" setup_rust |
setup_ruby |
RUBY_VERSION |
RUBY_VERSION="3.3" setup_ruby |
setup_java |
JAVA_VERSION |
JAVA_VERSION="21" setup_java |
setup_php |
PHP_VERSION, PHP_MODULES |
PHP_VERSION="8.3" PHP_MODULES="redis,gd" setup_php |
Database Setup
| Function | Variable(s) | Example |
|---|---|---|
setup_postgresql |
PG_VERSION, PG_MODULES |
PG_VERSION="16" setup_postgresql |
setup_postgresql_db |
PG_DB_NAME, PG_DB_USER |
PG_DB_NAME="mydb" PG_DB_USER="myuser" setup_postgresql_db |
setup_mariadb_db |
MARIADB_DB_NAME, MARIADB_DB_USER |
MARIADB_DB_NAME="mydb" setup_mariadb_db |
setup_mysql |
MYSQL_VERSION |
setup_mysql |
setup_mongodb |
MONGO_VERSION |
setup_mongodb |
setup_clickhouse |
- | setup_clickhouse |
Tools & Utilities
| Function | Description |
|---|---|
setup_adminer |
Installs Adminer for DB management |
setup_composer |
Install PHP Composer |
setup_ffmpeg |
Install FFmpeg |
setup_imagemagick |
Install ImageMagick |
setup_gs |
Install Ghostscript |
setup_hwaccel |
Configure hardware acceleration |
Helper Utilities
| Function | Description | Example |
|---|---|---|
import_local_ip |
Sets $LOCAL_IP variable |
import_local_ip |
ensure_dependencies |
Checks/installs dependencies | ensure_dependencies curl jq |
install_packages_with_retry |
APT install with retry | install_packages_with_retry nginx redis |
❌ Anti-Patterns (NEVER use!)
1. Pointless Variables
# ❌ WRONG - unnecessary variables
APP_NAME="myapp"
APP_DIR="/opt/${APP_NAME}"
APP_USER="root"
APP_PORT="3000"
cd $APP_DIR
# ✅ CORRECT - use directly
cd /opt/myapp
2. Custom Download Logic
# ❌ WRONG - custom wget/curl logic
RELEASE=$(curl -s https://api.github.com/repos/owner/repo/releases/latest | jq -r '.tag_name')
wget https://github.com/owner/repo/archive/${RELEASE}.tar.gz
tar -xzf ${RELEASE}.tar.gz
mv repo-${RELEASE} /opt/myapp
# ✅ CORRECT - use our function
fetch_and_deploy_gh_release "myapp" "owner/repo"
3. Custom Version-Check Logic
# ❌ WRONG - custom version check
CURRENT=$(cat /opt/myapp/version.txt)
LATEST=$(curl -s https://api.github.com/repos/owner/repo/releases/latest | jq -r '.tag_name')
if [[ "$CURRENT" != "$LATEST" ]]; then
# update...
fi
# ✅ CORRECT - use our function
if check_for_gh_release "myapp" "owner/repo"; then
# update...
fi
4. Docker-based Installation
# ❌ WRONG - using Docker
docker pull myapp/myapp:latest
docker run -d --name myapp myapp/myapp:latest
# ✅ CORRECT - Bare-Metal Installation
fetch_and_deploy_gh_release "myapp" "owner/repo"
npm install && npm run build
5. Custom Runtime Installation
# ❌ WRONG - custom Node.js installation
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
apt install -y nodejs
# ✅ CORRECT - use our function
NODE_VERSION="22" setup_nodejs
6. Redundant echo Statements
# ❌ WRONG - custom logging messages
echo "Installing dependencies..."
apt install -y curl
echo "Done!"
# ✅ CORRECT - use msg_info/msg_ok
msg_info "Installing Dependencies"
$STD apt install -y curl
msg_ok "Installed Dependencies"
7. Missing $STD Usage
# ❌ WRONG - apt without $STD
apt install -y nginx
# ✅ CORRECT - with $STD for silent output
$STD apt install -y nginx
8. Wrapping tools.func Functions in msg Blocks
# ❌ WRONG - tools.func functions have their own msg_info/msg_ok!
msg_info "Installing Node.js"
NODE_VERSION="22" setup_nodejs
msg_ok "Installed Node.js"
msg_info "Updating Application"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "appname" "owner/repo"
msg_ok "Updated Application"
# ✅ CORRECT - call directly without msg wrapper
NODE_VERSION="22" setup_nodejs
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "appname" "owner/repo"
Functions with built-in messages (NEVER wrap in msg blocks):
fetch_and_deploy_gh_releasecheck_for_gh_releasesetup_nodejssetup_postgresql/setup_postgresql_dbsetup_mariadb/setup_mariadb_dbsetup_mongodbsetup_mysqlsetup_rubysetup_gosetup_javasetup_phpsetup_uvsetup_rustsetup_composersetup_ffmpegsetup_imagemagicksetup_gssetup_adminersetup_hwaccel
📝 Important Rules
Variable Declarations (CT Script)
# Standard declarations (ALWAYS present)
APP="AppName"
var_tags="${var_tags:-tag1;tag2}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}"
var_disk="${var_disk:-8}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_unprivileged="${var_unprivileged:-1}"
Update-Script Pattern
function update_script() {
header_info
check_container_storage
check_container_resources
# 1. Check if installation exists
if [[ ! -d /opt/appname ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
# 2. Check for update
if check_for_gh_release "appname" "owner/repo"; then
# 3. Stop service
msg_info "Stopping Service"
systemctl stop appname
msg_ok "Stopped Service"
# 4. Backup data (if present)
msg_info "Backing up Data"
cp -r /opt/appname/data /opt/appname_data_backup
msg_ok "Backed up Data"
# 5. Perform clean install
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "appname" "owner/repo"
# 6. Rebuild (if needed)
cd /opt/appname
$STD npm install
$STD npm run build
# 7. Restore data
msg_info "Restoring Data"
cp -r /opt/appname_data_backup/. /opt/appname/data
rm -rf /opt/appname_data_backup
msg_ok "Restored Data"
# 8. Start service
msg_info "Starting Service"
systemctl start appname
msg_ok "Started Service"
msg_ok "Updated successfully!"
fi
exit # IMPORTANT: Always end with exit!
}
Systemd Service Pattern
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/appname.service
[Unit]
Description=AppName Service
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/appname
Environment=NODE_ENV=production
ExecStart=/usr/bin/node /opt/appname/server.js
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now appname
msg_ok "Created Service"
Installation Script Footer
# ALWAYS at the end of the install script:
motd_ssh
customize
cleanup_lxc
🔍 Checklist Before PR Creation
- No Docker installation used
fetch_and_deploy_gh_releaseused for GitHub releasescheck_for_gh_releaseused for update checkssetup_*functions used for runtimes (nodejs, postgresql, etc.)tools.funcfunctions NOT wrapped in msg_info/msg_ok blocks- No redundant variables
$STDbefore all apt/npm/build commandsmsg_info/msg_ok/msg_errorfor logging (only for custom code)- Correct script structure followed
- Update function present and functional
- Data backup implemented in update function
motd_ssh,customize,cleanup_lxcat the end- No custom download/version-check logic
- JSON metadata file created in
frontend/public/json/<appname>.json
📖 Reference: Good Example (Termix)
CT Script: ct/termix.sh
- Uses
check_for_gh_releasefor version checking - Uses
CLEAN_INSTALL=1 fetch_and_deploy_gh_releasefor clean updates - Backup/restore of
/opt/termix/data - Correct structure with all required variables
Install Script: install/termix-install.sh
NODE_VERSION="22" setup_nodejsinstead of manual installationfetch_and_deploy_gh_release "termix" "Termix-SSH/Termix"instead of wget/curl- Clean service configuration
- Correct footer with
motd_ssh,customize,cleanup_lxc
<EFBFBD> JSON Metadata Files
Every application requires a JSON metadata file in frontend/public/json/<appname>.json.
JSON Structure
{
"name": "AppName",
"slug": "appname",
"categories": [1],
"date_created": "2026-01-16",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 3000,
"documentation": "https://docs.appname.com/",
"website": "https://appname.com/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/appname.webp",
"config_path": "/opt/appname/.env",
"description": "Short description of the application and its purpose.",
"install_methods": [
{
"type": "default",
"script": "ct/appname.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 8,
"os": "Debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}
Required Fields
| Field | Type | Description |
|---|---|---|
name |
string | Display name of the application |
slug |
string | Lowercase, no spaces, used for filenames |
categories |
array | Category ID(s) - see category list below |
date_created |
string | Creation date (YYYY-MM-DD) |
type |
string | ct for container, vm for virtual machine |
updateable |
boolean | Whether update_script is implemented |
privileged |
boolean | Whether container needs privileged mode |
interface_port |
number | Primary web interface port (or null) |
documentation |
string | Link to official docs |
website |
string | Link to official website |
logo |
string | URL to application logo (preferably selfhst icons) |
config_path |
string | Path to main config file (or empty string) |
description |
string | Brief description of the application |
install_methods |
array | Installation configurations |
default_credentials |
object | Default username/password (or null) |
notes |
array | Additional notes/warnings |
Categories
| ID | Category |
|---|---|
| 0 | Miscellaneous |
| 1 | Proxmox & Virtualization |
| 2 | Operating Systems |
| 3 | Containers & Docker |
| 4 | Network & Firewall |
| 5 | Adblock & DNS |
| 6 | Authentication & Security |
| 7 | Backup & Recovery |
| 8 | Databases |
| 9 | Monitoring & Analytics |
| 10 | Dashboards & Frontends |
| 11 | Files & Downloads |
| 12 | Documents & Notes |
| 13 | Media & Streaming |
| 14 | *Arr Suite |
| 15 | NVR & Cameras |
| 16 | IoT & Smart Home |
| 17 | ZigBee, Z-Wave & Matter |
| 18 | MQTT & Messaging |
| 19 | Automation & Scheduling |
| 20 | AI / Coding & Dev-Tools |
| 21 | Webservers & Proxies |
| 22 | Bots & ChatOps |
| 23 | Finance & Budgeting |
| 24 | Gaming & Leisure |
| 25 | Business & ERP |
Notes Format
"notes": [
{
"text": "Change the default password after first login!",
"type": "warning"
},
{
"text": "Requires at least 4GB RAM for optimal performance.",
"type": "info"
}
]
Note types: info, warning, error
Examples with Credentials
"default_credentials": {
"username": "admin",
"password": "admin"
}
Or no credentials:
"default_credentials": {
"username": null,
"password": null
}
<EFBFBD>💡 Tips for AI Assistants
- Search
tools.funcfirst before implementing custom solutions - Use existing scripts as reference (e.g.,
linkwarden-install.sh,homarr-install.sh) - Ask when uncertain instead of introducing wrong patterns
- Consistency > Creativity - follow established patterns
- Test local variables - use
${VAR:-default}pattern for optional values
📚 Further Documentation
- CONTRIBUTING.md - General contribution guidelines
- GUIDE.md - Detailed developer documentation
- TECHNICAL_REFERENCE.md - Technical details
- EXIT_CODES.md - Exit code reference