Are you able to:
- Provide feedback and/or test areas of DietPi, to improve the user experience?
- Report bugs using the this template?
- Improve or add features to DietPi, our website or documentation?
- Add new software titles?
- Implement support for new single-board computers?
If so, let us know! We are always looking for talented people who believe in the DietPi project, and, wish to contribute in any way you can.
- Git coders: use the active development branch: dev.
- See here for repository branch guidance.
- Read below for developer-focused guidance and quick reference.
- micha@dietpi.com
- GitHub: MichaIng/DietPi
The below guide should help contributors add or modify DietPi scripts under
/boot/dietpi with minimal friction. It focuses on safe extension points,
shared helpers, persistence conventions, and reviewer-friendly test plans.
The DietPi Git repository is separated into three branches:
master: stable release branch (production-ready).beta: public pre-release testing branch.dev: active development branch — implement new features and fixes here.
Guidance:
- Target
devfor code contributions and open PRs against it unless asked otherwise. - Switching branches on your DietPi device:
- Fresh image: Before first boot, edit
dietpi.txton the FAT partition of the flashed image, and changeDEV_GITBRANCH=. AdjustDEV_GITOWNER=accordingly, if you want to switch to your fork of DietPi. - Existing install: run
dietpi-backupfirst, then useG_DEV_BRANCH betaorG_DEV_BRANCH devto quickly to the respective branch, invokingdietpi-update.
- Fresh image: Before first boot, edit
- Warning:
betaand especiallydevcan be unstable; avoid using them on critical production systems. Have adietpi-backup, or do tests on a dedicated testing system.
- Globals: scripts source
dietpi/func/dietpi-globalsfor shared helpers and environment setup (G_INIT(),G_EXIT(), color vars, etc.). Read this file first to understand helper semantics and cancel/error behavior. - UI: prefer
G_WHIP_*dialog helpers for menus, input and confirmations to maintain a consistent user experience across scripts. - Error-handling: use
G_EXEC()to wrap any command call, so DietPi's error handler and consistent console output apply. Validate root permissions and write access usingG_CHECK_ROOT_USER()/G_CHECK_ROOTFS_RW()where required. - Persistence: Write arrays or variables into a preference file
/boot/dietpi/.<prog_settings>. Persist arrays as indexed assignments (e.g.aARRAY[index]=1). Convert ESC bytes to\ewhen saving text if needed. Load the preferences with. "/boot/dietpi/.<prog_settings>"
DietPi provides many G_ prefixed helpers in dietpi/func/dietpi-globals. Usage hints:
- Read
dietpi/func/dietpi-globalswhen adding behavior that interacts with the user, modifies files, or runs external commands — it documents optional environment variables and exit/cancel semantics for each helper. - Prefer the
G_helpers over ad-hoc implementations to keep error handling consistent and reduce reviewer friction.
Below are the most useful ones for contributors and how to use them safely.
-
G_INIT()— initialize script runtime, sets up the working directory, exit traps, consistent locale for parsing external command outputs, and handles concurrent execution checks. Call early after sourcingdietpi-globals. -
G_EXEC()— robust command executor with built-in retries and an interactive error handler. Use instead of directrm/systemctlin scripts so failures are presented to the user and logged consistently. Optional env vars:$G_EXEC_DESC,$G_EXEC_RETRIES,$G_EXEC_OUTPUT. -
G_CHECK_ROOT_USER(),G_CHECK_ROOTFS_RW()— validate that the script runs with necessary privileges and writable rootfs before performing writes. UsingG_CHECK_ROOT_USER "$@", if the script does not have root permissions, re-executes withsudo. "$@" passes all CLI arguments to thesudo-edscript. -
G_CONFIG_INJECT()— targeted config-file editing helper. Use to atomically replace, uncomment, or add config lines using predictable patterns rather than ad-hocsedcalls. -
G_GET_NET(),G_GET_WAN_IP()— network helpers that return standardized values; use-qto hide error messages. -
G_DIETPI-NOTIFY()/G_BUG_REPORT()— helpers to generate formatted bug reports and diagnostics. Use when capturing logs for PRs / issues. -
G_WHIP_*family — dialog and UI helpers: (G_WHIP_MSG(),G_WHIP_YESNO(),G_WHIP_MENU(),G_WHIP_CHECKLIST(),G_WHIP_INPUTBOX(),G_WHIP_PASSWORD(),G_WHIP_VIEWFILE()). Prefer these for user interaction to maintain consistent UX and behavior. Quick notes:- Return value:
$G_WHIP_RETURNED_VALUEholds the helper result — a single value for inputbox and menus, or an array of enabled indices for checklists. - Default item:
$G_WHIP_DEFAULT_ITEMsets the pre-selected value. ForG_WHIP_MENU()it must exactly match a menu label. - Checklist structure:
$G_WHIP_CHECKLIST_ARRAYentries are triples:'tag' 'Description' 'on/off'. Use safe tags (letters, digits, underscore) to avoid parsing issues. - Enumerated checklists: set
G_WHIP_CHECKLIST_ENUM=1to display numeric indices in the UI to avoid long, complex, or non-safe keys. - Input validation:
G_WHIP_INPUTBOX()supports$G_WHIP_INPUTBOX_REGEXand$G_WHIP_INPUTBOX_REGEX_TEXTto validate and describe allowed input. The helper loops until input matches the regex or the user cancels (|| return). - Dialog sizing: use
$G_WHIP_SIZE_X_MAXto limit dialog width; helpers respect terminal width and default to a max of 120 chars.
- Return value:
- Add handler: implement
Menu_<Name>()to present inputs (useG_WHIP_*), validate, and update in-memory variables (e.g.aENABLED[index]). - Register option: add the menu label into
Menu_Main()(scripts use a case-switch dispatch). Remember to update$MENU_LASTITEM_*indices if used. - Persist: Write arrays or variables into a preference file (see the 'Core concepts' section).
- Test: include interactive steps in your PR Test Plan (open menu, toggle,
verify
cat /boot/dietpi/.<prog_settings>).
Below are minimal, copy-paste-ready examples that follow DietPi conventions.
-
A typical script header
. /boot/dietpi/func/dietpi-globals readonly G_PROGRAM_NAME='DietPi-DevTest' G_CHECK_ROOT_USER "$@" # if the script requires root permissions G_CHECK_ROOTFS_RW # if the script requires write access G_INIT -
G_WHIP_MENU()a menu of items the user can scroll through (choose one):G_WHIP_MENU_ARRAY=( 'Start' 'Start the service' 'Stop' 'Stop the service' ) G_WHIP_DEFAULT_ITEM='Start' G_WHIP_MENU 'Select action:' || return case $G_WHIP_RETURNED_VALUE in Start) echo 'Starting...';; Stop) echo 'Stopping...';; esac -
G_WHIP_CHECKLIST()a list of items the user can enabled/disabled (multi-select):G_WHIP_CHECKLIST_ARRAY=() G_WHIP_CHECKLIST_ARRAY+=( '5' 'Enable Foo' "${aENABLED[5]:=0}" ) G_WHIP_CHECKLIST_ARRAY+=( '6' 'Enable Bar' "${aENABLED[6]:=0}" ) # Set G_WHIP_CHECKLIST_ENUM=1 to display numeric indices in the UI G_WHIP_CHECKLIST 'Choose features to enable:' || return for i in $G_WHIP_RETURNED_VALUE; do aENABLED[$i]=1; done Save > "$FP_SAVEFILE" -
G_WHIP_INPUTBOX()a text entry box (validated input):G_WHIP_INPUTBOX_REGEX='^[0-9]+$' G_WHIP_INPUTBOX_REGEX_TEXT='a number' G_WHIP_DEFAULT_ITEM=10 G_WHIP_INPUTBOX 'Set retry count:' || return RETRIES=$G_WHIP_RETURNED_VALUE -
G_WHIP_YESNO()Yes/No prompt (confirmation):if G_WHIP_YESNO 'Delete backup?'; then G_EXEC rm -rf "$TARGET" fi -
G_WHIP_VIEWFILE()displays a file that can be scrolled:log=1 G_WHIP_VIEWFILE "$FP_LOG" || return -
G_TRUNCATE_MID()shorten long strings by squishing the middle characters:G_TRUNCATE_MID "Long text to be shortened by removing the middle" 26 # -> "Long text to... the middle" # And `G_TRUNCATE_MID "alphabetical" N` returns the below, as N decreases # alp...al # al...al # alphab # alpha # alph # alp -
Save()example persistence pattern (beware of escape sequences):Save(){ # `echo` text to be eval-ed when re-loading # Call with `Save > "preference/file/path"` echo "aDESCRIPTION[10]='${aDESCRIPTION[10]}'" for i in "${!aENABLED[@]}"; do echo "aENABLED[$i]=${aENABLED[$i]}"; done for i in {0..6}; do val="${aCOLOUR[$i]}"; esc=$(printf '%s' "$val" | sed $'s/\x1b/\\e/g'); esc=${esc//\'/\\\'}; echo "aCOLOUR[$i]='$esc'"; done }
When adding banner items, follow this minimal pattern:
-
Describe: add the label to
aDESCRIPTION[index]and a default toaENABLED[index]during initialization if relevant (the standard default is disabled=0). If the item needs to show in the main menu checklist, addindexto MENU_ITEMS. -
Output: implement
Get_<Shortname>()and add a guarded line inPrint_Banner_raw():(( ${aENABLED[index]} )) && Print_Item_State "${aDESCRIPTION[index]}" "$(Get_Shortname 2>&1)" -
Persist: ensure
Save()writesaENABLED[index]=...so the state survives restarts.
TARGETMENUID=0 # start at the top level main menu
while (( TARGETMENUID != -1 )); do
case $TARGETMENUID in
0) Menu_Main; ;; # sets TARGETMENUID based on selection
1) Menu_Settings; TARGETMENUID=0 ;; # run settings page then return to main menu
-1) break;;
esac
done