clamp 0.5.0 is out · Phases 0–9 complete

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
Linux or macOS · installs Rust if needed · prebuilt, checksum-verified
  • 9 packages
  • 14 runnable examples
  • 152 checks
  • 10 measured phases
~/projects
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.
0Dependencies
0 BBinary overhead
0Unsafe blocks

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 →

Released

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
Clamp CLI

What can I do now?

clamp init my-tool --tui · src/main.rs
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}");
        }
    });
}
Released

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
Lifecycle

What can I do now?

rustclamp::config · rustclamp-core lifecycle
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 };
Released

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
Web projects

What can I do now?

clamp init my-site --web · rustclamp::web
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()));
}
Released

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
Workers and outbox

What can I do now?

examples/03-email-worker
// 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(())
});
Released

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
Scheduler

What can I do now?

examples/04-scheduler
let catch_up_job = JobDeclaration::new(
    "cleanup-expired-sessions",
    Duration::from_secs(10),
    MisfirePolicy::RunOnce,
    || async {
        println!("cleanup operation invoked");
        Ok(())
    },
);
Released

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 + alloc consumer of Core
Loops and devices
examples/a6-platform-neutral
#![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.

Works today

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
Works today

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
In progress

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
Works today

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
Don't trust the marketing

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.

All measurements

  1. 01
    Facade dependencies

    Zero third-party crates in the facade, Core and Kernel, enforced by boundary checks.

    0
  2. 02
    Unchanged rebuild

    Median delta over plain Rust.

    +1.67 ms
  3. 03
    Clean build

    Median delta, about 16%. The initial cost budget.

    +36.78 ms
  4. 04
    Process wall time

    Median delta; sample ranges overlap almost entirely.

    +0.054 ms
  5. 05
    Console-only Users build

    Resolved packages. The same domain with HTTP resolves 62, with PostgreSQL 160: Axum, SQLx and Tokio stay out until selected.

    8
What Clamp is

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.

Not a framework Not an async runtime Not an ORM Not a DI container Not a replacement for Tokio, Axum or SQLx
Your application first

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.

Architecture

FAQ

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.

How to start

Start in three commands.
Bare minimum or a web page.

  1. 1

    Install RustClamp

    Linux or macOS. Installs Rust if it is missing, downloads the prebuilt, checksum-verified clamp and puts it on your PATH.

    $ curl -fsSL https://rustclamp.com/install.sh | bash
  2. 2

    Create and run

    Pick a starting point. Both are ordinary Cargo projects you can open, read and change.

    Bare minimumno dependencies
    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 inside Clamp::run. 0 B over plain Rust.

    A web pageneeds Node.js + npm
    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:8080

    Routes in app/routes/, pages in app/resources/views, Vite and Tailwind rebuilding on save.

  3. 3

    Grow it

    Add routes, sessions, jobs or a worker when you need them, and ask clamp inspect, why or doctor what your app is made of.

rustclamp.com/install.sh

Read it before you run it.

You are about to pipe a script into your shell, so here is every line of it, exactly as rustclamp.com serves it. In short, it:

  1. Checks you are on Linux or macOS (x86_64 or ARM64) and that curl, tar and HOME are there.
  2. Installs Rust with rustup (minimal profile) if Rust is missing.
  3. If no C compiler is found: on Linux it installs build tools with your package manager through sudo, so it may ask for your password; on macOS it starts the Xcode Command Line Tools install and stops.
  4. Downloads the latest prebuilt clamp release from GitHub and verifies its SHA-256 checksum, or builds it from source when no binary fits your platform.
  5. Installs clamp into ~/.cargo/bin and adds one PATH line to your shell profile (.zshrc, .bashrc or fish config) if it is not there yet.
Loading install.sh…
Download install.sh