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.
Live demo: https://cloudpebble-og-dev.exe.xyz (test with testuser/testpass123)
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 accountFor HTTPS behind a reverse proxy:
export PUBLIC_URL=https://your-domain.com
export EXPECT_SSL=yes
docker compose build
docker compose up -dOptional services (emulator, code completion):
docker compose --profile emulator --profile codecomplete up -dBrowser → 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)
| 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 |
| 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.
- User clicks "Run" in the browser
- Django creates a
BuildResultand queues a Celery task - Celery assembles source files from S3, runs
pebble build - Compiled
.pbwis uploaded to S3 - Browser polls for build status and shows results
- Browser POSTs to
/qemu/launchvia nginx - QEMU controller spawns a QEMU ARM emulator + pypkjs (JS runtime)
- Browser connects via WebSocket for VNC display
- Emulators auto-kill after 5 minutes without a ping
Platforms: aplite (Pebble), basalt (Time), chalk (Time Round), diorite (Pebble 2), emery (Time 2)
- Browser POSTs to
/ycmd/spinupto initialize a session - Proxy spawns a ycmd instance per target platform with Pebble SDK headers
- Browser connects via WebSocket for real-time completions, errors, and go-to-definition
# 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')
"ide/api/— REST endpoints returning JSON (project CRUD, source files, resources, builds, git, emulator, autocomplete)ide/models/— Database models: Project, SourceFile, ResourceFile, BuildResult, UserSettingside/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/Rebble OAuth2)
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) |
The nginx container listens on port 8080. Point your reverse proxy (Caddy, Traefik, etc.) at it for TLS termination.
For production at scale, split stateless services onto a PaaS and run the emulator on dedicated hardware:
Browser ──→ Railway
├── Web (Django) ──→ Supabase (Postgres + Auth)
│ ──→ Upstash (Redis)
│ ──→ Cloudflare R2 (object storage)
├── Celery worker ──→ same backends
└── ycmd proxy
Browser ──→ Hetzner (direct WebSocket for VNC)
└── QEMU controller (Docker + nginx + TLS)
QEMU runs on dedicated hardware because ARM emulation needs ~400MB RAM per instance and long-lived WebSocket connections — making it 3-10x cheaper on a dedicated server vs PaaS.
| Service | Provider | Spec | ~Monthly Cost |
|---|---|---|---|
| Web (Django) | Railway | ~1 vCPU, 1GB | $30 |
| Celery worker | Railway | ~2 vCPU, 2GB | $60 |
| ycmd proxy | Railway | ~0.5 vCPU, 512MB | $15 |
| QEMU controller | Hetzner AX42 | 8C/16T, 64GB DDR5 | $50 |
| PostgreSQL + Auth | Supabase Pro | 8GB DB, 100K MAU | $25 |
| Redis | Upstash | Pay-as-you-go | $3 |
| Object storage | Cloudflare R2 | 500GB, zero egress | $10 |
| Total | ~$200/mo |
Capacity: ~1,000 developers doing 20 builds/month + 5 hrs emulator/month. The Hetzner server handles 150+ concurrent emulators.
Set QEMU_URLS to the Hetzner server's public HTTPS endpoint. The browser connects directly to Hetzner for VNC — no traffic proxied through Railway.
- 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
| Limitation | Notes |
|---|---|
| No Pebble SSO | Pebble's auth servers are gone; use local accounts |
| No phone installs | Requires SSO token; use emulator instead |
| Code completion | WIP — container builds but not yet functional end-to-end |
- Originally written by Katharine Berry, supported by Pebble Technology
- Community revival at Rebble
- Docker Compose setup by iSevenDays
- 2026 modernization by Eric Migicovsky
MIT — see LICENSE.