Workpeg SDK
Python SDK and CLI for building, packaging, publishing, and distributing Workpeg Pegs.
Workpeg is a platform for developing portable applications called Pegs. Pegs can be built, packaged, distributed through the PegStore, and integrated into the broader Workpeg ecosystem.
The SDK covers:
- Functions — serverless backend logic, Docker packaging, registry publishing
- CDN — static asset uploads for Peg branding and distribution
- UI Compiler — compile Python UI apps directly to browser JavaScript
Installation
pip install workpeg
Install locally from source:
pip install -e .
Verify:
workpeg --version
CLI
Workpeg uses a namespace-oriented CLI.
workpeg project ...
workpeg function ...
workpeg cdn ...
workpeg ui ...
| Namespace | Purpose |
|---|---|
project |
Scaffold a whole peg — UI, function and manifest |
function |
Create, build, run, and publish Workpeg Functions |
cdn |
Upload public Peg assets to the CDN |
ui |
Scaffold, compile, and serve Python Peg UI apps |
workpeg --help
workpeg project --help
workpeg function --help
workpeg cdn --help
workpeg ui --help
Pegs
A peg is two halves and a manifest that binds them. Scaffold all three:
workpeg project create my-peg
Created my-peg/
workpeg.json namespace: my-peg
ui/ the interface
function/ the backend
The sections below cover each half on its own.
Full reference: docs/projects.md
Functions
Functions are the backend logic of a Peg. They are packaged as Docker images and published to the Workpeg Registry.
Create a project:
workpeg function new hello
hello/
├── app/
│ ├── __init__.py
│ └── main.py
├── Dockerfile
├── requirements.txt
└── README.md
Write a function:
def main(context, payload):
return {
"message": "Hello from Workpeg",
"payload": payload,
}
Run locally (no Docker):
echo '{"context": {}, "payload": {"name": "world"}}' \
| workpeg function runtime
Run with Docker:
workpeg function build
workpeg function run --with docker
Publish:
export WORKPEG_PK=<your-token>
workpeg function submit hello:1.0.0
Full reference: docs/functions.md
CDN
Upload static assets — logos, screenshots, banners — to the Peg CDN.
export WORKPEG_PK=<your-token>
# Single file
workpeg cdn submit logo.svg
# Directory
workpeg cdn submit ./assets
# With explicit CDN path
workpeg cdn submit ./assets --path brand
# Replace existing
workpeg cdn submit ./assets --overwrite
Full reference: docs/cdn.md
UI Compiler
Write Peg UI apps in Python. The SDK compiles them to vanilla JavaScript — no React, no Vue, no Python in the browser.
Python App (single-page or multi-route Router)
↓ AST Parser
Workpeg IR (AppIR | RouterIR)
↓ JS Generator
app.js + workpeg-runtime.js + index.html
Scaffold, compile, and run in one command:
workpeg ui new counter
Creating counter...
counter/main.py
counter/dist/
Serving → http://localhost:8080
Watching → main.py
Stop → Ctrl+C
This creates a ready-to-run Counter app, compiles the Python to JavaScript, and opens a local dev server with live reload. Open http://localhost:8080 in any browser. Edit counter/main.py and save — the browser reloads automatically.
Project structure:
counter/
├── main.py ← Router entry point
├── pages/
│ ├── __init__.py
│ ├── home.py ← HomePage
│ └── counter.py ← CounterPage
└── dist/
├── index.html
├── app.js
└── workpeg-runtime.js
main.py — Router with routes declared:
from workpeg.ui import Router, Route
from pages.home import HomePage
from pages.counter import CounterPage
class Counter(Router):
routes = [
Route("/", HomePage),
Route("/counter", CounterPage),
]
pages/counter.py — counter logic:
from workpeg.ui import App, State, Column, Text, Button, Link
class CounterPage(App):
count = State(0)
def increment(self):
self.count += 1
def build(self):
return Column(
Text(f"Count: {self.count}"),
Button("Increment", on_click=self.increment),
Link("← Home", href="/"),
)
Options for new:
# Custom port
workpeg ui new counter --port 3000
# Scaffold and compile only, no server
workpeg ui new counter --no-serve
# Overwrite an existing project
workpeg ui new counter --force
Multi-page apps with routing:
from workpeg.ui import App, Router, Route, Column, Text, Link
class Home(App):
def build(self):
return Column(Text("Home"), Link("About", href="/about"))
class About(App):
def build(self):
return Column(Text("About"), Link("Home", href="/"))
class MyApp(Router):
routes = [
Route("/", Home),
Route("/about", About),
]
The compiler generates a History-API-based SPA. Clicking Link widgets with internal href values updates the URL and swaps the view — no full-page reload. The back and forward buttons work correctly.
Lists work too. State fields can hold lists, and Python list operations compile to idiomatic JavaScript — literals, slicing, comprehensions, map/filter/reduce, sorted/len/in, mutation (append/pop/sort/…), and for loops. Mutating a state list re-renders automatically:
class Todos(App):
items = State(["Buy milk", "Walk dog"])
def add(self):
self.items.append(f"Task {len(self.items) + 1}") # → push, re-renders
def build(self):
return Column(
Text(f"{len(self.items)} tasks"),
Text(f"sorted: {sorted(self.items)}"),
Text(f"with a: {[t for t in self.items if 'a' in t]}"),
Button("Add", on_click=self.add),
)
See the full Python→JavaScript mapping in the Core concepts docs.
Serve an existing project (with live reload):
# Pass the project directory — main.py is found automatically
workpeg ui serve counter/
# Pin a port
workpeg ui serve counter/ --port 3000
# Explicit file form (same result)
workpeg ui serve counter/main.py
# Serve a pre-built dist directory directly (no recompile)
workpeg ui serve counter/dist/
Compile only, no server:
# Pass the project directory — output goes to counter/dist/ automatically
workpeg ui build counter/
# Custom output directory
workpeg ui build counter/ --out counter/build
# Explicit file form
workpeg ui build counter/main.py
Full reference: docs/getting-started.md and the rest of the Peg UI docs (Core concepts, Widgets, Routing, Data & realtime, Styling, Examples, Reference).
Schema-based UI
For cases where you want to define UI as a data structure (for use with the Workpeg platform renderer rather than the JS compiler), the SDK also ships a schema API:
from workpeg.ui import PegApp, Page, Column, Text, Button
from workpeg.ui import State, Binding, IncrementStateAction
state = State({"counter": 0})
app = PegApp(
title="My Peg",
state=state,
child=Page(
title="Dashboard",
child=Column(
children=[
Text(Binding("counter")),
Button("Increment", action=IncrementStateAction("counter")),
]
),
),
)
print(app.to_schema())
Full reference: docs/schema-ui.md
Documentation
| Document | Contents |
|---|---|
| docs/projects.md | workpeg project create: the peg layout, the manifest, naming rules, working on each half |
| docs/functions.md | Function contract, context, runtime, Docker, publishing |
| docs/cdn.md | CDN uploads, paths, authentication, asset structure |
| docs/getting-started.md | Peg UI: how it works, quick start, CLI, live reload |
| docs/core-concepts.md | App, State, build(), supported Python, lists, reactivity |
| docs/widgets.md | Widget gallery + full per-widget reference |
| docs/routing.md · data-realtime.md · state-components.md · styling.md | Routing, data/realtime, global state, theming |
| docs/reference.md · examples.md | Internals (IR, JS, runtime, errors) + complete examples |
| docs/schema-ui.md | Schema-based UI, PegApp, widgets, bindings, actions |
| docs/architecture.md | Platform overview, pipeline diagrams, design decisions |
Authentication
Both function submit and cdn submit require a Workpeg token:
export WORKPEG_PK=<your-token>
Optional API override:
export WORKPEG_API_BASE=https://repo.workpeg.com
Configuration
Optional workpeg.json in your project root. namespace records the peg the project belongs to — workpeg project create writes it, workpeg function new does not:
{
"namespace": "my-peg",
"function": {
"entrypoint": "app.main:main"
},
"runtime": {
"default": "docker",
"docker": {
"port": 8000
}
},
"build": {
"image": "workpeg-fn-hello"
},
"cdn": {
"assets_path": "assets"
}
}
Roadmap
| Feature | Status |
|---|---|
| Function runtime (local) | Available |
| Function runtime (Docker) | Available |
| Function publish | Available |
| CDN asset uploads | Available |
| UI Compiler (Python → JS) | Available |
workpeg project create (scaffold UI + function + manifest) |
Available |
workpeg ui new (scaffold + serve + live reload) |
Available |
| Schema-based UI | Available |
| Firecracker runtime | Planned |
| Peg packaging workflows | Planned |
| PegStore publishing | Planned |
| Additional widgets | Planned |
| UI widget library | Planned |
| Multi-page routing (History API SPA) | Available |
Method expressions (arithmetic, comparisons, ternary, min/max/abs) |
Available |
Control flow — if / elif / else, for loops |
Available |
Conditional rendering in build() (if/else → different widget trees) |
Available |
Reusable Component classes — props, optional own State (independent per instance), per-instance handlers, callback props |
Available |
Layout widgets — Column/Row, Center/Align (single-child), GridView (multi-child), ListView; custom single-child component slots |
Available |
Async data loading — async/await, http.get/post/put/patch/delete, on_mount, try/except |
Available |
http.* blocked from Workpeg domains (compile + runtime); reach the platform via the namespaced workpeg.* client |
Available |
workpeg.get/post/put/patch/delete — Workpeg-domains-only client; resolves paths against apiBase |
Available |
workpeg.* sends a Namespace whoami header (explicit > serving host > baked peg-namespace meta) |
Available |
Method local variables (step = 5; self.count += step) |
Available |
Console logging (print() → console.log()) |
Available |
| Dev error overlay (compile + runtime errors in the browser) | Available |
Fake cloud (--fake-cloud: local https://<app>.dev.workpeg.com, macOS/Linux/Windows) |
Available |
| Widget categories — layout / display / interactive (Flutter-style) | Available |
ListView with lazy, virtualized ListView.builder |
Available |
Center layout widget |
Available |
Image widget (object-fit, rounding, lazy loading, reactive src) |
Available |
TextInput widget (two-way binding, on_change/on_submit, focus-preserving) |
Available |
List support — literals, slicing, comprehensions, map/filter/reduce, mutation, for loops |
Available |
Reactive state arrays (in-place append/sort/… re-render) |
Available |
Contributing
External contributions follow GitLab Flow — fork, feature branch, merge
request against main at https://gitlab.com/workpeg/workpeg-sdk.
See CONTRIBUTING.md for the workflow, commit message
format, and development setup.
License
MIT — see LICENSE.
Metadata
Release files for workpeg 0.146.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| workpeg-0.146.0.tar.gz | 2.4 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| workpeg-0.146.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 4.9 MB
Release files / workpeg-0.146.0.tar.gz
| Download URL | workpeg-0.146.0.tar.gz |
|---|---|
| Size | 2.4 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9ca6817bc1df1ca3395062afd4c4ac4894aee8be03d1f889875667f90cd944dc
|
|
BLAKE2b-256 checksum How to use checksums |
749cd0238bb278de9a065704812a5409d5b4984d96fd514cd433befdf68e1470
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|
Release files / workpeg-0.146.0-py3-none-any.whl
| Download URL | workpeg-0.146.0-py3-none-any.whl |
|---|---|
| Size | 2.4 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e60977ba712855b4d450c0288d16acfe193561629c5e004408c990d732159823
|
|
BLAKE2b-256 checksum How to use checksums |
58b19d1320132110b68a60934a5a7a35502c689af5e0dfb8acc565f414c5af64
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|