Case Study: APR CLI Commands Demo

This case study demonstrates creating test models and using all 17 apr-cli commands for model inspection, validation, transformation, testing, and inference.

The Problem

APR model files need comprehensive tooling for:

NeedTraditional ApproachProblem
InspectionCustom scriptsNo standardization
ValidationManual checksumsIncomplete coverage
TransformationFramework-specificLock-in
RegressionManual testingError-prone

The Solution: apr-cli

The apr CLI provides 17 commands for complete model lifecycle management:

# Build the CLI
cargo build -p apr-cli

# Inspect model metadata
./target/debug/apr inspect model.apr --json

# Validate integrity (100-point QA)
./target/debug/apr validate model.apr --quality

# Quantize model
./target/debug/apr convert model.apr --quantize int8 -o model-int8.apr

Complete Example

Run: cargo run --example apr_cli_commands

//! APR CLI Commands Demo
//!
//! Demonstrates creating test models and using the apr-cli commands.
//! This example creates model files that work with all 17 apr-cli commands.
//!
//! Toyota Way Alignment:
//! - **Genchi Genbutsu**: Go and see - inspect actual model data
//! - **Jidoka**: Built-in quality - validate models automatically
//! - **Visualization**: Make problems visible with trace and debug
//!
//! Run with: `cargo run --example apr_cli_commands`
//!
//! After running, use the apr CLI on the generated files:
//! ```bash
//! cargo build -p apr-cli
//! ./target/debug/apr inspect /tmp/apr_cli_demo/demo_model.apr
//! ./target/debug/apr validate /tmp/apr_cli_demo/demo_model.apr --quality
//! ./target/debug/apr debug /tmp/apr_cli_demo/demo_model.apr --drama
//! ./target/debug/apr tensors /tmp/apr_cli_demo/demo_model.apr --stats
//! ./target/debug/apr trace /tmp/apr_cli_demo/demo_model.apr --verbose
//! ./target/debug/apr diff /tmp/apr_cli_demo/demo_model.apr /tmp/apr_cli_demo/demo_model_v2.apr
//! ./target/debug/apr probar /tmp/apr_cli_demo/demo_model.apr -o /tmp/apr_cli_demo/probar
//! ./target/debug/apr explain E002
//!
//! # Inference commands (requires --features inference):
//! cargo build -p apr-cli --features inference
//! ./target/debug/apr run /tmp/apr_cli_demo/demo_model.apr --input "[1.0, 2.0]"
//! ./target/debug/apr serve /tmp/apr_cli_demo/demo_model.apr --port 8080
//! ```

use aprender::serialization::apr::AprWriter;
use serde_json::json;
use std::fs;
use std::path::Path;

fn main() -> Result<(), String> {
    println!("=== APR CLI Commands Demo ===\n");

    // Create output directory
    let demo_dir = Path::new("/tmp/apr_cli_demo");
    fs::create_dir_all(demo_dir).map_err(|e| e.to_string())?;

    // Part 1: Create a demo model
    println!("--- Part 1: Creating Demo Model ---\n");
    let model_path = create_demo_model(demo_dir)?;
    println!("Created: {}\n", model_path.display());

    // Part 2: Create a second model for diff comparison
    println!("--- Part 2: Creating Second Model (for diff) ---\n");
    let model_v2_path = create_demo_model_v2(demo_dir)?;
    println!("Created: {}\n", model_v2_path.display());

    // Part 3: Show CLI commands
    println!("--- Part 3: CLI Commands Reference ---\n");
    print_cli_commands(&model_path, &model_v2_path);

    println!("\n=== Demo Complete! ===");
    println!("\nModel files created in: {}", demo_dir.display());
    println!("Build the CLI with: cargo build -p apr-cli");
    println!("Then run the commands shown above.");

    Ok(())
}

