Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Examples

Real-world usage patterns for kicad-ipc-rs.

Quick Version Probe (Async)

use kicad_ipc_rs::KiCadClient;

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), kicad_ipc_rs::KiCadError> {
    let client = KiCadClient::connect().await?;
    let version = client.get_version().await?;
    println!("{:?}", version);
    Ok(())
}

Open Board Detection (Blocking)

use kicad_ipc_rs::KiCadClientBlocking;

fn main() -> Result<(), kicad_ipc_rs::KiCadError> {
    let client = KiCadClientBlocking::connect()?;
    let has_board = client.has_open_board()?;
    println!("open board: {}", has_board);
    Ok(())
}

Example: Editable Item Mutation

Fetch editable tracks, mutate them in place, and write them back as one undoable KiCad commit:

use kicad_ipc_rs::{CommitAction, EditablePcbItem, KiCadClient};

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), kicad_ipc_rs::KiCadError> {
    let client = KiCadClient::connect().await?;

    let trace_type = KiCadClient::pcb_object_type_codes()
        .iter()
        .find(|entry| entry.name == "KOT_PCB_TRACE")
        .expect("trace object type should exist")
        .code;

    let mut items = client
        .get_editable_items_by_type_codes(vec![trace_type])
        .await?;

    for item in &mut items {
        if let EditablePcbItem::Track(track) = item {
            track.set_layer_id(0);
        }
    }

    let commit = client.begin_commit().await?;
    client.update_editable_items(items).await?;
    client
        .end_commit(commit, CommitAction::Commit, "update editable tracks")
        .await?;

    Ok(())
}

Example: PCB Analysis - Find Unconnected Nets

Analyze a board to find nets that aren’t properly connected:

use kicad_ipc_rs::KiCadClient;

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), kicad_ipc_rs::KiCadError> {
    let client = KiCadClient::connect().await?;
    
    // Get all nets in the current board
    let nets = client.get_nets().await?;
    
    // Filter for nets with names suggesting they're unconnected
    let suspicious: Vec<_> = nets
        .iter()
        .filter(|net| {
            net.name.to_lowercase().contains("unconnected") ||
            net.name.to_lowercase().contains("unrouted") ||
            net.name.starts_with("Net-(")
        })
        .collect();
    
    if suspicious.is_empty() {
        println!("All nets appear to be properly connected!");
    } else {
        println!("Found {} potentially unconnected nets:", suspicious.len());
        for net in suspicious {
            println!("  - {} (code: {})", net.name, net.code);
        }
    }
    
    Ok(())
}

Example: PCB Analysis - List All Footprints

Get a summary of all footprints on the board:

use kicad_ipc_rs::{KiCadClient, PcbObjectTypeCode};

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), kicad_ipc_rs::KiCadError> {
    let client = KiCadClient::connect().await?;
    
    // Get all footprints
    let footprints = client.get_items_by_type_codes(vec![
        PcbObjectTypeCode::new_footprint()
    ]).await?;
    
    let mut by_lib: std::collections::HashMap<String, usize> = std::collections::HashMap::new();
    
    for item in footprints {
        if let kicad_ipc_rs::PcbItem::Footprint(fp) = item {
            let lib = fp.library_id.unwrap_or_else(|| "Unknown".to_string());
            *by_lib.entry(lib).or_insert(0) += 1;
        }
    }
    
    println!("Footprints by library:");
    for (lib, count) in by_lib.iter().take(10) {
        println!("  {}: {}", lib, count);
    }
    
    Ok(())
}

Example: Automation - Batch Rename Text Variables

Update text variables across the project:

use kicad_ipc_rs::{KiCadClient, DocumentType};
use std::collections::BTreeMap;

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), kicad_ipc_rs::KiCadError> {
    let client = KiCadClient::connect().await?;
    
    // Get current text variables
    let current = client.get_text_variables().await?;
    println!("Current variables: {:?}", current);
    
    // Add/update variables
    let mut updates = current.clone();
    updates.insert("VERSION".to_string(), "v2.1.0".to_string());
    updates.insert("DATE".to_string(), "2026-03-29".to_string());
    
    // Set the updated variables
    client.set_text_variables(updates, 
        kicad_ipc_rs::MapMergeMode::Replace
    ).await?;
    
    println!("Text variables updated successfully");
    Ok(())
}

Example: Automation - Add Test Points to Unconnected Pads

Automatically add test point footprints to pads that aren’t connected to nets:

use kicad_ipc_rs::{KiCadClient, CommitAction, KiCadError, PcbItem};

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), kicad_ipc_rs::KiCadError> {
    let client = KiCadClient::connect().await?;
    
    // Get all pads and filter for unconnected ones
    let items = client.get_all_pcb_items().await?;
    
    let mut unconnected_pads = Vec::new();
    for item in items {
        if let PcbItem::Pad(pad) = item {
            if pad.net_code.is_none() && pad.pad_number != "1" {
                unconnected_pads.push(pad);
            }
        }
    }
    
    if unconnected_pads.is_empty() {
        println!("No unconnected pads found");
        return Ok(());
    }
    
    println!("Found {} unconnected pads to add test points", unconnected_pads.len());
    
    // Start commit session
    let commit = client.begin_commit().await?;
    
    // For each unconnected pad, add a test point footprint
    // (simplified - actual implementation would create footprint items)
    for pad in unconnected_pads.iter().take(5) {
        println!("Would add test point near pad {} at {:?}", 
            pad.pad_number, pad.position_nm);
    }
    
    // Commit the changes
    client.end_commit(
        commit.id,
        CommitAction::Commit,
        "Added test points to unconnected pads"
    ).await?;
    
    Ok(())
}

