Application policy (app)

August 31, 2026 ยท View on GitHub

lib_app.sh is an optional policy layer for applications that use the std and cli modules. It keeps configuration and lifecycle policy out of the foundation module while giving applications one small, composable contract.

The module is one sourceable file, is safe to source repeatedly, and never executes configuration data. Configuration files contain only trimmed key=value records; comments and blank lines are ignored. A malformed, unknown, or explicitly requested missing file is an error.

Configuration

base_app_init MODEL accepts only name=APP_KEY and description=TEXT. base_app_config_define MODEL KEY TYPE accepts env=NAME, default=VALUE, required=BOOL, secret=BOOL, enum=A,B, validator=FUNCTION, and help=TEXT. Attributes from one declaration context are rejected in the other with usage status 2.

base_app_init deploy name=deploy description="Example application"
base_app_config_define deploy channel enum \
  enum=stable,canary default=stable env=DEPLOY_CHANNEL
base_app_config_define deploy token string required=true secret=true env=DEPLOY_TOKEN

base_app_config_load deploy --user "$HOME/.config/deploy/config" \
  --project ./deploy.conf --cli channel=canary
base_app_config_get deploy channel channel
base_app_config_provenance deploy channel source

The deterministic precedence is CLI > environment > project > user > default. base_app_config_report prints key, source, and effective value as tab-separated records and redacts values declared with secret=true. Backslashes, tabs, carriage returns, and newlines in fields are escaped as \\, \\t, \\r, and \\n so each record remains one safe line. base_app_config_set_cli is a programmatic equivalent of --cli key=value.

base_app_config_load validates the complete candidate configuration before publishing it. If loading fails, the previously successful values and provenance remain unchanged; a successful load atomically replaces the model's complete effective snapshot.

Supported types are string, path, bool, integer, and enum. Optional validator=FUNCTION callbacks receive the candidate value and must return zero. No configuration value is evaluated as shell code.

Standard options and prompts

base_app_add_standard_options CLI_MODEL COMMAND_PATH adds opt-in --verbose, --quiet, --color, --dry-run, --non-interactive, --config, and --user-config options to a declarative CLI model. base_app_apply_standard_options publishes the parsed policy in BASE_BASH_LIBS_APP_* globals. Applications should call base_app_should_prompt before base_app_prompt; prompts are denied when stdin is not interactive or --non-interactive was selected.

Lifecycle

base_app_init deploy
base_app_hook deploy fatal report_failure report_failure_hook
base_app_hook deploy cleanup release_resources cleanup_hook
base_app_run deploy deploy_main "$@"

Hooks are named functions, receive (phase, status), and run in LIFO order. The normal/fatal/signal phase is followed by cleanup; each phase is dispatched at most once per base_app_run, and the application status is preserved even if a hook fails. INT, TERM, and HUP map to statuses 130, 143, and 129 respectively.

base_app_status MODEL RESULT_VARIABLE returns that model's most recent run or signal-derived status. A newly initialized model that has not run reports 0. BASE_BASH_LIBS_APP_LAST_STATUS remains the compatibility view of the most recently active model, but model-aware callers should use base_app_status.

The policy module owns no global trap or shell-code strings itself. It uses the stdlib's shared cleanup dispatcher and can therefore coexist with other cleanup paths and hooks.

The focused BATS coverage is in lib/bash/app/tests/lib_app.bats; the repository validation matrix also loads the module under every supported Bash option combination.