19 releases (12 breaking)

0.13.0 Apr 19, 2026
0.11.1 Apr 2, 2026
0.11.0 Mar 29, 2026
0.7.1 Dec 9, 2025
0.1.0 Sep 7, 2024

#234 in Build Utils

Download history 195/week @ 2026-01-22 106/week @ 2026-01-29 233/week @ 2026-02-05 233/week @ 2026-02-12 322/week @ 2026-02-19 382/week @ 2026-02-26 335/week @ 2026-03-05 253/week @ 2026-03-12 411/week @ 2026-03-19 327/week @ 2026-03-26 327/week @ 2026-04-02 37/week @ 2026-04-09 211/week @ 2026-04-16 112/week @ 2026-04-23 18/week @ 2026-04-30 18/week @ 2026-05-07

359 downloads per month
Used in cicero_cli

Apache-2.0

68KB
981 lines

Cicero

Cicero helps you implement a CLI for the CI needs of your Rust project.

You implement this CLI in Rust to benefit from its flexibility and familiarity, while Cicero provides a framework that simplifies common patterns and solves the hard parts that you really shouldn't write a custom solution for.

Usage

Below is a working example for building a distribution archive. The modules would be put into separate files.

mod main_rs {
    use clap::Parser;
    use crate::distribution;

    #[derive(Parser)]
    enum Cli {
        Distribution(distribution::DistributionCli),
    }

    cicero::workspace!(); //collect information about your workspace crates

    fn main() -> cicero::Result<()> {
        cicero::init::tracing().init(); //set up logging

        match Cli::parse() { //can add multiple subcommands/workflows
            Cli::Distribution(cli) => cli.run(),
        }
    }
}

mod distribution {
    use std::{fs, path::Path};
    use cicero::distribution::{bundle::zip::ZipBundler, Distribution, build::{ExecutableBuilder, target}};
    use cicero::path::repo_path;
    use crate::main_rs::workspace;

    #[derive(clap::Args)]
    pub struct DistributionCli;

    impl DistributionCli {
        pub fn run(self) -> cicero::Result<()> {
            let distribution = Distribution::new("myproject")?;

            distribution
                .add_file_from_path(
                    "README.md", //include into distribution as "README.md"
                    repo_path!("README.md") //load from path relative to repository root (compile-safe!)
                )?
                .add_executable(
                    "myproject_ci", //include as "myproject_ci", or "myproject_ci.exe" when targeting Windows
                    ExecutableBuilder::new(
                        workspace::package::ci //crate name from your workspace, as collected by `cicero::workspace!()` above
                    )
                    .target(
                        // `target` module provides compile-time access to targets supported by the Rust compiler.
                        // Can also parse from the CLI via `Target::from_str()`.
                        target::x86_64_unknown_linux_gnu
                    )
                )?;

            distribution
                .dir("doc")? //include the following under a subdirectory "doc/"
                .add_all(|dir| build_doc(dir))?;

            let path = distribution.bundle(ZipBundler)?;
            eprintln!("Placed distribution into {path:?}.");
            Ok(())
        }
    }


    use cicero::commands::{Cli, Crate};
    use cicero::command_exit_ok::CommandExitOk;

    pub static MDBOOK: Cli = Crate::new("mdbook").into_cli(); //defines installation instructions for a CLI tool

    pub fn build_doc(out_dir: &Path) -> cicero::Result<()> {
        MDBOOK.command() //triggers installation and provides std::process:Command object
            .arg("build")
            .arg("--dest-dir").arg(out_dir) //write files into distribution directory
            .current_dir(repo_path!("doc/"))
            .status_exit_ok()?; //runs command like `.status()`, but returns error when status code != 0
        Ok(())
    }
}

# //only needed for running this example in automated tests
# fn main() -> cicero::Result<()> { distribution::DistributionCli.run() }

In a codebase with Cicero set up, you would run this example with cargo ci distribution. It will then build a ZIP archive that contains these files:

myproject
├── README.md
├── myproject_ci (executable)
└── doc
    └── ...

Getting Started

Cicero uses a file structure akin to the cargo-xtask pattern. To set it up, you can use the following commands:

cargo install cicero_cli
cicero init  #run in your repository

cargo ci hello  #runs the 'hello' workflow added by the default template

You can find usage examples in the Cicero repository: https://codeberg.org/trem/cicero/src/branch/main/examples

Changelog

The changelog is available here: https://codeberg.org/trem/cicero/src/branch/main/CHANGELOG.md

Dependencies

~6–14MB
~206K SLoC