objectiveai-cli 2.0.5

ObjectiveAI command-line interface and embeddable library
# objectiveai-cli

CLI for ObjectiveAI. Built with `clap` derive macros.

## Building & Testing

```bash
cargo build --package objectiveai-cli
cargo test --package objectiveai-cli
```

## Command-to-Filesystem Mapping

The CLI command tree maps directly to the filesystem:

```
objectiveai agents get          → src/agents/mod.rs (Commands::Get)
objectiveai agents list         → src/agents/mod.rs (Commands::List)
objectiveai agents config get   → src/agents/config/mod.rs (Commands::Get)
objectiveai functions executions create → src/functions/executions/create/mod.rs
```

**Rule:** Each command level is a directory with `mod.rs`. Leaf commands are variants in the `Commands` enum. Every module exposes `pub enum Commands` with a `handle()` method.

## Module Structure

```
src/
├── main.rs              # Entry point, top-level Commands enum, Output enum
├── config.rs            # Config I/O: read(), write(), format_value(), format_jq()
├── error.rs             # CLI Error enum (thiserror)
├── remote.rs            # RemotePathCommitOptional args, Remote enum
├── get.rs               # Reusable GetArgs, GetPairArgs
├── list.rs              # Reusable list helpers (favorites, single, all, pair_*)
├── favorite.rs          # Reusable AddFavorite, EditFavorite arg structs
├── python.rs            # Python execution harness (system + rustpython)
├── api/                 # API config (mode, remote, local, headers)
├── agents/              # Agent commands (get, list, config, favorites)
├── swarms/              # Swarm commands
├── functions/           # Function commands (get, list, config, favorites, executions, inventions, profiles)
└── viewer/              # Viewer config
```

## Command Patterns

### Pattern A: Passthrough (nesting)

```rust
pub mod config;
pub mod favorites;

#[derive(Subcommand)]
pub enum Commands {
    Config { #[command(subcommand)] command: config::Commands },
    Favorites { #[command(subcommand)] command: favorites::Commands },
}

impl Commands {
    pub fn handle(self) -> Result<crate::Output, crate::error::Error> {
        match self {
            Commands::Config { command } => command.handle(),
            Commands::Favorites { command } => command.handle(),
        }
    }
}
```

### Pattern B: Config Get/Set (leaf)

```rust
#[derive(Subcommand)]
pub enum Commands {
    Get,
    Set { value: String },
}

impl Commands {
    pub fn handle(self) -> Result<crate::Output, crate::error::Error> {
        let (client, mut config) = crate::config::read()?;
        match self {
            Commands::Get => Ok(crate::Output::ConfigGet(
                crate::config::format_value(&config.api().get_mode()),
            )),
            Commands::Set { value } => {
                config.api().set_mode(value);
                crate::config::write(&client, &config)?;
                Ok(crate::Output::ConfigSet)
            }
        }
    }
}
```

### Pattern C: API commands (async)

```rust
impl Commands {
    pub async fn handle(self) -> Result<crate::Output, crate::error::Error> {
        match self {
            Commands::Get { args } => {
                let path = args.resolve(get_favorites)?;
                crate::api::run(|http_client| async move {
                    let response = objectiveai::agent::get_agent(&http_client, path).await?;
                    Ok(serde_json::to_string(&response).unwrap())
                }, false).await
            }
        }
    }
}
```

### Pattern D: Favorites management

Uses reusable `crate::favorite::AddFavorite` / `EditFavorite` structs. Variants: `Get`, `Add`, `Del`, `Edit`.

## Naming Conventions

- **Modules**: snake_case matching command names (`agents/`, `functions/executions/`)
- **Command enums**: Always `pub enum Commands` with `#[derive(Subcommand)]`
- **Argument structs**: Descriptive PascalCase with `#[derive(Args)]` (e.g., `GetArgs`, `ProfileArgs`)
- **Handler methods**: Always `handle(self)` or `async fn handle(self)`
- **Return type**: Always `Result<crate::Output, crate::error::Error>`

## Output Enum

All commands return `Output`:

```rust
pub enum Output {
    ConfigGet(String),   // Config value → stdout
    ConfigSet,           // Silent success
    Api(String),         // API response JSON → stdout
}
```

`main.rs` matches on this and prints to stdout. No `println!` outside `main.rs`.

## Async vs Sync

- **Sync**: Config commands (read/write local files)
- **Async**: API commands (use `crate::api::run()` which manages HTTP client and viewer)

When a command is async, all its parent `handle()` methods must also be async.

## Reusable Components

- `crate::get::GetArgs` — resolves `--favorite` or `--remote/--owner/--repository/--commit` to a path
- `crate::list::Source` — enum for `favorites`, `filesystem`, `objectiveai`, `all`
- `crate::favorite::{AddFavorite, EditFavorite}` — shared CRUD args for favorites
- `crate::api::run()` — runs async closure with HTTP client, handles Local/Remote/Viewer modes