The application composition layer for Rust.APIs.workers.CLIs.devices.
Use RustClamp when your application is becoming more than one thing. Start with a tiny Rust program, add only what it needs, and keep Rust's performance, ownership and control.
$ curl -fsSL https://rustclamp.com/install.sh | bash
- 9 packages
- 14 runnable examples
- 152 checks
- 10 measured phases
clamp init hello-clamp
Created RustClamp blank project at hello-clamp
Next: cd hello-clamp && cargo run
cd hello-clamp && clamp run
Compiling rustclamp v0.1.0 (github.com/rustclamp/rustclamp)
Compiling hello-clamp v0.1.0
Finished `dev` profile in 0.72s
Hello from Clamp!
clamp init my-site --web
Created RustClamp web project at my-site
Next: cd my-site && clamp dev
cd my-site && clamp dev
[clamp] installing frontend dependencies: npm install
[clamp] started vite: npx vp build --watch
[clamp] started app: cargo run
[vite] built in 84ms.
[app] Serving on http://127.0.0.1:8080
clamp
╭──────────────────────────────╮
│ Welcome to Clamp │
│ RustClamp tools │
╰──────────────────────────────╯
1. Create a project
2. Check this project
3. Run tests
4. Build this project
5. Run this project
6. Inspect architecture JSON
7. Show command help
0. Exit
Choose an option:
clamp help
Usage:
clamp init <project-name> [--blank|--app|--web|--tui]
clamp <inspect|tree|graph|why|doctor> FILE [MODULE] [--process ID] [--json]
clamp dev
clamp self-update
clamp <check|test|build|run> [Cargo arguments]
Create a blank, app, web or TUI project, run
Procfile.dev, inspect a resolved projection, or
run a Cargo command.
Start small.
Compose what comes next.
Don't take a feature list on trust. Start with Hello Clamp and follow one application as it grows: configuration, HTTP, a worker, scheduled jobs, a device loop. Every step is a runnable example. See the whole learning tree →
Console and TUI tools
Start with a plain Rust program and keep it that way until it needs more. clamp init my-tool --tui generates exactly this; commands contributed by modules come in when the tool grows.
- One closure, run once on the current thread
- Adds 0 B over plain Rust, no dependencies
- CLI commands as typed contributions when you need them
What can I do now?
use std::io::{self, BufRead};
use rustclamp::prelude::*;
fn main() {
Clamp::run(|| {
println!("Clamp TUI. Type a line, or `quit` to exit.");
for line in io::stdin().lock().lines().map_while(Result::ok) {
if line.trim() == "quit" {
break;
}
println!("you said: {line}");
}
});
}Services and daemons
Configuration comes from .env and the environment, and a module opts into only the lifecycle phases it needs: start in dependency order, report readiness, drain, stop. Tokio joins only the process that selects it.
- Real environment variables win over
.env - Opt-in
Initialize,Start,Ready,Drain,Stop - Providers start first and stop last
What can I do now?
use rustclamp::config::Config;
use rustclamp_core::{LifecycleContext, Module, ModuleId, Start, Stop};
struct Mailer {
per_day: u32,
running: bool,
}
impl Module for Mailer {
const ID: ModuleId = ModuleId::new("app.mailer");
}
impl Start for Mailer {
type Error = String;
fn start(&mut self, _: &LifecycleContext) -> Result<(), String> {
self.running = true;
Ok(())
}
}
impl Stop for Mailer {
type Error = String;
fn stop(&mut self, _: &LifecycleContext) -> Result<(), String> {
self.running = false; // drained before this runs
Ok(())
}
}
let config = Config::load();
let mailer = Mailer { per_day: config.get_or("MAIL_PER_DAY", 300), running: false };Web apps and APIs
Routes, views, sessions, CSRF and rate limits from rustclamp::web: standard library only, no async runtime to learn. clamp init my-site --web adds a Vite and Tailwind front end; reach for the Axum-based rustclamp-http when you need Tower.
- Route groups with their own middleware
- Sessions, CSRF and throttling built in
- Unmatched GETs serve files from
public/; errors render as pages - A UUIDv7 reference on every request: in
X-Request-Id, every log line and the error page
What can I do now?
use std::time::Duration;
use rustclamp::prelude::*;
use rustclamp::web::{self, Router, Sessions, csrf, json, redirect, throttle};
fn routes() -> Router {
Router::new()
.view("/", "welcome")
.group(|site| {
site.middleware(Sessions::new(Duration::from_secs(7200)).middleware())
.middleware(csrf())
.post("/contact", |request| {
let name = request.form("name").unwrap_or_default();
if let Some(session) = request.session() {
session.put("flash", &format!("Thanks, {name}!"));
}
redirect("/")
})
})
.group(|api| {
api.middleware(throttle(60, Duration::from_secs(60)))
.get("/api/health", |_| json(r#"{"status":"ok"}"#))
})
}
fn main() {
Clamp::run(|| web::serve(routes()));
}Workers and queues
Handlers are contributed by message name and schema version and run over NATS JetStream. Failures are classified before anything is retried, so a timeout never turns into a duplicate payment.
- Bounded retry, dead-letter, deadlines
- Transactional outbox and durable inbox, tested by killing processes
- Correlated tracing across API and Worker
WorkerService: backpressure, bounded concurrency and a timed drain over your transport
What can I do now?
// The payload is decoded before the handler runs; one that does not decode never reaches it.
let handler = HandlerDeclaration::typed(SUBJECT, 1, |email: EmailPayload, _| async move {
println!("delivered email to {}: {}", email.to, email.subject);
Ok(())
});Scheduled jobs
Jobs are contributed like routes and driven by a Clock you control, so tests move time instead of waiting for it. No cron daemon and no async runtime required.
- Explicit misfire policy: run once or skip
- Stops admitting new runs before active jobs drain
- Process-local overlap suppression
What can I do now?
let catch_up_job = JobDeclaration::new(
"cleanup-expired-sessions",
Duration::from_secs(10),
MisfirePolicy::RunOnce,
|| async {
println!("cleanup operation invoked");
Ok(())
},
);Devices and embedded
Sensors, displays and bus decoders are capabilities and contributions, so a test fixture and a real board are two providers of the same thing. Core can already be used from no_std code; bare-metal Core is the next boundary.
- Bounded input, stale and missing samples reported
- CAN decoders contributed and checked for duplicate IDs
- A
no_std + allocconsumer of Core
#![no_std]
#![forbid(unsafe_code)]
extern crate alloc;
use rustclamp_core::ModuleId;
pub struct Thermometer;
impl rustclamp_core::Module for Thermometer {
const ID: ModuleId = ModuleId::new("example.platform-neutral.thermometer");
}Start where you are.
Don't rewrite.
You do not need a clean slate. Pick the piece you already have, or a small new one at the edge — a CLI, a worker, a scheduled job — and let Clamp earn the rest. If it doesn't help, remove it.
Nothing yet
One command gives you an ordinary Cargo project: your code inside Clamp::run, 0 B over plain Rust.
clamp init hello-clamp
Getting started
A Rust program or CLI
Wrap your existing main in Clamp::run. Nothing else changes until you add a capability.
Clamp::run(|| your_main())
Clamp CLI
An Axum service
Keep Axum: rustclamp-http is built on it. Today routes are declared one path at a time; mounting a whole existing Router is being built.
HttpRoute::new("/users", get(list))
Track it
A worker or a job
A new background worker or scheduled job is a low-risk first Clamp process next to what you already run.
examples/03-email-worker
See the examples
Verify the system.
Binary size added by Pico
0 B
Unused architecture should disappear. Pico against a plain Rust control, same payload, toolchain and flags, paired runs on one machine. A budget to defend, not a universal guarantee.
- 01Facade dependencies0
Zero third-party crates in the facade, Core and Kernel, enforced by boundary checks.
- 02Unchanged rebuild+1.67 ms
Median delta over plain Rust.
- 03Clean build+36.78 ms
Median delta, about 16%. The initial cost budget.
- 04Process wall time+0.054 ms
Median delta; sample ranges overlap almost entirely.
- 05Console-only Users build8
Resolved packages. The same domain with HTTP resolves 62, with PostgreSQL 160: Axum, SQLx and Tokio stay out until selected.
Application composition
layer for Rust.
It coordinates how the pieces fit together and lets specialised libraries keep doing what they do best. Integrate before reinventing.
Convenience
without surrendering Rust.
No macros you cannot read, no global registry, no runtime you did not ask for. Missing or ambiguous wiring fails with a named error before anything runs, and you can drop to plain Rust for any part.
Questions,
answered plainly.
Short answers here. The numbers, sources and trade-offs live in the docs.
01What is RustClamp?
The application composition layer for Rust. It sits above the crates you already use, such as Axum, SQLx and Tokio, and composes them. You start with an application and add only the capabilities it needs: a CLI, HTTP, storage, workers, scheduled jobs, devices. The architecture can grow without RustClamp becoming the center of your application.
02Why not just use Axum?
You might not need to replace it. Axum solves HTTP extremely well, and rustclamp-http is built on Axum and Tower. Clamp works one level above that choice: it composes the application in which HTTP is one capability next to storage, workers and jobs.
03Why not plain Rust?
You can build all of it in plain Rust. Clamp is not trying to remove Rust; it removes repeated application wiring. For a single closure it is plain Rust — Pico measures within noise of it. The difference appears as an app grows, when modules declare what they require and Clamp checks and wires it once, before anything runs.
04Can I use it in an existing project?
Yes, at the edge first: wrap a main, or add a new worker, job or CLI next to what you run. Mounting a whole existing Axum Router is in progress. If a pilot does not help, remove it — an adoption path needs an exit path.
05What can I build with it?
Start with Hello Clamp, then add one thing: configuration, HTTP, a worker, scheduled jobs, a device loop. The learning path above is the honest answer — each step is a runnable example, not a promise.
06Why should I trust something this new?
You should not, because a homepage says so. Try it on something small with clear success criteria and an easy rollback: measure runtime, memory, compile time, wiring and how hard it is to remove. The source is public and every claim on this page links to a test or a measurement.
07Is it ready for production?
No. RustClamp is experimental: APIs can still change before 1.0 and packages are not on crates.io. Build prototypes and internal tools with it today; the roadmap shows what stands between here and 1.0.
08Can I add it with cargo add?
Not yet. Until crate names are published, clamp init writes the Git dependency for you, so a new project builds straight from the public repository. Getting started has the commands.
09Is RustClamp an official Rust project?
No. It is built for Rust, independent of the Rust project and not endorsed by it.
Start in three commands.
Bare minimum or a web page.
-
1
Install RustClamp
Linux or macOS. Installs Rust if it is missing, downloads the prebuilt, checksum-verified
clampand puts it on yourPATH.$ curl -fsSL https://rustclamp.com/install.sh | bash -
2
Create and run
Pick a starting point. Both are ordinary Cargo projects you can open, read and change.
clamp init hello-clamp Created RustClamp blank project at hello-clamp cd hello-clamp && clamp run Hello from Clamp!One file,
src/main.rs: your code insideClamp::run. 0 B over plain Rust.clamp init my-site --web Created RustClamp web project at my-site cd my-site && clamp dev [vite] built · [app] cargo run [app] Serving on http://127.0.0.1:8080Routes in
app/routes/, pages inapp/resources/views, Vite and Tailwind rebuilding on save. -
3
Grow it
Add routes, sessions, jobs or a worker when you need them, and ask
clamp inspect,whyordoctorwhat your app is made of.