fn create_demo_model(dir: &Path) -> Result<std::path::PathBuf, String> {
    let mut writer = AprWriter::new();

    // Add model metadata
    writer.set_metadata("model_type", json!("linear_regression"));
    writer.set_metadata("model_name", json!("Demo Linear Regression"));
    writer.set_metadata("description", json!("A demo model for CLI testing"));
    writer.set_metadata("n_features", json!(2));
    writer.set_metadata("n_outputs", json!(1));
    writer.set_metadata("framework", json!("aprender"));
    writer.set_metadata("framework_version", json!(env!("CARGO_PKG_VERSION")));

    // Add hyperparameters
    writer.set_metadata(
        "hyperparameters",
        json!({
            "n_layer": 4,
            "n_embd": 128,
            "learning_rate": 0.01
        }),
    );

    // Add training info
    writer.set_metadata(
        "training",
        json!({
            "dataset": "synthetic",
            "n_samples": 1000,
            "n_epochs": 100,
            "final_loss": 0.0234
        }),
    );

    // Add tensors (simulating a small model)
    println!("  Adding tensors...");

    // Weights tensor
    let weights: Vec<f32> = vec![1.5, 0.8];
    writer.add_tensor_f32("weights", vec![2, 1], &weights);

    // Bias tensor
    let bias: Vec<f32> = vec![0.5];
    writer.add_tensor_f32("bias", vec![1], &bias);

    // Embedding layer (to make it more interesting for trace)
    let embedding: Vec<f32> = (0..128).map(|i| (i as f32) * 0.01).collect();
    writer.add_tensor_f32("embedding", vec![128], &embedding);

    // Layer norm weights
    let ln_weight: Vec<f32> = vec![1.0; 128];
    writer.add_tensor_f32("layer_norm.weight", vec![128], &ln_weight);

    // Write to file
    let path = dir.join("demo_model.apr");
    let bytes = writer.to_bytes()?;
    fs::write(&path, &bytes).map_err(|e| e.to_string())?;

    println!("  Model type: Linear Regression");
    println!("  Tensors: 4");
    println!("  Size: {} bytes", bytes.len());

    Ok(path)
}

fn create_demo_model_v2(dir: &Path) -> Result<std::path::PathBuf, String> {
    let mut writer = AprWriter::new();

    // Slightly different metadata
    writer.set_metadata("model_type", json!("linear_regression"));
    writer.set_metadata("model_name", json!("Demo Linear Regression v2"));
    writer.set_metadata("description", json!("Updated model with more training"));
    writer.set_metadata("n_features", json!(2));
    writer.set_metadata("n_outputs", json!(1));
    writer.set_metadata("framework", json!("aprender"));
    writer.set_metadata("framework_version", json!(env!("CARGO_PKG_VERSION")));

    // Different hyperparameters
    writer.set_metadata(
        "hyperparameters",
        json!({
            "n_layer": 4,
            "n_embd": 128,
            "learning_rate": 0.005  // Changed
        }),
    );

    // More training
    writer.set_metadata(
        "training",
        json!({
            "dataset": "synthetic_extended",  // Changed
            "n_samples": 2000,                // Changed
            "n_epochs": 200,                  // Changed
            "final_loss": 0.0156              // Improved
        }),
    );

    // Slightly different weights (simulating retraining)
    let weights: Vec<f32> = vec![1.52, 0.79]; // Slightly different
    writer.add_tensor_f32("weights", vec![2, 1], &weights);

    let bias: Vec<f32> = vec![0.48]; // Slightly different
    writer.add_tensor_f32("bias", vec![1], &bias);

    let embedding: Vec<f32> = (0..128).map(|i| (i as f32) * 0.0101).collect();
    writer.add_tensor_f32("embedding", vec![128], &embedding);

    let ln_weight: Vec<f32> = vec![1.0; 128];
    writer.add_tensor_f32("layer_norm.weight", vec![128], &ln_weight);

    let path = dir.join("demo_model_v2.apr");
    let bytes = writer.to_bytes()?;
    fs::write(&path, &bytes).map_err(|e| e.to_string())?;

    println!("  Model type: Linear Regression v2");
    println!("  Tensors: 4");
    println!("  Size: {} bytes", bytes.len());

    Ok(path)
}

