@klugeinteractive/create-kluge-app
v1.4.0
Published
Scaffold a new app for the Kluge Studio OS platform
Readme
create-kluge-app
Scaffold a new app for the Kluge Studio OS platform. Generates a project pre-wired for Kluge Studio: database connection, 0.0.0.0 binding, /health endpoint, idempotent migrations, and Kluge Studio OS SDK integration.
Every app includes both a React/Vite frontend and a backend API — choose your backend language.
Usage
npx create-kluge-app my-app --type=fullstack-node # Vite + Express
npx create-kluge-app my-app --type=fullstack-python # Vite + FastAPI
npx create-kluge-app my-app --type=fullstack-flask # Vite + FlaskOr interactively (no arguments needed):
npx create-kluge-app
# → prompts for name and template typeOptions
| Argument | Description |
|---|---|
| name | App name (positional). Must match /^[a-z][a-z0-9-]*$/ — used as subdomain and Docker container name. |
| --type | Template: fullstack-node, fullstack-python (FastAPI), or fullstack-flask |
Templates
fullstack-node — Vite + Express + PostgreSQL
npx create-kluge-app my-app --type=fullstack-node
cd my-app
cd server && npm install
cd ../client && npm install
cp ../.env.example ../.env # fill in DATABASE_URL
# Terminal 1 — API
cd server && npm run dev # :3000
# Terminal 2 — UI
cd client && npm run dev # :5173 (proxies /api → :3000)Structure:
my-app/
client/ — Vite + React, proxies /api to server
server/ — Express, /health, DB migrations
Dockerfile — multi-stage (node build + node runtime)
.env.exampleWhat's included:
server/src/index.js— Express app,/health, runs migrations on startupserver/src/db/migrate.js— Idempotent migration runner with_migrationstableclient/src/App.jsx—KlugeStudio.setNav(),getUser(),notify()examplesclient/index.html— linkstheme.cssandsdk.jswithdata-dev="true"for local dev
Adding a migration:
// server/src/db/migrate.js
const MIGRATIONS = [
{
name: '001_create_items',
sql: `CREATE TABLE IF NOT EXISTS items ( ... );`,
},
];fullstack-python — Vite + FastAPI + PostgreSQL
npx create-kluge-app my-app --type=fullstack-python
cd my-app
cd client && npm install
cd ../server && python -m venv venv && source venv/bin/activate
pip install -r requirements.txt
cp ../.env.example ../.env # fill in DATABASE_URL
# Terminal 1 — API
uvicorn main:app --reload --port 8000 # :8000
# Terminal 2 — UI
cd client && npm run dev # :5173 (proxies /api → :8000)Structure:
my-app/
client/ — Vite + React, proxies /api to server
server/
main.py — FastAPI app, /health, serves static in prod
database.py — SQLAlchemy engine + session + Base
requirements.txt
Dockerfile — multi-stage (node build + python runtime)
.env.exampleAdding a model:
# server/models.py
from database import Base
from sqlalchemy import Column, Integer, String
class Item(Base):
__tablename__ = "items"
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False)Import in main.py before Base.metadata.create_all():
import models # noqa — registers model with Basefullstack-flask — Vite + Flask + PostgreSQL
npx create-kluge-app my-app --type=fullstack-flask
cd my-app
cd client && npm install
cd ../server && python -m venv venv && source venv/bin/activate
pip install -r requirements.txt
cp ../.env.example ../.env # fill in DATABASE_URL
# Terminal 1 — API
python app.py # Flask on :5000
# Terminal 2 — UI
cd ../client && npm run dev # :5173 (proxies /api → :5000)Structure:
my-app/
client/ — Vite + React, proxies /api to server
server/
app.py — Flask create_app() factory, /health, serves static in prod
database.py — flask-sqlalchemy db instance
requirements.txt
Dockerfile — multi-stage (node build + python runtime)
.env.exampleAdding a model:
# server/models.py
from database import db
class Item(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)In app.py, import inside create_app() before db.create_all():
def create_app():
...
with app.app_context():
import models # noqa
db.create_all()Kluge Studio deploy requirements
Every template is pre-configured for these requirements:
| Requirement | How it's met |
|---|---|
| Binds to 0.0.0.0 | app.listen(PORT, '0.0.0.0') / uvicorn --host 0.0.0.0 |
| /health returns 200 | Included in all templates |
| DATABASE_URL from env | Read from process.env.DATABASE_URL / os.getenv |
| RDS SSL compatibility | sslmode stripped from URL + rejectUnauthorized: false (node) |
| Idempotent startup | Migrations use CREATE TABLE IF NOT EXISTS / SQLAlchemy create_all |
| Auto-detected project type | package.json → node/vite, requirements.txt + fastapi → fastapi |
Kluge Studio OS SDK reference
// Register nav items (flat format) — icon is optional
KlugeHub.setNav([
{ label: 'Home', url: '/', icon: 'home' },
{ label: 'Reports', url: '/reports', icon: 'bar-chart' },
]);
// Register nav items with sections
KlugeHub.setNav([
{ section: 'Main', items: [
{ label: 'Home', url: '/', icon: 'home' },
{ label: 'Reports', url: '/reports', icon: 'bar-chart' },
]},
{ section: 'Account', items: [
{ label: 'Settings', url: '/settings', icon: 'settings' },
{ label: 'Log out', url: '/logout', icon: 'log-out' },
]},
]);
// Handle in-app SPA navigation from the sidebar
KlugeHub.onNavigate((path) => {
router.push(path); // React Router, Vue Router, etc.
});
// Get the logged-in user
const user = KlugeHub.getUser();
// → { id, email, name, role, picture } | null
// Send a notification
KlugeHub.notify({ title: 'Done!', body: 'Export ready.', kind: 'success' });
// kind: 'info' | 'success' | 'error' | 'warning'
// Broadcast a message to all other open apps
KlugeHub.broadcast('data-updated', { table: 'orders' });
// Listen for broadcasts from other apps
KlugeHub.listen('data-updated', (payload) => console.log(payload));
KlugeHub.unlisten('data-updated', handler);
// Badge — show a count bubble on this app's hub icon
KlugeHub.setBadge(5); // pink bubble on the app icon in the hub grid
KlugeHub.clearBadge(); // remove it
// Icons — 62 built-in Lucide SVG icons (no network request)
const icon = KlugeHub.icon('trash', 18); // → SVGElement, size optional (default 16)
button.prepend(icon);
console.log(KlugeHub.icons); // → ['home', 'menu', 'trash', ...]
// Confirm dialog — hub-native modal, keyboard-accessible
const ok = await KlugeHub.confirm('Delete this item?', {
title: 'Are you sure?',
confirmText: 'Delete',
cancelText: 'Cancel',
kind: 'danger', // 'default' | 'danger'
});
if (ok) deleteItem();Kluge Studio OS theme CSS classes
Provided by https://api.studio.klugeinteractive.com/theme.css.
| Class | Description |
|---|---|
| .k-card, .k-card-sm | Glass card container |
| .k-btn | Base button |
| .k-btn-primary | Accent-colored button |
| .k-btn-ghost | Outline button |
| .k-btn-danger | Red destructive button |
| .k-btn-sm | Small button modifier |
| .k-input, .k-textarea, .k-select | Form inputs |
| .k-label | Form label |
| .k-badge | Neutral badge |
| .k-badge-green/yellow/red/blue/accent | Colored badges |
| .k-table | Styled table |
| .k-grid-2, .k-grid-3 | 2/3-column grid |
| .k-stack | Vertical flex stack |
| .k-row | Horizontal flex row |
| .k-muted | Dimmed text |
| .k-accent | Accent-colored text |
| .k-divider | Horizontal rule |
Naming rules
App names must match /^[a-z][a-z0-9-]*$/:
✔ my-app
✔ trading-dashboard
✔ api2
✘ My_App (uppercase, underscore)
✘ 2fast (starts with digit)
✘ my app (space)The name is used as the subdomain (my-app.studio.klugeinteractive.com) and Docker container name.
