Add Prettier as a dev dependency with .prettierrc.json config and .prettierignore. Hook added via mirrors-prettier in pre-commit config. All TypeScript, JSON, Markdown, and YAML files auto-formatted. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
14 KiB
KiCAD IPC API Migration Plan
Status: 📋 Planning Target Completion: Week 2-3 (November 1-8, 2025) Priority: 🔴 CRITICAL - Current SWIG API deprecated
Executive Summary
The current KiCAD MCP Server uses SWIG-based Python bindings (import pcbnew) which are deprecated as of KiCAD 9.0 and will be removed in KiCAD 10.0. We must migrate to the official KiCAD IPC API to future-proof the project.
Why Migrate?
| SWIG API (Current) | IPC API (Future) |
|---|---|
| ❌ Deprecated | ✅ Official & Supported |
| ❌ Will be removed in KiCAD 10.0 | ✅ Long-term stability |
| ❌ Python-only | ✅ Multi-language (Python, JS, etc.) |
| ❌ Direct linking | ✅ Inter-process communication |
| ⚠️ Synchronous only | ✅ Async support |
| ⚠️ No versioning | ✅ Protocol Buffers versioning |
Decision: Migrate immediately to avoid technical debt
IPC API Overview
Architecture
┌─────────────────────────────────────────────────────────────┐
│ TypeScript MCP Server (Node.js) │
└──────────────────────┬──────────────────────────────────────┘
│ JSON over stdin/stdout
┌──────────────────────▼──────────────────────────────────────┐
│ Python Interface Layer │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ KiCAD API Abstraction (NEW) │ │
│ └────────────────────────────────────────────────────────┘ │
└──────────────────────┬──────────────────────────────────────┘
│ kicad-python library
┌──────────────────────▼──────────────────────────────────────┐
│ KiCAD IPC Server (Protocol Buffers) │
│ Running inside KiCAD Process │
└──────────────────────┬──────────────────────────────────────┘
│ UNIX Sockets / Named Pipes
┌──────────────────────▼──────────────────────────────────────┐
│ KiCAD 9.0+ Application │
└─────────────────────────────────────────────────────────────┘
Key Differences
-
KiCAD Must Be Running
- SWIG: Can run headless, no KiCAD GUI needed
- IPC: Requires KiCAD running with IPC server enabled
-
Communication Method
- SWIG: Direct Python module import
- IPC: Socket-based RPC (Remote Procedure Call)
-
API Structure
- SWIG:
board.SetSize(width, height) - IPC:
kicad.get_board().set_size(width, height)
- SWIG:
Migration Strategy
Phase 1: Research & Preparation (Days 1-2)
Goals:
- Understand kicad-python library
- Test IPC connection
- Document API differences
Tasks:
# Install kicad-python
pip install kicad-python>=0.5.0
# Test basic connection
python3 << EOF
from kicad import KiCad
kicad = KiCad()
print(f"Connected to KiCAD: {kicad.check_version()}")
EOF
# Read official documentation
# https://docs.kicad.org/kicad-python-main
Deliverables:
- kicad-python installed and tested
- Connection test script
- API comparison document (SWIG vs IPC)
Phase 2: Abstraction Layer (Days 3-4)
Goal: Create an abstraction layer to support both APIs during transition
File Structure:
python/kicad_api/
├── __init__.py
├── base.py # Abstract base class
├── ipc_backend.py # NEW: IPC API implementation
├── swig_backend.py # Legacy SWIG implementation
└── factory.py # Backend selector
Abstract Interface:
# python/kicad_api/base.py
from abc import ABC, abstractmethod
from typing import Optional
from pathlib import Path
class KiCADBackend(ABC):
"""Abstract base class for KiCAD API backends"""
@abstractmethod
def connect(self) -> bool:
"""Connect to KiCAD"""
pass
@abstractmethod
def disconnect(self) -> None:
"""Disconnect from KiCAD"""
pass
@abstractmethod
def is_connected(self) -> bool:
"""Check if connected"""
pass
@abstractmethod
def create_project(self, path: Path, name: str) -> dict:
"""Create a new KiCAD project"""
pass
@abstractmethod
def open_project(self, path: Path) -> dict:
"""Open existing project"""
pass
@abstractmethod
def get_board(self) -> 'BoardAPI':
"""Get board API"""
pass
# ... more abstract methods
IPC Implementation:
# python/kicad_api/ipc_backend.py
from kicad import KiCad
from kicad_api.base import KiCADBackend
class IPCBackend(KiCADBackend):
"""KiCAD IPC API backend"""
def __init__(self):
self.kicad = None
def connect(self) -> bool:
"""Connect to running KiCAD instance"""
try:
self.kicad = KiCad()
# Verify connection
version = self.kicad.check_version()
logger.info(f"Connected to KiCAD via IPC: {version}")
return True
except Exception as e:
logger.error(f"Failed to connect via IPC: {e}")
return False
def create_project(self, path: Path, name: str) -> dict:
"""Create project using IPC API"""
# Implementation here
pass
Backend Factory:
# python/kicad_api/factory.py
from typing import Optional
from kicad_api.base import KiCADBackend
from kicad_api.ipc_backend import IPCBackend
from kicad_api.swig_backend import SWIGBackend
def create_backend(backend_type: Optional[str] = None) -> KiCADBackend:
"""
Create appropriate KiCAD backend
Args:
backend_type: 'ipc', 'swig', or None for auto-detect
Returns:
KiCADBackend instance
"""
if backend_type == 'ipc':
return IPCBackend()
elif backend_type == 'swig':
return SWIGBackend()
else:
# Auto-detect: Try IPC first, fall back to SWIG
try:
backend = IPCBackend()
if backend.connect():
return backend
except ImportError:
pass
# Fall back to SWIG
return SWIGBackend()
Deliverables:
- Abstract base class defined
- IPC backend implemented
- SWIG backend (wrapper around existing code)
- Factory with auto-detection
Phase 3: Port Core Modules (Days 5-8)
Migration Order (by complexity):
-
project.py (Simple - good starting point)
- Create, open, save projects
- Estimated: 2 hours
-
board.py (Medium - board properties)
- Set size, layers, outline
- Estimated: 4 hours
-
component.py (Complex - many operations)
- Place, move, rotate, delete
- Component arrays and alignment
- Estimated: 8 hours
-
routing.py (Complex - trace routing)
- Nets, traces, vias
- Copper pours, differential pairs
- Estimated: 8 hours
-
design_rules.py (Medium - DRC)
- Set rules, run DRC
- Estimated: 4 hours
-
export.py (Medium - file exports)
- Gerber, PDF, SVG, 3D
- Estimated: 4 hours
Total Estimated Time: 30 hours (~4 days)
Migration Template:
# OLD (SWIG)
import pcbnew
board = pcbnew.LoadBoard(filename)
board.SetBoardSize(width, height)
# NEW (IPC via abstraction)
from kicad_api import create_backend
backend = create_backend('ipc')
backend.connect()
board_api = backend.get_board()
board_api.set_size(width, height)
Deliverables:
- project.py migrated
- board.py migrated
- component.py migrated
- routing.py migrated
- design_rules.py migrated
- export.py migrated
Phase 4: Testing & Validation (Days 9-10)
Testing Strategy:
-
Unit Tests
@pytest.mark.parametrize("backend_type", ["ipc", "swig"]) def test_create_project(backend_type): backend = create_backend(backend_type) result = backend.create_project(Path("/tmp/test"), "TestProject") assert result["success"] is True -
Integration Tests
- Run side-by-side: IPC vs SWIG
- Compare outputs for identical operations
- Verify file compatibility
-
Performance Benchmarks
# Measure: operations/second for each backend # Expected: IPC slightly slower due to IPC overhead
Deliverables:
- 50+ unit tests passing for IPC backend
- Side-by-side comparison tests
- Performance benchmarks documented
API Comparison Reference
Project Operations
| Operation | SWIG | IPC |
|---|---|---|
| Create project | Custom file creation | kicad.create_project() |
| Open project | pcbnew.LoadBoard() |
kicad.open_project() |
| Save project | board.Save() |
board.save() |
Board Operations
| Operation | SWIG | IPC |
|---|---|---|
| Get board | pcbnew.LoadBoard() |
kicad.get_board() |
| Set size | board.SetBoardSize() |
board.set_size() |
| Add layer | board.GetLayerCount() |
board.layers.add() |
Component Operations
| Operation | SWIG | IPC |
|---|---|---|
| Place component | pcbnew.FOOTPRINT() |
board.add_footprint() |
| Move component | fp.SetPosition() |
footprint.set_position() |
| Rotate component | fp.SetOrientation() |
footprint.set_rotation() |
Routing Operations
| Operation | SWIG | IPC |
|---|---|---|
| Add net | board.GetNetCount() |
board.nets.add() |
| Route trace | pcbnew.PCB_TRACK() |
board.add_track() |
| Add via | pcbnew.PCB_VIA() |
board.add_via() |
Configuration Changes
Update requirements.txt
+ # KiCAD IPC API (official Python bindings)
+ kicad-python>=0.5.0
# Legacy SWIG support (for backward compatibility)
kicad-skip>=0.1.0
Environment Variables
# Enable IPC API in KiCAD preferences
# Preferences > Plugins > Enable IPC API Server
# Set backend preference (optional)
export KICAD_BACKEND=ipc # or 'swig' or 'auto'
User Migration Guide
Create docs/MIGRATING_TO_IPC.md:
- How to enable IPC in KiCAD
- What changes for users
- Troubleshooting IPC connection issues
Rollback Plan
If IPC migration fails:
- Keep SWIG backend - Already abstracted
- Default to SWIG - Change factory auto-detection
- Document limitations - Note that SWIG will be removed eventually
- Plan retry - Schedule IPC migration for later
Success Criteria
- ✅ All existing functionality works with IPC backend
- ✅ Tests pass with both IPC and SWIG backends
- ✅ Performance acceptable (< 20% slowdown vs SWIG)
- ✅ Documentation updated
- ✅ Migration guide created
- ✅ User-facing tools work without changes
Timeline
| Week | Days | Tasks |
|---|---|---|
| Week 2 | Mon-Tue | Research, install kicad-python, test connection |
| Wed-Thu | Build abstraction layer | |
| Fri | Port project.py and board.py | |
| Week 3 | Mon-Tue | Port component.py and routing.py |
| Wed | Port design_rules.py and export.py | |
| Thu-Fri | Testing, validation, documentation |
Resources
- Official Docs: https://docs.kicad.org/kicad-python-main
- kicad-python PyPI: https://pypi.org/project/kicad-python/
- IPC API Spec: https://dev-docs.kicad.org/en/apis-and-binding/ipc-api/
- Protocol Buffers: Used by IPC for message format
Open Questions
-
How to handle KiCAD not running?
- Option A: Auto-launch KiCAD in background
- Option B: Require user to launch KiCAD first
- Option C: Fall back to SWIG if IPC unavailable
- Decision: Option C for now, A later
-
Connection management
- Should we keep connection open or connect per-operation?
- Decision: Keep alive with reconnect logic
-
Performance vs reliability
- IPC has overhead but more stable
- Decision: Reliability > performance
Next Steps (This Week)
-
Install kicad-python
pip install kicad-python -
Test IPC connection
# Launch KiCAD # Enable IPC in preferences python3 -c "from kicad import KiCad; k=KiCad(); print(k.check_version())" -
Create abstraction layer structure
mkdir -p python/kicad_api touch python/kicad_api/{__init__,base,ipc_backend,swig_backend,factory}.py -
Begin project.py migration
- Start with simplest module
- Establish patterns for others
Prepared by: Claude Code Last Updated: October 25, 2025 Status: 📋 Ready to execute