fn print_cli_commands(model_path: &Path, model_v2_path: &Path) {
    let model = model_path.display();
    let model_v2 = model_v2_path.display();
    let demo_dir = model_path.parent().unwrap().display();

    println!("Build the CLI first:");
    println!("  cargo build -p apr-cli\n");
    println!("For inference commands (run, serve):");
    println!("  cargo build -p apr-cli --features inference\n");

    println!("=== 17 APR CLI Commands ===\n");

    println!("--- Model Inspection ---\n");

    println!("1. INSPECT - View model metadata:");
    println!("   ./target/debug/apr inspect {model}");
    println!("   ./target/debug/apr inspect {model} --json");
    println!("   ./target/debug/apr inspect {model} --weights\n");

    println!("2. TENSORS - List tensor info:");
    println!("   ./target/debug/apr tensors {model}");
    println!("   ./target/debug/apr tensors {model} --stats");
    println!("   ./target/debug/apr tensors {model} --json\n");

    println!("3. TRACE - Layer-by-layer analysis:");
    println!("   ./target/debug/apr trace {model}");
    println!("   ./target/debug/apr trace {model} --verbose");
    println!("   ./target/debug/apr trace {model} --json\n");

    println!("4. DEBUG - Debug output:");
    println!("   ./target/debug/apr debug {model}");
    println!("   ./target/debug/apr debug {model} --drama");
    println!("   ./target/debug/apr debug {model} --hex --limit 64\n");

    println!("--- Quality & Validation ---\n");

    println!("5. VALIDATE - Check model integrity (100-point QA):");
    println!("   ./target/debug/apr validate {model}");
    println!("   ./target/debug/apr validate {model} --quality");
    println!("   ./target/debug/apr validate {model} --strict\n");

    println!("6. LINT - Best practices check:");
    println!("   ./target/debug/apr lint {model}\n");

    println!("7. DIFF - Compare two models:");
    println!("   ./target/debug/apr diff {model} {model_v2}");
    println!("   ./target/debug/apr diff {model} {model_v2} --json\n");

    println!("--- Model Transformation ---\n");

    println!("8. CONVERT - Quantization/optimization:");
    println!("   ./target/debug/apr convert {model} --quantize int8 -o {demo_dir}/model-int8.apr");
    println!(
        "   ./target/debug/apr convert {model} --quantize fp16 -o {demo_dir}/model-fp16.apr\n"
    );

    println!("9. EXPORT - Export to other formats:");
    println!(
        "   ./target/debug/apr export {model} --format safetensors -o {demo_dir}/model.safetensors"
    );
    println!("   ./target/debug/apr export {model} --format gguf -o {demo_dir}/model.gguf\n");

    println!("10. MERGE - Merge models:");
    println!("    ./target/debug/apr merge {model} {model_v2} --strategy average -o {demo_dir}/merged.apr");
    println!("    ./target/debug/apr merge {model} {model_v2} --strategy weighted -o {demo_dir}/merged.apr\n");

    println!("--- Import & Interop ---\n");

    println!("11. IMPORT - Import external models:");
    println!("    ./target/debug/apr import ./external.safetensors -o imported.apr");
    println!("    ./target/debug/apr import hf://org/repo -o model.apr --arch whisper\n");

    println!("--- Testing & Regression ---\n");

    println!("12. CANARY - Regression testing:");
    println!("    ./target/debug/apr canary create {model} --input ref.wav --output {demo_dir}/canary.json");
    println!("    ./target/debug/apr canary check {model_v2} --canary {demo_dir}/canary.json\n");

    println!("13. PROBAR - Visual regression testing export:");
    println!("    ./target/debug/apr probar {model} -o {demo_dir}/probar_output");
    println!("    ./target/debug/apr probar {model} -o {demo_dir}/probar_output --format json\n");

    println!("--- Help & Documentation ---\n");

    println!("14. EXPLAIN - Get explanations:");
    println!("    ./target/debug/apr explain E002");
    println!("    ./target/debug/apr explain --tensor encoder.conv1.weight");
    println!("    ./target/debug/apr explain --file {model}\n");

    println!("--- Interactive ---\n");

    println!("15. TUI - Interactive terminal UI:");
    println!("    ./target/debug/apr tui {model}");
    println!("    Tabs: Overview [1], Tensors [2], Stats [3], Help [?]");
    println!("    Navigation: j/k or arrows, Tab to switch, q to quit\n");

    println!("--- Inference (requires --features inference) ---\n");

    println!("16. RUN - Run inference on a model:");
    println!("    ./target/debug/apr run {model} --input \"[1.0, 2.0]\"");
    println!("    ./target/debug/apr run {model} --input \"1.0,2.0\"");
    println!("    ./target/debug/apr run {model} --input \"[1.0, 2.0]\" --json\n");

    println!("17. SERVE - Start inference server:");
    println!("    ./target/debug/apr serve {model} --port 8080");
    println!("    ./target/debug/apr serve {model} --host 0.0.0.0 --port 3000");
    println!("    # Then: curl http://localhost:8080/health");
    println!(
        "    # Then: curl -X POST http://localhost:8080/predict -d '{{\"input\": [1.0, 2.0]}}'\n"
    );
}

