Skip to content

programmism/junior-swarm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

57 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Junior Swarm

Code from your phone. Junior Swarm gives you isolated Docker containers with a full terminal, git integration, and file uploads — accessible from any device via a mobile-first web app.

What it does

  1. You deploy the server on any machine with Docker
  2. Open the web app from your phone or browser
  3. Create a project (optionally clone a GitHub repo, including private ones)
  4. Get a full terminal with colors, cursor support, and resize
  5. Upload files from your device directly into the container

Prerequisites

  • Docker and Docker Compose (for the server)
  • Flutter 3.11+ (only if you want to build the mobile app yourself)

Quick Start

1. Deploy the server

git clone https://github.com/programmism/junior-swarm.git
cd junior-swarm
cp .env.example .env

Edit .env and set a strong API_KEY:

API_KEY=your-secret-key-here
PORT=8080

Start the server:

docker compose up -d

Verify it's running:

curl http://localhost:8080/healthz
# {"status":"ok"}

2. Open the app

The Flutter web app is in the app/ directory. To build and serve it:

cd app
flutter pub get
flutter run -d chrome

Or build for deployment:

flutter build web
# Serve app/build/web with any static file server (nginx, caddy, etc.)

3. Connect

  1. Open the app in your browser
  2. Enter your server URL (e.g. http://your-server:8080)
  3. Enter your API key
  4. Tap Connect

Production Deployment (nginx + HTTPS)

If you already have nginx on the host (e.g. serving multiple services), add Junior Swarm as another site.

1. Build the Flutter web app

cd app
flutter pub get
flutter build web
sudo mkdir -p /var/www/junior-swarm
sudo cp -r build/web/* /var/www/junior-swarm/

2. Configure nginx

Create /etc/nginx/sites-available/junior-swarm:

server {
    listen 80;
    server_name YOUR_DOMAIN;

    root /var/www/junior-swarm;
    index index.html;

    # API requests -> control plane
    location /api/ {
        proxy_pass http://127.0.0.1:8080/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # WebSocket terminal sessions
    location /sessions/ {
        proxy_pass http://127.0.0.1:8080/sessions/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }

    # Flutter web SPA
    location / {
        try_files $uri $uri/ /index.html;
    }
}

Enable and reload:

sudo ln -s /etc/nginx/sites-available/junior-swarm /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

3. Enable HTTPS with Let's Encrypt

Requires a domain pointed at the server — Let's Encrypt cannot issue certs for bare IPs.

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d YOUR_DOMAIN

Certbot will obtain the certificate and update the nginx config to enable SSL and redirect HTTP to HTTPS.

Verify auto-renewal:

sudo certbot renew --dry-run

Usage

Create a project

Tap + and fill in:

  • Project Name — any name you want
  • GitHub Repository URL — optional, will be cloned on start
  • GitHub Token — for private repos, paste a Personal Access Token with repo scope
  • Base Image — defaults to ubuntu:22.04

Start and connect

  1. Tap your project, then tap Start
  2. If you provided a GitHub URL, the repo is auto-cloned into /workspace
  3. Tap Terminal to open a full xterm session (colors, vim, htop — everything works)

Upload files

In the terminal screen, tap the attach icon in the top bar to pick and upload files from your device. Files are uploaded to /uploads inside the container.

Configuration

Variable Default Description
API_KEY (empty = auth disabled) Bearer token for all API requests
PORT 8080 Host port to expose

API Reference

All endpoints except /healthz require Authorization: Bearer <API_KEY> header.

Health check

GET /healthz

Projects

Create project:

curl -X POST http://localhost:8080/projects \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-app",
    "github_url": "https://github.com/user/repo",
    "github_token": "ghp_...",
    "base_image": "ubuntu:22.04"
  }'

The github_url, github_token, and base_image fields are optional.

List projects:

GET /projects

Get / Start / Stop / Delete project:

GET    /projects/{id}
POST   /projects/{id}/start
POST   /projects/{id}/stop
DELETE /projects/{id}

Terminal sessions

Create session (project must be running):

curl -X POST http://localhost:8080/projects/{id}/sessions \
  -H "Authorization: Bearer $API_KEY"

Connect via WebSocket:

ws://localhost:8080/sessions/{id}/terminal?token=<API_KEY>

Messages are JSON:

  • Client sends: {"type": "input", "data": "ls\n"} or {"type": "resize", "cols": 120, "rows": 40}
  • Server sends: {"type": "output", "data": "..."}

File upload

curl -X POST http://localhost:8080/sessions/{id}/upload \
  -H "Authorization: Bearer $API_KEY" \
  -F file=@myfile.txt

Architecture

docker compose up
  +-- socket-proxy   (Docker socket proxy, least-privilege)
  +-- control-plane  (Go API server)
        +-- REST API + Bearer auth middleware
        +-- WebSocket terminal (docker exec + tmux)
        +-- File upload (multipart -> container)
        +-- SQLite (projects + sessions)

Development

cd server
go test ./...
go run ./cmd/devbox

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors