SkillAgentSearch skills...

Cacao

🍫 Cacao is a reactive Python web framework for building real-time apps with a decorator-based API, component state management, JSON UIs, and WebSocket-powered updates. Ideal for dashboards, internal tools, and hybrid apps (web & desktop).

Install / Use

/learn @cacao-research/Cacao
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

<div align="center">

image

Cacao

High-performance reactive web framework for Python.

Build dashboards, internal tools, and data apps with a simple API β€” real WebSocket reactivity, not full-page reruns.

PyPI Version Downloads Python License CI GitHub Pages

React WebSocket Starlette GitHub Stars

<br>

Features Β· Quick Start Β· Examples Β· Components Β· Architecture Β· Static Builds Β· Contributing

</div>

v2.0 β€” Complete rewrite with signal-based reactivity, session-scoped state, plugin hooks, and a Streamlit-like API that doesn't re-run your entire script.

Quick Start

pip install cacao
import cacao as c

c.title("Hello, Cacao!")
c.text("Welcome to the simplest Python web framework")
cacao run app.py

That's it β€” 3 lines of Python and you have a live web app with hot reload.


Why Cacao?

| Feature | Cacao | Streamlit | |---------|-------|-----------| | Reactivity | Signal-based (only changed values update) | Full script re-run on every interaction | | State | Session-scoped by design | st.session_state bolt-on | | Updates | WebSocket streaming (instant) | HTTP polling (laggy) | | Multi-user | Isolated sessions built-in | Shared state issues | | API | Context managers + decorators | Magic globals | | Static export | cacao build β€” no server needed | Not supported |


Features

Reactive Signals

count = c.signal(0, name="count")

@c.on("increment")
async def increment(session, event):
    count.set(session, count.get(session) + 1)

Signals are the core of Cacao. When a value changes, only the affected components update β€” no full-page reruns, no diffing your entire tree.

60+ Built-in Components

Layouts, forms, charts, display elements, navigation β€” everything you need out of the box.

Multi-Page Apps

with c.page("/"):
    c.title("Home")

with c.page("/settings"):
    c.title("Settings")

Hash-based routing works both in server mode and static builds.

Static Builds

cacao build app.py

Export your app to a static site (HTML + JS + CSS) that runs entirely in the browser. Deploy to GitHub Pages, Netlify, or any static host β€” no Python server required.

Plugin Hooks & Auth

Extensible architecture with plugin registration, authentication hooks, and notification toasts.

Dark & Light Themes

c.config(theme="dark")  # or "light"

Examples

Interactive Counter

import cacao as c

c.config(title="Counter")
count = c.signal(0, name="count")

@c.on("increment")
async def increment(session, event):
    count.set(session, count.get(session) + 1)

@c.on("decrement")
async def decrement(session, event):
    count.set(session, count.get(session) - 1)

c.title("Counter")

with c.card():
    c.metric("Count", count)
    with c.row():
        c.button("-", on_click="decrement", variant="secondary")
        c.button("+", on_click="increment")

Dashboard with Charts

import cacao as c

c.config(title="Sales Dashboard", theme="dark")
sales = c.sample_sales_data()

c.title("Sales Dashboard")

with c.row():
    c.metric("Revenue", "$45,231", trend="+20.1%", trend_direction="up")
    c.metric("Orders", "1,247", trend="+12.5%", trend_direction="up")
    c.metric("Customers", "842", trend="+5.3%", trend_direction="up")

with c.row():
    with c.col(span=8):
        with c.card("Revenue Trend"):
            c.line(sales, x="date", y="revenue", area=True)
    with c.col(span=4):
        with c.card("By Category"):
            c.pie(sales[:5], values="revenue", names="category", donut=True)

with c.card("Recent Transactions"):
    c.table(sales[:10], columns=["date", "category", "revenue", "orders"])

More examples in the examples/ directory:

| Example | Description | |---------|-------------| | simple/hello.py | Minimal hello world | | simple/counter.py | Interactive counter with signals | | simple/metrics.py | KPI dashboard | | simple/dashboard.py | Full dashboard with charts | | chat/app.py | Chat application | | todo/server.py | Todo list app | | analytics_dashboard/ | Analytics dashboard |


Components

Layout

| Component | Description | |-----------|-------------| | row() | Horizontal flex layout | | col(span=N) | Column with 12-grid span | | grid() | CSS grid layout | | container() | Centered container | | stack() | Vertical stack | | split() | Side-by-side split | | hero() | Hero section | | card() | Card container | | tabs() / tab() | Tabbed content | | accordion() | Collapsible sections | | modal() | Modal dialog | | panel() | Sliding panel | | app_shell() | Full app layout with sidebar |

Display

| Component | Description | |-----------|-------------| | title() / text() | Typography | | markdown() | Markdown with optional TOC | | code() | Syntax-highlighted code | | metric() | KPI metric with trend | | table() | Data table | | json_view() | Interactive JSON viewer | | badge() / alert() | Status indicators | | progress() | Progress bar | | image() / video() | Media | | timeline() | Timeline display | | diff() | Side-by-side diff viewer | | breadcrumb() | Navigation breadcrumb |

Form

| Component | Description | |-----------|-------------| | button() | Button with variants | | input_field() | Text input | | textarea() | Multi-line input | | select() | Dropdown select | | checkbox() / switch() | Toggle inputs | | slider() | Range slider | | date_picker() | Date picker | | search_input() | Search with suggestions | | file_upload() | File upload | | chat() | Chat input interface |

Charts

| Component | Description | |-----------|-------------| | line() / area() | Line and area charts | | bar() | Bar chart | | pie() / donut() | Pie and donut charts | | scatter() | Scatter plot | | gauge() | Gauge meter | | heatmap() | Heatmap | | radar() | Radar chart | | funnel() | Funnel chart | | treemap() | Treemap |


Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                         PYTHON SERVER                           β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚ Signals  β”‚  β”‚ Sessions β”‚  β”‚  Events  β”‚  β”‚ WebSocket/HTTPβ”‚  β”‚
β”‚  β”‚ (state)  │──│ (per-    │──│ (typed   │──│    Server     β”‚  β”‚
β”‚  β”‚          β”‚  β”‚  client) β”‚  β”‚  async)  β”‚  β”‚  (Starlette)  β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                     β”‚ JSON
                                                     β”‚ WebSocket
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      REACT CLIENT                  β”‚           β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚  Hooks   β”‚  β”‚Componentsβ”‚  β”‚  Event   β”‚  β”‚   State     β”‚   β”‚
β”‚  β”‚useCacao()│──│ (60+ UI) │──│Dispatcher│──│   Store     β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Data flow:

Python API β†’ JSON definition β†’ WebSocket β†’ React renders
     ↑                                         ↓
Signal.set() ←── Event handler ←── User action

CLI

cacao run app.py                     # Run with hot reload
cacao run app.py --port 3000         # Custom port
cacao run app.py --no-reload         # Disable hot reload
cacao create my-dashboard            # Scaffold a new project
cacao build app.py                   # Build static site
cacao build app.py --base-path /repo # For GitHub Pages subdirectory

Static Builds

Cacao generates static sites that run entirely in the browser β€” no Python server required.

cacao build app.py

Output:

dist/
β”œβ”€β”€ index.html    # Your app
β”œβ”€β”€ cacao.js      # Runtime + built-in handlers
└── cacao.css     # Styles

Built-in client-side handlers for common operations:

  • Encoders β€” Base64, URL, HTML entities, JWT decode
  • Generators β€” UUID, passwords, Lorem Ipsum
  • Converters β€” JSON/YAML, case conversion, number bases
  • Text β€” Statistics, regex t

Related Skills

View on GitHub
GitHub Stars15
CategoryDevelopment
Updated12d ago
Forks0

Languages

Python

Security Score

80/100

Audited on Mar 25, 2026

No findings