All 17 Commands

Model Inspection

1. INSPECT - View Model Metadata

apr inspect model.apr              # Basic info
apr inspect model.apr --json       # JSON output
apr inspect model.apr --weights    # Include tensor info

Shows model type, framework, hyperparameters, and training info.

2. TENSORS - List Tensor Info

apr tensors model.apr              # List all tensors
apr tensors model.apr --stats      # Include statistics
apr tensors model.apr --json       # JSON output

Lists tensor names, shapes, dtypes, and statistics.

3. TRACE - Layer-by-Layer Analysis

apr trace model.apr                # Basic trace
apr trace model.apr --verbose      # Detailed trace
apr trace model.apr --json         # JSON output

Analyzes model layer by layer for debugging inference.

4. DEBUG - Debug Output

apr debug model.apr                # Standard debug
apr debug model.apr --drama        # Detailed drama mode
apr debug model.apr --hex --limit 64  # Hex dump

Provides detailed tensor inspection for debugging.

Quality & Validation

5. VALIDATE - Check Model Integrity

apr validate model.apr             # Basic validation
apr validate model.apr --quality   # 100-point QA checklist
apr validate model.apr --strict    # Strict mode

Runs the 100-point quality assessment with grades A+ to F.

6. LINT - Best Practices Check

apr lint model.apr                 # Check best practices

Static analysis for naming conventions, metadata completeness, and efficiency.

Checks:

  • Standard tensor naming patterns (layer.0.weight, not l0_w)
  • Required metadata (author, license, provenance)
  • Tensor alignment (64-byte boundaries)
  • Compression for large tensors (>1MB)

7. DIFF - Compare Two Models

apr diff model_v1.apr model_v2.apr       # Compare models
apr diff model_v1.apr model_v2.apr --json  # JSON output

Shows metadata and tensor differences between model versions.

Model Transformation

8. CONVERT - Quantization/Optimization

apr convert model.apr --quantize int8 -o model-int8.apr
apr convert model.apr --quantize int4 -o model-int4.apr
apr convert model.apr --quantize fp16 -o model-fp16.apr

Applies quantization for reduced model size and faster inference.

QuantizationSize ReductionAccuracy Impact
fp1650%Minimal
int875%Small
int487.5%Moderate

9. EXPORT - Export to Other Formats

apr export model.apr --format safetensors -o model.safetensors
apr export model.apr --format gguf -o model.gguf

Exports APR models to other ecosystems:

  • SafeTensors - HuggingFace ecosystem
  • GGUF - llama.cpp / local inference

10. MERGE - Merge Models

apr merge model1.apr model2.apr --strategy average -o merged.apr
apr merge model1.apr model2.apr --strategy weighted -o merged.apr

Combines multiple models using different strategies:

  • average - Simple tensor averaging
  • weighted - Weighted combination

Import & Interop

11. IMPORT - Import External Models

apr import external.safetensors -o imported.apr
apr import hf://org/repo -o model.apr --arch whisper

Imports from SafeTensors, HuggingFace Hub, and other formats.

Testing & Regression

12. CANARY - Regression Testing

# Create canary from original model
apr canary create model.apr --input ref.wav --output canary.json

# Check optimized model against canary
apr canary check model-optimized.apr --canary canary.json

Captures tensor statistics for regression testing after transformations (quantization, pruning).

Canary data includes:

  • Tensor shapes and counts
  • Mean, std, min, max for each tensor
  • Drift tolerance checking

13. PROBAR - Visual Regression Testing