Example: CI/CD - Design Rule Check Integration

Script to run automated checks before committing to version control:

use kicad_ipc_rs::KiCadClientBlocking;

fn main() -> Result<(), kicad_ipc_rs::KiCadError> {
    let client = KiCadClientBlocking::connect()?;
    
    // Check 1: Verify board is open
    if !client.has_open_board()? {
        eprintln!("ERROR: No board is open in KiCad");
        std::process::exit(1);
    }
    
    // Check 2: Get all nets and look for DRC markers
    let nets = client.get_nets()?;
    println!("✓ Board has {} nets", nets.len());
    
    // Check 3: Verify board origin is set
    let origin = client.get_board_origin(
        kicad_ipc_rs::BoardOriginKind::Drill
    )?;
    println!("✓ Board origin at ({}, {})", origin.x_nm, origin.y_nm);
    
    // Check 4: Save the board before proceeding
    client.save_document()?;
    println!("✓ Board saved");
    
    // Check 5: Export board as string for diffing
    let board_string = client.get_board_as_string()?;
    println!("✓ Board exported ({} bytes)", board_string.len());
    
    println!("\nAll checks passed! Board is ready for commit.");
    Ok(())
}

Example: Integration - Net Class Validation

Verify that all nets have appropriate net classes assigned:

use kicad_ipc_rs::KiCadClientBlocking;
use std::collections::BTreeSet;

fn main() -> Result<(), kicad_ipc_rs::KiCadError> {
    let client = KiCadClientBlocking::connect()?;
    
    // Get all net classes
    let net_classes = client.get_net_classes()?;
    let class_names: BTreeSet<_> = net_classes
        .iter()
        .map(|nc| nc.name.clone())
        .collect();
    
    // Get all nets
    let nets = client.get_nets()?;
    
    // Check each net has a valid net class
    let mut missing_class = Vec::new();
    let netclass_map = client.get_netclass_for_nets(
        nets.iter().map(|n| n.code).collect()
    )?;
    
    for (net_code, class_entry) in netclass_map {
        if class_entry.net_class_name.is_empty() {
            let net = nets.iter().find(|n| n.code == net_code).unwrap();
            missing_class.push(net.name.clone());
        }
    }
    
    if missing_class.is_empty() {
        println!("✓ All {} nets have net classes assigned", nets.len());
    } else {
        println!("⚠ {} nets without net classes:", missing_class.len());
        for net in missing_class.iter().take(10) {
            println!("  - {}", net);
        }
    }
    
    Ok(())
}

Example: Working with Selections

Programmatically select and modify items:

use kicad_ipc_rs::KiCadClientBlocking;

fn main() -> Result<(), kicad_ipc_rs::KiCadError> {
    let client = KiCadClientBlocking::connect()?;
    
    // Get current selection summary
    let summary = client.get_selection_summary(vec![])?;
    println!("Currently selected: {} items", summary.total_count);
    
    // Clear selection
    let result = client.clear_selection()?;
    println!("Cleared {} items from selection", result.summary.total_count);
    
    // Get all tracks
    let tracks = client.get_items_by_type_codes(vec![
        kicad_ipc_rs::PcbObjectTypeCode::new_trace()
    ])?;
    
    // Select first 5 tracks
    let track_ids: Vec<_> = tracks.iter()
        .take(5)
        .filter_map(|item| {
            if let kicad_ipc_rs::PcbItem::Track(t) = item {
                t.id.clone()
            } else {
                None
            }
        })
        .collect();
    
    if !track_ids.is_empty() {
        let result = client.add_to_selection(track_ids)?;
        println!("Added {} tracks to selection", result.summary.total_count);
    }
    
    Ok(())
}

CLI Testing Tool

A CLI tool is available for rapid command testing and debugging:

cargo run --features blocking --bin kicad-ipc-cli -- help

Common commands:

# Basic connectivity
cargo run --features blocking --bin kicad-ipc-cli -- ping
cargo run --features blocking --bin kicad-ipc-cli -- version

# Board queries
cargo run --features blocking --bin kicad-ipc-cli -- board-open
cargo run --features blocking --bin kicad-ipc-cli -- nets
cargo run --features blocking --bin kicad-ipc-cli -- pcb-types

# Selection
cargo run --features blocking --bin kicad-ipc-cli -- selection-summary
cargo run --features blocking --bin kicad-ipc-cli -- clear-selection

Full command catalog: docs/TEST_CLI.md

Next Steps