This is the Elm-based Pebble development platform.
elmc/- Elm-to-C compiler, runtime, and conformance tests.ide/- Phoenix LiveView IDE app (Phases 1-3 baseline).packages/elm-pebble/elm-watch/- watch-side Elm package API surface.packages/elm-pebble-companion-core/- companion-side Elm package API surface.shared/- cross-target Elm protocol modules (watch + companion).ide/priv/pebble_app_template/- Pebble app template/shim used by IDE publish builds.
Run the IDE container with persistent storage:
docker compose up -dThis starts elm-pebble-ide on http://localhost:4000/projects
and stores all runtime data in the named volume elm_pebble_ide_data:
- SQLite database (
/var/lib/ide/ide_prod.db) - project workspace files (
/var/lib/ide/workspace_projects) - user settings (
/var/lib/ide/config/settings.jsonin local mode, or/var/lib/ide/users/<id>/settings.jsonper user in public mode) - Pebble SDK state (
/var/lib/ide/.pebble-sdk)
Container image includes required toolchain binaries:
elm(installed globally via npm)pebbleCLI (pebble-tool)gif2apng1.9 (built from SourceForge sources for animated bitmap GIF upload)- Pebble SDK installed on first container start into the persistent volume (
PEBBLE_SDK_VERSION, defaultlatest, currently v4.17) - embedded emulator runtime support (
qemu-pebblefrom the installed SDK,pypkjsfrompebble-tool, QEMU keymap data, and bzip2 for flash images)
On first startup, the container installs the Pebble SDK into the persistent
volume (if missing) and starts the Phoenix server immediately. On later starts,
the entrypoint upgrades the active SDK when PEBBLE_SDK_VERSION=latest and a
newer release is available (for example v4.17 replacing v4.9.169). SDK install
runs in the background by default. To wait for the SDK before serving traffic:
PEBBLE_SDK_BLOCKING_INSTALL=1 docker compose up -dTo pin a specific SDK version at runtime:
PEBBLE_SDK_VERSION=4.9.169 docker compose up -dThe embedded emulator uses these container paths by default:
ELM_PEBBLE_SDK_INSTALL_ROOT=/var/lib/ide/.pebble-sdk/SDKs/currentELM_PEBBLE_QEMU_BIN=/var/lib/ide/.pebble-sdk/SDKs/current/toolchain/bin/qemu-pebbleELM_PEBBLE_PYPKJS_BIN=/opt/pipx/venvs/pebble-tool/bin/pypkjsELM_PEBBLE_QEMU_IMAGE_ROOT=/var/lib/ide/.pebble-sdk/SDKs/current/sdk-core/pebbleELM_PEBBLE_QEMU_DATA_ROOT=/usr/share/qemu
If QEMU flash images are not present in the active SDK, the IDE downloads them
on demand into ELM_PEBBLE_QEMU_IMAGE_ROOT.
The browser WASM emulator runtime is not built automatically by the IDE.
Build it once on a machine with Docker, then copy the assets into the IDE data
volume (/var/lib/ide/wasm_emulator by default):
docker compose run --rm wasm-emulator-builder
docker compose restart elm-pebble-ideOr from a repo checkout:
ELM_PEBBLE_WASM_OUTPUT_DIR=/tmp/wasm-out ./scripts/build_wasm_emulator_runtime.shThe builder downloads QEMU 10.1 source, clones ericmigi/pebble-qemu-wasm,
applies the local control-bridge patch, builds qemu-system-arm.js,
qemu-system-arm.wasm, and qemu-system-arm.worker.js, then copies all
available Pebble SDK QEMU firmware images from the active SDK into per-platform
directories under /var/lib/ide/wasm_emulator/firmware/sdk.
By default the builder uses emery as the legacy single-image fallback. Override
that fallback with:
PEBBLE_WASM_FIRMWARE_PLATFORM=basalt docker compose run --rm wasm-emulator-builderThe IDE serves WASM assets from ELM_PEBBLE_WASM_EMULATOR_ROOT, which defaults
to /var/lib/ide/wasm_emulator in Docker. Firmware binaries and built WASM
artifacts are not committed to the repository.
To skip automatic SDK installation/activation:
INSTALL_PEBBLE_SDK=0 docker compose up -dTo use an external disk path instead of a Docker-managed volume:
cp docker-compose.external-disk.example.yml docker-compose.override.yml
# edit the host path in docker-compose.override.yml
docker compose up -dProduction releases support SQLite (default) or PostgreSQL. The adapter is
selected at runtime via IDE_REPO_ADAPTER or by setting DATABASE_URL (which
implies Postgres). Both adapters are included in the same release image.
cp docker-compose.postgres.example.yml docker-compose.override.yml
# set POSTGRES_PASSWORD, SECRET_KEY_BASE, PHX_HOST, etc.
docker compose up -d --buildOr run a Postgres-backed container manually:
docker build -t elm-pebble-ide .
docker run --env DATABASE_URL=postgres://user:pass@host:5432/ide_prod elm-pebble-ideEnvironment variables:
| Variable | SQLite (default) | PostgreSQL |
|---|---|---|
IDE_REPO_ADAPTER |
sqlite (optional) |
postgres |
DATABASE_PATH |
SQLite file path | not used |
DATABASE_URL |
must be unset | required (also selects Postgres when adapter unset) |
DATABASE_SSL |
off (plain TCP) | true when the server requires TLS |
POOL_SIZE |
connection pool (default 10) |
same |
Project source files still live on disk under PROJECTS_ROOT; only users, login
tokens, and project metadata move to Postgres.
The image build pipeline is defined in .github/workflows/docker-image.yml.
On pushes, GitHub Actions publishes images to GitHub Container Registry as
ghcr.io/<owner>/<repo>.
To run a published image directly:
ELM_PEBBLE_IMAGE=ghcr.io/synalysis/elm-pebble:latest docker compose up -dThe target architecture and staged execution plan for the IDE are captured in:
docs/IDE_ROADMAP.md