Skip to content
Bartl

One startup path. Multiple states.

Install, restore, upgrade: one shared startup path.

Bartl is an operating philosophy for resilience and sovereignty that can actually be exercised. It connects application, infrastructure and responsibility for the complete service. This page explains one technical contribution: the shared startup path for stateful applications.

Decision logic

How the application starts

You install or start the application. It works out what needs doing:

  • If its data is already there, it uses it.
  • Otherwise, it restores the latest backup.
  • If no backup store is configured, or there is no backup yet, it starts with the application's initial data.
  • If the software is newer than the data, it performs the necessary update.

You do not have to choose or manually perform those internal steps.

For routine upgrades, we can install the newer version as a replacement rather than change the running installation. The replacement restores the backup and updates the data through that same procedure. Each such upgrade therefore also exercises recovery.

This is an operating choice, not a different application mechanism: we select the version and where it should run; the application determines the steps.

Choosing a replacement changes the destination and requires switching service to it, but does not introduce another initialization/recovery interface.

Select an observed case below the pseudocode. The presentation follows the application contract in README.md. Observation or integrity errors stop startup rather than assuming empty state.

Interactive pseudocode for the Bartl startup decision
until serving():
    local = observe_local_state()
    if local.exists:
        engine version vs local.version:
            equal:    serving()
            engine >: migrate(local)
            engine <: abort("downgrade")
    else:
        backup = observe_backup()
        if backup.valid: restore(backup)
        else:            init()

Select an observed state to highlight the resulting branch.

Technical contract

Separate release, state and configuration. Use backups when available.

The shared startup path needs neither a mode selector nor an initialization permission. A backup is queried only without local state.

  1. Versioned release

    An immutable application artifact with a known engine version and the product-specific migration logic that belongs to that release.

  2. Fully declared state

    All mutable data and metadata, including a reliably detectable state version. Undeclared state cannot be backed up or restored dependably.

  3. Optional backup

    The latest fully published and verified backup for this customer and application. No configured backup store, or a store containing no backup, means absence. Lookup and integrity errors stop startup.

  4. Target configuration

    Endpoints and credentials supplied by the target. They are bound at startup and belong neither in the release nor in the backed-up state.

Executable reference

WordPress, MySQL, and Docker Compose as an inspectable example.

bartl-wordpress illustrates the mechanism for one pinned WordPress configuration. Its particular prerequisites do not define the general startup contract. The database and uploads are state. WordPress core, plugins, and themes remain immutable image content.

State
MySQL database and wp-content/uploads
Release
WordPress core, plugins, and themes in the image
Backup
Checksums for every member and .sha256 as the commit marker
Restore
Only to an empty, compatible target with complete inputs
Failure
Abort on missing, incomplete, or contradictory inputs

Quickstart

The prerequisite is a Linux host with Docker and Docker Compose. Without WORDPRESS_PUBLIC_URL, the local reference runs at http://localhost:8080.

git clone https://codeberg.org/bartlapp/bartl-wordpress.git
cd bartl-wordpress
mkdir -p backup-store
docker compose up -d

Publish a backup after WordPress has been initialized:

docker compose exec bartl-init /backup.sh

Repository and runbook on Codeberg

Evidence boundary

The reference demonstrates the mechanism only for this WordPress configuration. It demonstrates neither other applications nor the quality of a target environment or a particular restart time.

Explicit boundary

What startup does and what the complete service still needs.

The startup mechanism does

  • observe local state and versions first, querying backups only without local state
  • select the startup path from those observations
  • verify backups before using them
  • invoke product-specific migration
  • abort on downgrade, inconsistency, or missing prerequisites
  • use the same path for normal startup and restore

Not covered by the startup mechanism

  • provision target infrastructure
  • configure network, DNS, TLS, or identity
  • operate external backup storage
  • create backups or migrations for arbitrary products
  • guarantee availability or restart times
  • coordinate traffic or write authority
  • replace a complete operations or recovery process

Fit

The pattern requires a clean state boundary.

A good fit when

  • mutable state can be named completely and versioned
  • release, state, and target configuration are cleanly separated
  • backup integrity and restore can be checked automatically
  • product-specific migrations can be invoked deterministically

Not a fit when

  • critical state is unknown or spread across uncontrolled locations
  • empty, valid, and damaged state cannot be distinguished
  • release and runtime state cannot be separated
  • the startup mechanism is expected to perform every external operating task

Inspect the mechanism in a running example.

Run the reference, publish a backup, and observe startup on an empty compatible target. The spec describes the narrow contract behind it.