# 🤖 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`) ```bash #!/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`) ```bash #!/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 </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`:** ```bash # 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:** ```bash 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 ```bash # ❌ 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 ```bash # ❌ 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 ```bash # ❌ 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 ```bash # ❌ 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 ```bash # ❌ 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 ```bash # ❌ 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 ```bash # ❌ 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 ```bash # ❌ 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_release` - `check_for_gh_release` - `setup_nodejs` - `setup_postgresql` / `setup_postgresql_db` - `setup_mariadb` / `setup_mariadb_db` - `setup_mongodb` - `setup_mysql` - `setup_ruby` - `setup_go` - `setup_java` - `setup_php` - `setup_uv` - `setup_rust` - `setup_composer` - `setup_ffmpeg` - `setup_imagemagick` - `setup_gs` - `setup_adminer` - `setup_hwaccel` --- ## 📝 Important Rules ### Variable Declarations (CT Script) ```bash # 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 ```bash 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 ```bash msg_info "Creating Service" cat </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 ```bash # 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_release` used for GitHub releases - [ ] `check_for_gh_release` used for update checks - [ ] `setup_*` functions used for runtimes (nodejs, postgresql, etc.) - [ ] **`tools.func` functions NOT wrapped in msg_info/msg_ok blocks** - [ ] No redundant variables - [ ] `$STD` before all apt/npm/build commands - [ ] `msg_info`/`msg_ok`/`msg_error` for logging (only for custom code) - [ ] Correct script structure followed - [ ] Update function present and functional - [ ] Data backup implemented in update function - [ ] `motd_ssh`, `customize`, `cleanup_lxc` at the end - [ ] No custom download/version-check logic - [ ] JSON metadata file created in `frontend/public/json/.json` --- ## 📖 Reference: Good Example (Termix) ### CT Script: [ct/termix.sh](../ct/termix.sh) - Uses `check_for_gh_release` for version checking - Uses `CLEAN_INSTALL=1 fetch_and_deploy_gh_release` for clean updates - Backup/restore of `/opt/termix/data` - Correct structure with all required variables ### Install Script: [install/termix-install.sh](../install/termix-install.sh) - `NODE_VERSION="22" setup_nodejs` instead of manual installation - `fetch_and_deploy_gh_release "termix" "Termix-SSH/Termix"` instead of wget/curl - Clean service configuration - Correct footer with `motd_ssh`, `customize`, `cleanup_lxc` --- ## � JSON Metadata Files Every application requires a JSON metadata file in `frontend/public/json/.json`. ### JSON Structure ```json { "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 ```json "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 ```json "default_credentials": { "username": "admin", "password": "admin" } ``` Or no credentials: ```json "default_credentials": { "username": null, "password": null } ``` --- ## �💡 Tips for AI Assistants 1. **Search `tools.func` first** before implementing custom solutions 2. **Use existing scripts as reference** (e.g., `linkwarden-install.sh`, `homarr-install.sh`) 3. **Ask when uncertain** instead of introducing wrong patterns 4. **Consistency > Creativity** - follow established patterns 5. **Test local variables** - use `${VAR:-default}` pattern for optional values --- ## 📚 Further Documentation - [CONTRIBUTING.md](contribution/CONTRIBUTING.md) - General contribution guidelines - [GUIDE.md](contribution/GUIDE.md) - Detailed developer documentation - [TECHNICAL_REFERENCE.md](TECHNICAL_REFERENCE.md) - Technical details - [EXIT_CODES.md](EXIT_CODES.md) - Exit code reference