Installation

Margaret needs Rust 1.95 or newer and edition 2024. Let's set up the box office crate:

$ cargo new box_office

1. Add the dependencies

Margaret goes into Cargo.toml twice: once as the runtime, and once as a build dependency that generates your wiring.

[dependencies]
anyhow = "1.0"
clap = "4.5"
margaret = "0.4"

[build-dependencies]
margaret = { version = "0.4", default-features = false, features = ["codegen"] }

The generated code lives in your crate and calls a few crates directly. As you use more features, add them too:

FeatureCrates
HTTP servers and background servicestokio, tokio-util, trzcina
Route binders, WebSocket handlers, sign-in, and signing keysasync-trait
Modelschrono, uuid, rust_decimal, as your columns need them
Request data and WebSocket messagesserde, validator (both with derive)
Viewsmaud
WebSocket sessionsserde_json
Streamed responsesbytes, futures-util
Service identityspiffe (with spiffe-types)

Forget one, and the compiler points at the line that needs it. Margaret re-exports reqwest as margaret::framework::reqwest, so HTTP clients need no extra dependency.

2. Add the build script

fn main() -> Result<(), margaret::framework::codegen::codegen_error::CodegenError> {
    margaret::framework::codegen::generate::generate()
}

It reads your crate, starting at src/lib.rs, and writes the wiring into a margaret/ directory next to Cargo.toml. That directory is generated, so keep it out of git:

/margaret/

3. Include the generated module

#[rustfmt::skip]
#[path = "../margaret/mod.rs"]
pub mod margaret;

4. Call the runner from main

use margaret::framework::console::command_outcome::CommandOutcome;

fn main() -> CommandOutcome {
    box_office::margaret::run::run(std::env::args_os())
}

Margaret generates the runner as soon as your application has something to run, like a console command. Once it serves something, like an HTTP route, the runner becomes async, and main moves to Tokio:

use margaret::framework::console::command_outcome::CommandOutcome;

#[tokio::main]
async fn main() -> CommandOutcome {
    box_office::margaret::run::run(std::env::args_os()).await
}

Don't worry about missing that moment: the compiler tells you.

That's it! Let's build your first application.