| Crates.io | clarence |
| lib.rs | clarence |
| version | 0.1.0 |
| created_at | 2025-11-25 17:39:31.88628+00 |
| updated_at | 2025-11-25 17:39:31.88628+00 |
| description | Build powerful CLI tools backed by HTTP APIs |
| homepage | |
| repository | https://github.com/osscorplabs/clarence |
| max_upload_size | |
| id | 1950157 |
| size | 165,491 |
Build powerful CLI tools backed by HTTP APIs in Rust.
use clarence::Clarence;
fn main() {
Clarence::builder()
.name("mycli")
.base_url("https://api.example.com")
.run();
}
mycli users list --active
# → GET https://api.example.com/users/list?active=true
cargo add clarence
use clarence::Clarence;
fn main() {
Clarence::builder()
.name("mycli")
.base_url("https://api.example.com")
.help("My CLI tool")
.version(env!("CARGO_PKG_VERSION"))
.run();
}
Usage:
mycli deploy staging --force true
# → GET https://api.example.com/deploy/staging?force=true
use clarence::{Clarence, Context, Handler, Result, StorageRef};
fn main() {
Clarence::builder()
.name("mycli")
.base_url("https://api.example.com")
.header("Authorization", StorageRef::get("token"))
.on("login", Handler::custom(login))
.fallback(Handler::http().build())
.run();
}
fn login(ctx: &mut Context) -> Result<i32> {
let token = ctx.args.get_flag("token")
.ok_or("Usage: mycli login --token YOUR_TOKEN")?;
ctx.store.set("token", format!("Bearer {}", token))?;
ctx.end().success_with("Logged in successfully")
}
Usage:
mycli login --token abc123
mycli users list
# → GET https://api.example.com/users/list (Authorization: Bearer abc123)
use clarence::{Clarence, Context, Handler, Method, Result};
fn main() {
Clarence::builder()
.name("mycli")
.base_url("https://api.example.com")
.on("login", Handler::custom(login))
.on("deploy", Handler::http()
.method(Method::Post)
.build())
.run();
}
fn login(ctx: &mut Context) -> Result<i32> {
let user = ctx.args.positional.first().unwrap();
println!("Logging in as {}", user);
ctx.end().success()
}
use clarence::{Clarence, Environment, StorageRef};
fn main() {
Clarence::builder()
.name("mycli")
.environments(
Environment::builder()
.flag("env")
.default("dev")
.add("prod", "https://api.prod.com", |env| {
env.header("X-Env", "production")
})
.add("dev", "http://localhost:3000", |_| {})
.build()
)
.run();
}
Usage:
mycli deploy # Uses dev (default)
mycli deploy --env prod # Uses prod
Send git repository information as HTTP headers:
use clarence::{Clarence, Handler, Method};
fn main() {
// Enable globally for all requests
Clarence::builder()
.name("mycli")
.base_url("https://api.example.com")
.send_git_context() // Adds x-cli-git-* headers
.run();
// Or enable per-handler
Clarence::builder()
.name("mycli")
.base_url("https://api.example.com")
.on("deploy", Handler::http()
.method(Method::Post)
.send_git_context() // Only for this handler
.build())
.run();
// Access in custom handlers
Handler::custom(|ctx| {
if ctx.git.is_git_repo {
println!("Branch: {:?}", ctx.git.branch);
println!("Repo: {:?}", ctx.git.repo_name);
}
ctx.end().success()
})
}
HTTP headers sent:
x-cli-git: true (or false)x-cli-git-repo-url: https://github.com/user/repo.gitx-cli-git-repo-name: repox-cli-git-branch: mainYour API can control CLI behavior returning cli_actions:
{
"cli_actions": [
{ "type": "print", "text": "✓ Deployed to production" },
{ "type": "execute", "command": "ls" },
{ "type": "download", "url": "https://...", "path": "./deploy.log" },
{ "type": "storage_set", "key": "last_deploy", "value": "prod" },
{ "type": "storage_unset", "key": "last_deploy" }
]
}
Enable in handler:
use clarence::{Handler, JsonCliActionsParser};
Handler::http()
.parser(
JsonCliActionsParser::new()
.allow_print()
.allow_execute() // (!) Allows commands to be executed remotely
.allow_download()
.allow_storage_set()
.allow_storage_unset()
)
.build()
Clarence::builder()
.name("mycli") // Required
.base_url("https://api.example.com") // Required (unless only custom handlers)
.header("key", "value") // Static header
.header("key", StorageRef::get("k")) // Dynamic from storage
.send_git_context() // Send git info as headers
.help("Help text") // Enable --help
.version("1.0.0") // Enable --version
.on("command", handler) // Register command
.fallback(handler) // Fallback for unknown commands
.environments(config) // Multi-environment
.run() // Start CLI
// Custom function
Handler::custom(|ctx| { ... })
// HTTP request
Handler::http()
.method(Method::Post) // GET, POST, PUT, DELETE, PATCH
.endpoint("/path") // Custom endpoint
.header("key", "value") // Add custom header
.parser(parser) // Custom response parser
.send_git_context() // Send git info as headers
.build()
fn handler(ctx: &mut Context) -> Result<i32> {
// Arguments
ctx.args.command // Vec<String>
ctx.args.positional // Vec<String>
ctx.args.flags // HashMap<String, String>
ctx.args.get_flag("key") // Option<&String>
ctx.args.has_flag("key") // bool
// Storage
ctx.store.set("key", value)?
ctx.store.get("key") // Option<String>
ctx.store.unset("key")?
// Git context
ctx.git.is_git_repo // bool
ctx.git.repo_url // Option<String>
ctx.git.repo_name // Option<String>
ctx.git.branch // Option<String>
// Exit helpers
ctx.end().success() // Exit 0
ctx.end().success_with("Done!") // Exit 0, print
ctx.end().error() // Exit 1
ctx.end().error_with("Failed!") // Exit 1, print error
ctx.end().code(42) // Custom exit code
Ok(0) // Or return directly
}
Run examples with:
cargo run --example complete -- --help
cargo run --example github -- login --token YOUR_TOKEN
cargo run --example environments -- deploy --env prod
cargo test
MIT
https://github.com/osscorplabs/clarence