apr probar model.apr -o probar_output         # Create probar suite
apr probar model.apr -o output --format json  # JSON format

Exports model data for visual regression testing.

Help & Documentation

14. EXPLAIN - Get Explanations

apr explain E002                           # Explain error code
apr explain --tensor encoder.conv1.weight  # Explain tensor name
apr explain --file model.apr               # Analyze file

Provides context-aware explanations for errors and tensor patterns.

Interactive

15. TUI - Interactive Terminal UI

apr tui model.apr                          # Launch interactive UI

Interactive terminal interface for model exploration with four tabs:

TabKeyDescription
Overview1Model metadata, hyperparameters, training info
Tensors2Tensor list with shapes, dtypes, sizes
Stats3Tensor statistics (mean, std, min, max, zeros, NaNs)
Help?Keyboard shortcuts and navigation help

Keyboard Navigation:

  • 1, 2, 3, ? - Switch tabs directly
  • Tab / Shift+Tab - Cycle through tabs
  • j / - Next item in list
  • k / - Previous item in list
  • q / Esc - Quit

Inference (requires --features inference)

Build with inference support:

cargo build -p apr-cli --features inference

16. RUN - Run Model Inference

apr run model.apr --input "[1.0, 2.0]"       # JSON array input
apr run model.apr --input "1.0,2.0"          # CSV input
apr run model.apr --input "[1.0, 2.0]" --json  # JSON output

Runs inference on APR, SafeTensors, or GGUF models:

FormatInference Type
APR (.apr)Full ML inference via realizar
SafeTensors (.safetensors)Tensor inspection
GGUF (.gguf)Model inspection (mmap)

Input Formats:

  • JSON array: "[1.0, 2.0, 3.0]"
  • CSV: "1.0,2.0,3.0"

17. SERVE - Start Inference Server

apr serve model.apr --port 8080              # Start on port 8080
apr serve model.apr --host 0.0.0.0 --port 3000  # Bind to all interfaces

Starts a REST API server for model inference:

APR Models (full inference):

# Health check
curl http://localhost:8080/health

# Run inference
curl -X POST http://localhost:8080/predict \
  -H "Content-Type: application/json" \
  -d '{"input": [1.0, 2.0]}'

Server Features:

  • /health - Health check endpoint
  • /predict - Inference endpoint (APR models)
  • /model - Model info endpoint (GGUF/SafeTensors)
  • /tensors - Tensor listing (SafeTensors)
  • Graceful shutdown via Ctrl+C

Example Output

Running the example creates demo models:

=== APR CLI Commands Demo ===

--- Part 1: Creating Demo Model ---
  Adding tensors...
  Model type: Linear Regression
  Tensors: 4
  Size: 1690 bytes
Created: /tmp/apr_cli_demo/demo_model.apr

--- Part 2: Creating Second Model (for diff) ---
  Model type: Linear Regression v2
  Tensors: 4
  Size: 1707 bytes
Created: /tmp/apr_cli_demo/demo_model_v2.apr

Use Cases

CI/CD Model Validation

# In CI pipeline
apr validate model.apr --strict --min-score 90 && apr lint model.apr
if [ $? -ne 0 ]; then
    echo "Model validation failed"
    exit 1
fi

Model Optimization Pipeline

# Quantize for production
apr convert model.apr --quantize int8 -o model-int8.apr

# Verify no regression
apr canary create model.apr --input test.wav --output canary.json
apr canary check model-int8.apr --canary canary.json

# Export for deployment
apr export model-int8.apr --format gguf -o model.gguf

Model Version Comparison

# Compare before/after optimization
apr diff original.apr quantized.apr --json | jq '.tensor_changes'

Debugging Inference Issues

# Layer-by-layer trace
apr trace model.apr --verbose | grep -i "nan\|inf"

# Drama mode for detailed analysis
apr debug model.apr --drama

Benefits

BenefitDescription
StandardizedConsistent CLI for all APR models
Comprehensive17 commands cover full lifecycle
ScriptableJSON output for automation
DebuggableDeep inspection with drama mode
Validatable100-point QA with grades
TransformableQuantization and format conversion
TestableCanary regression testing
InferenceRun predictions and serve REST APIs