| name | adding-raps-cli-command |
| version | 1.0 |
| description | Use when adding a new CLI command or subcommand to RAPS — covers the clap struct pattern, module wiring, output formatting, and test structure across the 10-crate workspace. |
Adding a RAPS CLI Command
Add a new command or subcommand following the established patterns.
Repo: /root/github/raps/raps
Architecture
raps-kernel/ — config, auth, security, logging (shared by all)
raps-oss/ — OSS bucket/object API client
raps-derivative/ — Model Derivative API client
raps-dm/ — Data Management API client
raps-da/ — Design Automation API client
raps-acc/ — ACC Issues, RFIs, Submittals, Assets, Checklists
raps-webhooks/ — Webhooks API client
raps-reality/ — Reality Capture API client
raps-admin/ — Account Admin API client
raps-cli/ — CLI layer (clap, MCP server, commands)
Commands live in raps-cli/src/commands/. API clients live in domain crates.
Command Pattern
1. Clap Subcommand Enum
use clap::Subcommand;
#[derive(Debug, Subcommand)]
pub enum FooCommands {
List,
Info {
foo_id: String,
},
Create {
#[arg(short, long)]
name: String,
#[arg(short, long, default_value = "default")]
policy: String,
},
}
2. Execute Method
impl FooCommands {
pub async fn execute(
self,
client: &FooClient,
output_format: OutputFormat,
) -> Result<()> {
match self {
FooCommands::List => list_foos(client, output_format).await,
FooCommands::Info { foo_id } => get_foo(client, &foo_id, output_format).await,
FooCommands::Create { name, policy } => {
create_foo(client, &name, &policy, output_format).await
}
}
}
}
3. Output Struct
#[derive(Debug, Serialize)]
struct FooOutput {
id: String,
name: String,
#[serde(skip_serializing_if = "Option::is_none")]
description: Option<String>,
}
4. Output Formatting
match output_format {
OutputFormat::Table => {
println!("{}", "Foo Details".bold());
println!("{}", "-".repeat(60));
println!(" {} {}", "Name:".bold(), output.name.cyan());
}
_ => {
output_format.write(&output)?;
}
}
Wiring a New Command
- Create
raps-cli/src/commands/foo.rs
- Add
pub mod foo; to raps-cli/src/commands/mod.rs
- Add variant to main CLI enum in
raps-cli/src/main.rs:
#[command(subcommand)]
Foo(commands::foo::FooCommands),
- Add match arm in dispatch:
Commands::Foo(cmd) => cmd.execute(&foo_client, output_format).await,
If Adding an API Client
- Create function in the appropriate domain crate (e.g.,
raps-oss/src/objects.rs)
- Use
reqwest with the shared HttpClientConfig
- Return domain types with
#[derive(Debug, Deserialize, Serialize)]
- Handle errors with
anyhow::Result
Test Pattern
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_foo_output_serialization() {
let output = FooOutput { id: "123".into(), name: "test".into(), description: None };
let json = serde_json::to_string(&output).unwrap();
assert!(json.contains("\"id\":\"123\""));
}
}
Checklist
- Create command file with Subcommand enum + execute method
- Wire into mod.rs and main.rs
- Create Serialize output struct
- Handle Table + structured output formats
- Add tests
- Run
cargo clippy --workspace and cargo test --workspace