02 — CLI Interface
The bext CLI is the primary interface for developers. It replaces the current bext-server [subcommand] pattern with a proper CLI that handles running, building, deploying, and managing applications.
Current State
bext-server # Start HTTP server
bext-server build # Run build script
bext-server validate # Validate config
bext-server scan # Print route table
bext-server version # Print version
bext-server help # Usage
Target State
# Core commands
bext run [dir] # Run an app (auto-detect framework, serve it)
bext dev [dir] # Dev mode (watch + HMR + source maps)
bext build [dir] # Build for production
bext start [dir] # Start built app in production mode
# App management
bext apps list # List registered apps
bext apps add <name> # Register an app
bext apps remove <name> # Unregister an app
bext apps info <name> # Show app details (routes, cache stats, deploy history)
# Deployment
bext deploy <dir> --app <name> # Deploy app (build + swap)
bext rollback <name> # Rollback to previous version
bext promote <name> # Promote canary to 100%
# Multi-app platform
bext serve # Start the platform (serves all registered apps)
bext serve --config platform.toml
# Cache management
bext cache stats # Cache hit rates, sizes, per-app breakdown
bext cache purge --app <name> # Purge app cache
bext cache purge --tag <tag> # Purge by tag
bext cache purge --all # Purge everything
bext cache warm <url-list> # Pre-warm cache from URL list
# Plugin management
bext plugins list # List installed plugins
bext plugins install <path.wasm> # Install WASM plugin
bext plugins remove <name> # Remove plugin
bext plugins inspect <path.wasm> # Show manifest, permissions, size
# Inspection
bext routes [dir] # Print route table (current scan command)
bext config validate [file] # Validate config (current validate command)
bext health # Platform health check
bext metrics # Current metrics snapshot
bext ps # Running apps, isolate count, memory usage
# Flow engine
bext flows list # List active flows
bext flows inspect <id> # Show flow steps + status
bext flows cancel <id> # Cancel a running flow
bext flows gc # Force garbage collection
Implementation Tasks
CLI-1: CLI Framework Setup
Replace the hand-rolled arg parsing in main.rs with clap.
File: bext-server/src/cli.rs
use clap::{Parser, Subcommand};
#[derive(Parser)]
#[command(name = "bext", version, about = "Application deployment platform")]
pub struct Cli {
#[command(subcommand)]
pub command: Option,
/// Config file path
#[arg(short, long, default_value = "bext.config.toml")]
pub config: String,
/// Log level
#[arg(long, default_value = "info")]
pub log_level: String,
}
#[derive(Subcommand)]
pub enum Command {
/// Run an app (auto-detect framework)
Run {
/// App directory (default: current dir)
#[arg(default_value = ".")]
dir: String,
/// Listen address
#[arg(short, long, default_value = "0.0.0.0:3000")]
listen: String,
/// Number of workers
#[arg(short, long)]
workers: Option<usize>,
},
/// Dev mode with watch + hot reload
Dev {
#[arg(default_value = ".")]
dir: String,
#[arg(short, long, default_value = "0.0.0.0:3000")]
listen: String,
},
/// Build for production
Build {
#[arg(default_value = ".")]
dir: String,
/// Output directory
#[arg(short, long, default_value = "dist")]
output: String,
},
/// Start the multi-app platform
Serve {
/// Platform config
#[arg(short, long, default_value = "platform.toml")]
config: String,
},
/// Deploy an app
Deploy {
dir: String,
#[arg(long)]
app: String,
},
/// App management
Apps {
#[command(subcommand)]
command: AppsCommand,
},
/// Cache management
Cache {
#[command(subcommand)]
command: CacheCommand,
},
/// Plugin management
Plugins {
#[command(subcommand)]
command: PluginsCommand,
},
/// Print route table
Routes {
#[arg(default_value = ".")]
dir: String,
},
/// Validate config
Config {
#[command(subcommand)]
command: ConfigCommand,
},
/// Platform health check
Health,
/// Current metrics
Metrics,
/// Running processes
Ps,
/// Flow engine management
Flows {
#[command(subcommand)]
command: FlowsCommand,
},
}
Tasks:
- Add
clapdependency tobext-server/Cargo.toml - Create
cli.rswith full command tree - Migrate existing subcommands (build, validate, scan, version)
- Wire up
main.rsto use clap dispatch - Add shell completions generation (
clap_complete) - Add
--jsonflag to all inspection commands for machine-readable output - Colored terminal output with
owo-colorsorcolored - Progress bars for long operations with
indicatif
CLI-2: bext run Command
The primary command. Takes a directory, detects the framework, and serves it.
Flow:
bext run ./my-app
1. detect framework (RT-1)
2. load bext.config.toml if present, else generate defaults
3. run transforms (using detected profile)
4. if needs bundle: run build (Bun/esbuild)
5. create isolate with SSR bundle
6. start HTTP server
7. serve requests: static → ISR cache → isolate render
Output:
bext v0.5.0
Framework: Next.js (app router)
Directory: ./my-app
Routes: 42 pages, 8 API routes
Listen: http://localhost:3000
ready in 847ms
Tasks:
- Implement
runcommand handler - Call framework detection (RT-1)
- Generate default config for detected framework
- Trigger build if needed (delegate to Bun or esbuild)
- Create isolate and start serving
- Pretty startup banner with timing
- Graceful shutdown on SIGINT/SIGTERM
-
--portshorthand for--listen -
--opento open browser after start
CLI-3: bext dev Command
Development mode with file watching, hot reload, and source maps.
Behavior:
- Watch source files for changes
- On change: re-run affected transforms, rebuild SSR bundle, hot-reload isolate
- WebSocket HMR connection to browser (send reload signal)
- Source maps enabled for stack traces
- Relaxed security (no rate limiting, CORS allow-all, auth bypass on localhost)
Tasks:
- Implement
devcommand handler - File watcher (notify crate, already used in bundler.rs)
- Incremental transform (only re-transform changed files)
- WebSocket HMR endpoint (
/bext-hmr) - Client-side HMR script injection (auto-inject
<script>tag) - Source map generation in transforms
- Dev-mode defaults (no rate limit, CORS *, auth bypass)
- Error overlay (render build/runtime errors as HTML page)
-
--no-hmrflag to disable HMR (useful for debugging)
CLI-4: bext serve (Multi-App Platform)
Starts the platform server that routes to multiple apps based on hostname.
Config: platform.toml
[platform]
listen = "0.0.0.0:443"
tls_cert = "/etc/letsencrypt/live/example.com/fullchain.pem"
tls_key = "/etc/letsencrypt/live/example.com/privkey.pem"
[apps.marketing]
source = "./apps/marketing"
domains = ["example.com", "www.example.com"]
runtime = "ssr"
cache.default_ttl = "1h"
[apps.dashboard]
source = "./apps/dashboard"
domains = ["app.example.com"]
runtime = "ssr"
auth.required = true
[apps.api]
source = "./apps/api"
domains = ["api.example.com"]
runtime = "js"
rate_limit.rpm = 1000
[apps.docs]
source = "./apps/docs"
domains = ["docs.example.com"]
runtime = "static"
Tasks:
- Parse
platform.tomlconfig format - Create
PlatformServerthat manages multipleAppInstances - Hostname → app routing (extends tenant cache)
- Per-app isolates with independent caches
- Per-app rate limiting
- TLS termination (rustls)
- Per-app health checks
-
bext apps list/add/removecommands to manage apps - Live reload of platform config (add/remove apps without restart)
CLI-5: Inspection Commands
Commands for inspecting the running platform state.
bext ps output:
APP STATUS WORKERS MEMORY REQ/S CACHE HIT UPTIME
marketing running 4 48MB 1,240 94.2% 2d 14h
dashboard running 2 32MB 420 87.6% 2d 14h
api running 1 16MB 3,100 N/A 2d 14h
docs static - - 180 99.8% 2d 14h
bext cache stats output:
APP ENTRIES HIT RATE MEM USED STALE/SWR TAGS
marketing 2,481 94.2% 148MB 12 product,blog,page
dashboard 892 87.6% 64MB 3 user,report
api - - - - -
docs 1,200 99.8% 24MB 0 -
TOTAL 4,573 93.1% 236MB 15
Tasks:
-
bext ps— query running apps, format table -
bext health— check all subsystems (DB, cache, isolates, plugins) -
bext metrics— JSON dump of all metrics -
bext cache stats— per-app cache breakdown -
bext routes— migrate existingscancommand -
bext config validate— migrate existingvalidatecommand - All commands support
--jsonfor machine-readable output
Binary Naming
Rename bext-server binary to bext:
# bins/bext/Cargo.toml (rename from bext-server)
[[bin]]
name = "bext"
path = "src/main.rs"
The old bext-server behavior (bext-server with no args starts the server) maps to bext serve or bext run ..
Tasks:
- Rename
bext-servercrate tobext(or addbextas a bin alias) - Update all scripts and docs
- Backward compat:
bextwith no args shows help,bext run .starts server
Shell Completions
Generate completions for bash, zsh, fish, PowerShell:
bext completions bash > /etc/bash_completion.d/bext
bext completions zsh > ~/.zfunc/_bext
bext completions fish > ~/.config/fish/completions/bext.fish
Tasks:
- Add
completionssubcommand usingclap_complete - Auto-install completions on
bext install-completions