Auto-generated UI from type hints. Shareable link. Built-in storage. Self-hosted with Docker.
docker run \
-p 3000:3000 \
-p 3001:3001 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /tmp/runit-workspaces:/tmp/runit-workspaces \
-v /tmp/runit-storage:/tmp/runit-storage \
-e NEXT_PUBLIC_API_URL=http://localhost:3001 \
-e MASTER_ENCRYPTION_KEY="$(openssl rand -base64 32)" \
-e GEMINI_API_KEY="your-key-here" \
ghcr.io/buildingopen/runitOpen localhost:3000. The API runs on localhost:3001. Paste this:
from runit import app
@app.action
def greet(name: str) -> dict:
return {"message": f"Hello, {name}!"}Hit "Go Live." Share the link. That's it.
git clone https://github.com/buildingopen/runit
cd runit
npm run setup:local
npm installSelf-host path:
docker-compose up --buildManual local dev path:
# Terminal 1
cd services/control-plane && npm run dev
# Terminal 2
npm run dev:localOpen http://localhost:3000. The local API should answer on http://localhost:3001/health.
- Greeting app: start with the snippet in Quick Start
- Visit counter with memory: examples/visit-counter/main.py
- Invoice generator: examples/invoice-generator/main.py
See all examples in examples/README.md.
- You write a Python function with type hints
- RunIt extracts the schema (OpenAPI)
- RunIt generates a web form from the schema
- RunIt runs the function in a Docker sandbox
- Anyone with the link can use it
Got code from ChatGPT with no functions or type hints? RunIt can handle it.
import requests
city = "Berlin"
response = requests.get(f"https://wttr.in/{city}?format=j1")
data = response.json()
print(f"Temperature in {city}: {data['current_condition'][0]['temp_C']}°C")With GEMINI_API_KEY set, RunIt uses AI to:
- Detect
cityas a form input with "Berlin" as the default - Identify
requestsas a dependency - Wrap the script in a callable function
- Name the app "Weather Checker"
Without the key, raw scripts still deploy and run, but hardcoded values won't become form inputs. Add type hints to your functions for the same effect without AI:
def run(city: str = "Berlin") -> dict:
...Set up: add GEMINI_API_KEY to your .env file. Get a free key.
from runit import app, remember
@app.action
def count_visits(name: str) -> dict:
visits = (remember("visits") or 0) + 1
remember("visits", visits)
return {"message": f"Hello {name}! Visit #{visits}"}No database setup. Built-in key-value storage.
| Example | What it does |
|---|---|
| Invoice Generator | Create invoices with automatic tax calculation |
| Text Analyzer | Count words, find common phrases, detect sentiment |
| Unit Converter | Convert temperatures and distances between units |
| Visit Counter | Greet visitors and track counts with remember() |
git clone https://github.com/buildingopen/runit
cd runit
npm run setup:local
docker-compose up --buildsetup:local generates the encryption key and .env file. That starts the control plane API on localhost:3001 with SQLite and Docker sandboxing.
For the all-in-one web + API container, use the Quick Start command above.
- Web UI:
http://localhost:3000 - Control plane API:
http://localhost:3001 - Health check:
http://localhost:3001/health
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
MASTER_ENCRYPTION_KEY |
Yes | 32-byte base64 key for secrets encryption | |
COMPUTE_BACKEND |
No | docker |
docker for self-hosted |
PORT |
No | 3001 |
Server port |
API_KEY |
No | Bearer token to protect API | |
RUNNER_IMAGE |
No | runit-runner:latest |
Docker image for code execution |
RUNNER_MEMORY |
No | 512m |
Memory limit per container |
RUNNER_CPUS |
No | 1 |
CPU limit per container |
RUNNER_NETWORK |
No | none |
Network mode (none for isolation) |
GEMINI_API_KEY |
No | Enables AI smart ingest for raw scripts (see below) |
See .env.example for the full list.
Python SDK
from runit import app, remember, forget, storage
# Mark functions as actions
@app.action
def my_func(x: int) -> dict:
return {"result": x * 2}
# Custom action name
@app.action(name="custom_name")
def another_func(y: str) -> dict:
return {"greeting": f"Hello, {y}!"}
# Full storage API
storage.set("config", {"theme": "dark"})
data = storage.get("config") # {"theme": "dark"}
storage.get("missing", default=0) # 0
storage.list() # ["config"]
storage.delete("config")CLI
npm install -g @buildingopen/cli
# Deploy a Python file
runit deploy my-app.py --name "My App"
# List your apps
runit list
# View logs
runit logs
# Check local setup
runit doctor
# Manage storage
runit storage list
runit storage get <key>
runit storage set <key> <value>
# Share your app
runit share create <endpoint_id>MCP Server (for AI agents)
npm install -g @buildingopen/mcp-serverGives AI agents (Claude, Cursor, etc.) tools to deploy code, run actions, and manage storage.
API Reference
All routes are under /v1/. Full OpenAPI spec at /v1/openapi.json.
Human-friendly API docs landing: /docs.
Apps: GET /v1/projects, POST /v1/projects, GET /v1/projects/:id, DELETE /v1/projects/:id
Deploy: POST /v1/projects/:id/deploy, GET /v1/projects/:id/deploy/status
Runs: POST /v1/runs, GET /v1/runs/:id
Secrets: POST /v1/projects/:id/secrets, GET /v1/projects/:id/secrets
Storage: GET /v1/projects/:id/storage, PUT /v1/projects/:id/storage/:key, GET /v1/projects/:id/storage/:key
Architecture
Function (type hints) -> OpenAPI Schema -> Auto-generated Form -> Shareable Link
|
Docker Sandbox
|
SQLite
runit/
+-- apps/web/ # Next.js web app (paste, deploy, run, share)
+-- packages/
| +-- cli/ # CLI: runit deploy, runit list, ...
| +-- client/ # TypeScript API client
| +-- mcp-server/ # MCP tools for AI agents
| +-- openapi-form/ # Auto-generates web forms from functions
| +-- shared/ # TypeScript types and contracts
| +-- ui/ # Shared React components
+-- services/
| +-- control-plane/ # Hono.js API server
| +-- runner/ # Python execution runtime + SDK
Development
npm install
npm run build # Build all packages
npm test # Run all tests- Turn Python functions into usable apps without building frontend forms by hand
- Keep execution isolated with Docker sandboxing
- Keep state simple with built-in
remember()storage - Share links instantly for demos, internal tools, and experiments
RunIt works with standard API and browser tooling:
- OpenAPI contract at
GET /v1/openapi.json - Docs landing at
GET /docs - Browser automation friendly routes (
/new,/p/:id,/s/:id) - CLI + API parity for scripting and CI
Common pairings:
- Postman/Insomnia for API exploration
- Playwright/browser-use style flows for UI automation
- cURL scripts for smoke checks and CI gates
See docs/INTEGRATIONS.md for concrete examples.
- 2-minute onboarding guide: docs/LAUNCH_FIRST_APP.md
- Distribution copy for launch channels: docs/LAUNCH_KIT.md
- PRR scorecard and go/no-go checks: docs/PRR_SCORECARD.md
See CONTRIBUTING.md for guidelines.
MIT. See LICENSE.