Skip to content

coredevices/cloudpebble

Repository files navigation

CloudPebble

A web-based IDE for developing Pebble smartwatch applications. Write C or JavaScript, compile, and test on an in-browser emulator — all from the browser.

Try it out at https://cloudpebble.repebble.com

Self-hosting instructions

git clone https://github.com/coredevices/cloudpebble.git
cd cloudpebble
export PUBLIC_URL=http://localhost:8080
docker compose build
docker compose up
# Open http://localhost:8080 and register an account

For HTTPS behind a reverse proxy:

export PUBLIC_URL=https://your-domain.com
export EXPECT_SSL=yes
docker compose build
docker compose up -d

Optional services (emulator, code completion):

docker compose --profile emulator --profile codecomplete up -d

Host it easily on exe.dev

Use this to bootstrap a brand-new exe.dev VM and get CloudPebble running.

1. Prepare local repo + env

git clone https://github.com/coredevices/cloudpebble.git
cd cloudpebble
cp .env.example .env 2>/dev/null || true

Set .env values for your dev host and secrets (at minimum):

PUBLIC_URL=https://YOURDOMAIN.exe.xyz
EXPECT_SSL=yes
SECRET_KEY=<generate-a-random-secret>
QEMU_SERVER=root@<your-vm-or-qemu-host>
QEMU_SSH_KEY=~/.ssh/id_pub

2. Create/prepare the exe.dev VM

From your machine:

ssh -i ~/.ssh/id_pub YOURDOMAIN.exe.xyz

On the VM:

sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo $VERSION_CODENAME) stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker $USER
mkdir -p ~/cloudpebble
exit

Reconnect after the docker group change:

ssh -i ~/.ssh/id_pub YOURDOMAIN.exe.xyz
docker --version
docker compose version
exit

3. Sync code to VM

From your machine:

rsync -avz --delete --exclude='.git' --exclude='.env' \
  -e "ssh -i ~/.ssh/id_exe" \
  /path/to/cloudpebble/ YOURDOMAIN.exe.xyz:~/cloudpebble/

4. Build and start services

ssh -i ~/.ssh/id_exe YOURDOMAIN.exe.xyz "
  cd ~/cloudpebble &&
  docker compose build &&
  docker compose up -d
"

Optional profiles:

ssh -i ~/.ssh/id_exe YOURDOMAIN.exe.xyz "
  cd ~/cloudpebble &&
  docker compose --profile emulator --profile codecomplete up -d
"

5. Verify

curl -I https://YOURDOMAIN.exe.xyz/
ssh -i ~/.ssh/id_exe YOURDOMAIN.exe.xyz "cd ~/cloudpebble && docker compose ps"
ssh -i ~/.ssh/id_exe YOURDOMAIN.exe.xyz "cd ~/cloudpebble && docker compose logs web --tail 100"

6. Create a test user (optional)

ssh -i ~/.ssh/id_exe YOURDOMAIN.exe.xyz "
  cd ~/cloudpebble &&
  docker compose exec -T web /usr/local/bin/python manage.py shell -c \"
from django.contrib.auth.models import User;
User.objects.create_user('testuser', 'test@example.com', 'testpass123')
\"
"

Architecture

Browser → nginx:8080 → web:80       (Django app)
                     → qemu:80      (emulator, WebSocket/VNC)
                     → ycmd:80      (code completion, WebSocket)
                     → s3:4569      (build artifacts via /s3builds/)

web ←→ postgres      (database)
    ←→ redis         (Celery broker)
    ←→ s3            (source files, builds)

celery ←→ same backends (background build tasks)

Services

Service Image Purpose
nginx nginx:alpine Reverse proxy, WebSocket routing, S3 proxy
web Python 3.11 + Django 4.2 IDE frontend and REST API
celery Same as web Background build tasks
qemu Python 3.11 + QEMU Pebble emulator with VNC (profile: emulator)
ycmd Python 3.11 + ycmd/clang C code completion (profile: codecomplete)
redis redis Celery task broker
postgres postgres:16 Database
s3 kuracloud/fake-s3 S3-compatible object storage

Three Codebases

Directory Service Framework
cloudpebble/ web + celery Django 4.2 + Celery 5.x
cloudpebble-qemu-controller/ qemu Flask + gevent
cloudpebble-ycmd-proxy/ ycmd Flask + gevent

The web and celery containers share the same Docker image. RUN_WEB=yes starts Django; RUN_CELERY=yes starts the Celery worker.

How It Works

Building Apps

  1. User clicks "Run" in the browser
  2. Django creates a BuildResult and queues a Celery task
  3. Celery assembles source files from S3, runs pebble build
  4. Compiled .pbw is uploaded to S3
  5. Browser polls for build status and shows results

Emulator

  1. Browser POSTs to /qemu/launch via nginx
  2. QEMU controller spawns a QEMU ARM emulator + pypkjs (JS runtime)
  3. Browser connects via WebSocket for VNC display
  4. Emulators auto-kill after 5 minutes without a ping

Platforms: aplite (Pebble), basalt (Time), chalk (Time Round), diorite (Pebble 2), emery (Time 2), gabbro (Round 2)

Code Completion

  1. Browser POSTs to /ycmd/spinup to initialize a session
  2. Proxy spawns a ycmd instance per target platform with Pebble SDK headers
  3. Browser connects via WebSocket for real-time completions, errors, and go-to-definition

Development

# Run tests
docker compose exec web python manage.py test

# Run a single test module
docker compose exec web python manage.py test ide.tests.test_compile

# Django shell
docker compose exec web python manage.py shell

# Database migrations
docker compose exec web python manage.py migrate

# Create a user via CLI
docker compose exec web python manage.py shell -c "
from django.contrib.auth.models import User
User.objects.create_user('username', 'email@example.com', 'password')
"

Django App Structure

  • ide/api/ — REST endpoints returning JSON (project CRUD, source files, resources, builds, git, emulator, autocomplete)
  • ide/models/ — Database models: Project, SourceFile, ResourceFile, BuildResult, UserSettings
  • ide/tasks/ — Celery tasks: build.py (compile), git.py (GitHub sync), archive.py (import/export)
  • ide/static/ide/js/ — Frontend JavaScript (jQuery + Backbone + CodeMirror SPA)
  • auth/ — Authentication (local accounts + Pebble OAuth2)

Environment Variables

Key variables set in docker-compose.yml:

Variable Purpose
PUBLIC_URL Public-facing URL (e.g. http://localhost:8080)
EXPECT_SSL Set to yes for HTTPS deployments
AWS_S3_FAKE_S3 fake-s3 endpoint (default: s3:4569)
QEMU_URLS Emulator controller URL
YCM_URLS Code completion proxy URL
GITHUB_ID / GITHUB_SECRET GitHub OAuth (optional)

Tech Stack

  • Backend: Python 3.11, Django 4.2 LTS, Celery 5.x, PostgreSQL 16, Redis
  • Frontend: jQuery 2.1, Backbone, CodeMirror 4.2, noVNC (Bower-managed)
  • Build: pebble-tool 5.0 + SDK 4.9, ARM GCC cross-compiler
  • Emulator: coredevices/qemu (ARM Cortex-M3/M4), pypkjs (JS runtime)
  • Code Completion: ycm-core/ycmd with Clang completer

Known Limitations

Limitation Notes
JSHint/linting Project-level JS lint settings are currently not working end-to-end
Code completion WIP — container builds but not yet functional end-to-end

Credits

  • Originally created by Katharine Berry
  • Later supported by Pebble Technology
  • Community revival at Rebble
  • Docker Compose setup by iSevenDays
  • 2026 modernization by Eric Migicovsky (and Claude Code!)

License

MIT — see LICENSE.

About

CloudPebble - Web-based IDE for Pebble development

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 6