# Schematic Wiring Implementation Plan
**Date:** 2026-01-10
**Status:** Planning Phase
**Priority:** HIGH (User-requested feature for Issue #26)
---
## Executive Summary
This plan outlines the implementation of complete schematic wiring functionality for the KiCAD MCP Server. Currently, component placement works perfectly with dynamic symbol loading, but wire/connection tools are incomplete or non-functional.
**Goal:** Enable users to create complete, functional schematics with wired connections between components through the MCP interface.
---
## Current State Analysis
### What Exists ✅
**Files:**
- `python/commands/connection_schematic.py` - ConnectionManager class with wire/label methods
- MCP handlers in `kicad_interface.py` for 6 connection-related tools
**MCP Tools (Registered):**
1. `add_schematic_wire` - Add wire between two points
2. `add_schematic_connection` - Connect two component pins
3. `add_schematic_net_label` - Add net label
4. `connect_to_net` - Connect pin to named net
5. `get_net_connections` - Query net connections
6. `generate_netlist` - Generate netlist from schematic
**ConnectionManager Methods:**
- `add_wire(schematic, start_point, end_point)` - Add wire between coordinates
- `add_connection(schematic, source_ref, source_pin, target_ref, target_pin)` - Connect pins
- `add_net_label(schematic, net_name, position)` - Add label
- `connect_to_net(schematic, component_ref, pin_name, net_name)` - Pin to net
- `get_pin_location(symbol, pin_name)` - Get pin coordinates
- `get_net_connections(schematic, net_name)` - Query connections
- `generate_netlist(schematic)` - Generate netlist
### What's Broken/Missing ❌
**Problem 1: kicad-skip API Uncertainty**
- Code assumes `schematic.wire.append()` exists
- Code assumes `schematic.label.append()` exists
- Code assumes pins have `.name` and `.location` attributes
- **Need to verify what kicad-skip actually supports**
**Problem 2: Pin Location Calculation**
- Current implementation tries to calculate absolute pin positions
- May not account for symbol rotation
- May not work with multi-unit symbols
- Pin numbering vs pin naming confusion
**Problem 3: No Visual Feedback**
- No way to verify wires were created correctly
- No validation of wire endpoints
- No checks for overlapping wires or junctions
**Problem 4: Limited Testing**
- No integration tests for wiring functionality
- No validation with real KiCad schematics
- User reported `add_schematic_wire` fails
**Problem 5: Missing Features**
- No junction (wire intersection) support
- No bus support (multi-bit signals)
- No no-connect flags
- No power symbols (VCC, GND graphical symbols)
- No hierarchical labels
---
## Technical Challenges
### Challenge 1: kicad-skip Wire API
**Issue:** The kicad-skip library documentation is sparse. We need to determine:
- Does `schematic.wire` exist?
- What's the correct API to add wires?
- How are wires stored in .kicad_sch files?
**S-Expression Format (KiCad 8/9):**
```lisp
(wire (pts (xy 100 100) (xy 200 100))
(stroke (width 0) (type default))
(uuid "12345678-1234-1234-1234-123456789012")
)
```
**Approach:**
1. Examine kicad-skip source code
2. Test wire creation manually with kicad-skip
3. Fall back to S-expression manipulation if necessary (similar to dynamic symbol loading)
### Challenge 2: Pin Location Discovery
**Issue:** Need to find exact pin coordinates for automatic wiring.
**Pin Data in Symbols:**
Pins are defined within symbol definitions in lib_symbols, with coordinates relative to symbol origin. When symbol is placed, pins move with it.
**Required Information:**
- Symbol position (x, y)
- Symbol rotation angle
- Pin offset from symbol origin
- Pin number/name mapping
**Solution:**
1. Parse symbol definition to find pin definitions
2. Apply transformation matrix (position + rotation) to pin coordinates
3. Return absolute pin position in schematic space
### Challenge 3: Smart Wire Routing
**Issue:** Users don't want to manually specify every wire segment.
**Desired Behavior:**
```
User: "Connect R1 pin 1 to C1 pin 1"
System:
- Calculate R1 pin 1 location: (100, 100)
- Calculate C1 pin 1 location: (150, 120)
- Create wire path (orthogonal routing preferred):
- (100, 100) → (100, 120) → (150, 120)
- Or simple direct: (100, 100) → (150, 120)
```
**Auto-Routing Options:**
1. **Direct** - Single wire segment (diagonal if needed)
2. **Orthogonal** - Only horizontal/vertical segments (2 segments)
3. **Manhattan** - Complex path avoiding components (3+ segments)
**Phase 1 Approach:** Start with direct wiring, add orthogonal later.
### Challenge 4: Net Label Integration
**Issue:** Labels need to attach to wires, not float in space.
**KiCad Behavior:**
- Labels must touch a wire or pin
- Labels create electrical connections at their attachment point
- Multiple labels with same name = connected net
**Implementation:**
- When adding label, find nearest wire endpoint
- Attach label to that coordinate
- Or create short wire stub for label attachment
---
## Implementation Phases
### Phase 1: Core Wire Functionality (Week 1)
**Goal:** Get basic wiring working with kicad-skip API
**Tasks:**
1. **Research kicad-skip Wire API** (4 hours)
- Read kicad-skip source code
- Test wire creation with Python REPL
- Document actual API methods
- Create test schematic with manual wires
2. **Fix Wire Creation** (6 hours)
- Update ConnectionManager.add_wire() with correct API
- Handle S-expression manipulation if needed
- Add UUID generation for wires
- Test with simple wire (100,100) → (200,100)
3. **Implement Pin Discovery** (8 hours)
- Parse symbol definitions to extract pin data
- Handle pin coordinates relative to symbol
- Apply rotation transformation
- Test with R, C, LED from dynamic symbols
4. **Fix add_schematic_connection** (4 hours)
- Use correct pin discovery
- Create direct wire between pins
- Handle error cases (pin not found, etc.)
- Test with R1 pin 2 → C1 pin 1
5. **Integration Testing** (4 hours)
- Create test schematic with R, C, LED
- Wire R to C
- Wire C to LED
- Verify schematic opens in KiCad
- Verify electrical connectivity
**Deliverables:**
- Working `add_schematic_wire` tool
- Working `add_schematic_connection` tool
- Pin location discovery working
- Integration test passing
- Documentation updated
**Success Criteria:**
- User can connect two resistor pins with MCP command
- Wire appears in KiCad schematic viewer
- Netlist shows electrical connection
---
### Phase 2: Net Labels & Named Nets (Week 1-2)
**Goal:** Enable named net connections (VCC, GND, etc.)
**Tasks:**
1. **Fix Net Label Creation** (4 hours)
- Update ConnectionManager.add_net_label()
- Use correct kicad-skip API or S-expression
- Position labels correctly
- Test label creation
2. **Implement connect_to_net** (6 hours)
- Create wire stub from pin
- Attach label to wire endpoint
- Support common nets (VCC, GND, 3V3, etc.)
- Test with multiple components on same net
3. **Net Connection Discovery** (6 hours)
- Parse wires and labels in schematic
- Build connectivity graph
- Implement get_net_connections()
- Return all pins on a net
4. **Power Symbol Support** (8 hours)
- Add power symbols to templates (VCC, GND, 3V3, 5V)
- Or dynamically load from power library
- Connect power pins to power nets
- Test complete circuit with power
5. **Testing** (4 hours)
- Create circuit with VCC, GND nets
- Connect multiple components to each net
- Verify net connectivity
- Generate and validate netlist
**Deliverables:**
- Working `add_schematic_net_label` tool
- Working `connect_to_net` tool
- Working `get_net_connections` tool
- Power symbol support
- Netlist generation working
**Success Criteria:**
- User can label nets VCC, GND
- Multiple components connect to same net
- Netlist correctly shows net membership
---
### Phase 3: Advanced Features (Week 2-3)
**Goal:** Professional schematic features
**Tasks:**
1. **Junction Support** (4 hours)
- Detect wire intersections
- Add junction dots at T-junctions
- S-expression: `(junction (at x y) (diameter 0) (uuid ...))`
2. **No-Connect Flags** (2 hours)
- Add "X" marks on unused pins
- S-expression: `(no_connect (at x y) (uuid ...))`
3. **Orthogonal Routing** (6 hours)
- Implement 2-segment wire routing
- Horizontal-then-vertical or vertical-then-horizontal
- Choose best path based on pin positions
4. **Bus Support** (8 hours)
- Multi-bit signal buses
- Bus labels (e.g., "D[0..7]")
- Bus entries for individual signals
5. **Hierarchical Labels** (8 hours)
- Labels for hierarchical sheets
- Input/Output/Bidirectional types
- Sheet connections
**Deliverables:**
- Junction creation
- No-connect support
- Smart orthogonal routing
- Bus and hierarchical label support
**Success Criteria:**
- Wires route cleanly around components
- Junctions appear at wire intersections
- Unused pins marked with no-connect
---
### Phase 4: Validation & Polish (Week 3-4)
**Goal:** Production-ready reliability
**Tasks:**
1. **ERC Integration** (6 hours)
- Electrical Rule Check
- Detect floating nets
- Detect unconnected pins
- Detect short circuits
2. **Visual Validation** (4 hours)
- Export schematic to PDF after wiring
- Verify wire appearance
- Check net label placement
3. **Comprehensive Testing** (8 hours)
- Test with Device library components
- Test with IC components (multi-pin)
- Test with connectors
- Test complex circuits (10+ components)
4. **Error Handling** (4 hours)
- Graceful failures
- Clear error messages
- Validation of coordinates
- Duplicate net label detection
5. **Documentation** (6 hours)
- Update MCP tool descriptions
- Add usage examples to README
- Create wiring tutorial
- Add to CHANGELOG
**Deliverables:**
- ERC validation
- Comprehensive test suite
- Error handling
- Complete documentation
**Success Criteria:**
- 95%+ test pass rate
- Users can create functional circuits
- Clear error messages on failures
---
## Technical Approach
### Option A: Use kicad-skip Native API (Preferred)
**If kicad-skip supports wires natively:**
```python
# Add wire using native API
wire = schematic.wire.new(
start=[100, 100],
end=[200, 100]
)
# Add label
label = schematic.label.new(
text="VCC",
at=[150, 100]
)
```
**Pros:**
- Clean, maintainable code
- Follows library patterns
- Less likely to break
**Cons:**
- Depends on kicad-skip having these features
- May be limited in functionality
### Option B: S-Expression Manipulation (Fallback)
**If kicad-skip doesn't support wires:**
Use the same approach as dynamic symbol loading:
```python
import sexpdata
from sexpdata import Symbol
# Read schematic
with open(schematic_path, 'r') as f:
sch_data = sexpdata.loads(f.read())
# Create wire S-expression
wire_sexp = [
Symbol('wire'),
[Symbol('pts'),
[Symbol('xy'), 100, 100],
[Symbol('xy'), 200, 100]
],
[Symbol('stroke'), [Symbol('width'), 0], [Symbol('type'), Symbol('default')]],
[Symbol('uuid'), str(uuid.uuid4())]
]
# Insert into schematic
sch_data.append(wire_sexp)
# Write back
with open(schematic_path, 'w') as f:
f.write(sexpdata.dumps(sch_data))
```
**Pros:**
- Complete control
- Can implement any feature
- Works around library limitations
**Cons:**
- More complex
- Requires deep KiCad format knowledge
- More maintenance
### Hybrid Approach (Recommended)
1. Try kicad-skip native API first
2. Fall back to S-expression if needed
3. Use S-expression for advanced features (junctions, buses)
---
## Pin Discovery Algorithm
### Step 1: Get Symbol Definition
Symbols are stored in `lib_symbols` section:
```lisp
(lib_symbols
(symbol "Device:R"
(symbol "R_0_1"
(rectangle (start -1 -2.54) (end 1 2.54) ...))
(symbol "R_1_1"
(pin passive line (at 0 3.81 270) (length 1.27)
(name "~" (effects (font (size 1.27 1.27))))
(number "1" (effects (font (size 1.27 1.27)))))
(pin passive line (at 0 -3.81 90) (length 1.27)
(name "~" (effects (font (size 1.27 1.27))))
(number "2" (effects (font (size 1.27 1.27)))))))
```
### Step 2: Extract Pin Information
For each pin:
- Number (e.g., "1", "2")
- Name (e.g., "GND", "VCC", "~" for unnamed)
- Position relative to symbol origin: `(at x y angle)`
- Length (distance from symbol body to connection point)
### Step 3: Get Symbol Instance Position
From symbol instance in schematic:
```lisp
(symbol (lib_id "Device:R") (at 100 100 0) (unit 1)
(property "Reference" "R1" ...))
```
Extract:
- Position: `(at 100 100 0)` = x=100, y=100, rotation=0°
- Reference: "R1"
### Step 4: Calculate Absolute Pin Position
```python
def get_absolute_pin_position(symbol_instance, pin_definition):
# Symbol position
symbol_x, symbol_y, symbol_rotation = symbol_instance.at.value
# Pin position relative to symbol
pin_x, pin_y, pin_angle = pin_definition.at.value
# Apply rotation transformation
if symbol_rotation != 0:
# Rotate pin coordinates around origin
rad = math.radians(symbol_rotation)
rotated_x = pin_x * math.cos(rad) - pin_y * math.sin(rad)
rotated_y = pin_x * math.sin(rad) + pin_y * math.cos(rad)
pin_x, pin_y = rotated_x, rotated_y
# Translate to absolute position
abs_x = symbol_x + pin_x
abs_y = symbol_y + pin_y
return [abs_x, abs_y]
```
---
## Wire Routing Strategies
### Strategy 1: Direct Wire (Phase 1)
Simplest: single wire segment from pin A to pin B.
```
R1 pin 2 C1 pin 1
o-------------o
```
**Pros:** Simple, fast
**Cons:** Diagonal wires (not standard practice)
### Strategy 2: Orthogonal 2-Segment (Phase 3)
Two segments: horizontal then vertical, or vertical then horizontal.
```
R1 pin 2 C1 pin 1
o-----┐
│
└------o
```
**Algorithm:**
1. Calculate midpoint
2. Route horizontal to midpoint
3. Route vertical to target
4. Or vice versa based on direction
**Pros:** Standard practice, cleaner schematics
**Cons:** Slightly more complex
### Strategy 3: Manhattan Routing (Future)
Complex multi-segment paths avoiding components.
**Pros:** Professional appearance
**Cons:** Requires collision detection, path planning
---
## Testing Strategy
### Unit Tests
Test individual functions:
- `test_add_wire()` - Wire creation
- `test_get_pin_location()` - Pin discovery
- `test_add_net_label()` - Label creation
- `test_calculate_pin_position()` - Coordinate math
### Integration Tests
Test complete workflows:
- `test_connect_two_resistors()` - Wire R1 to R2
- `test_connect_to_vcc_net()` - Multiple components to VCC
- `test_generate_netlist()` - Netlist accuracy
- `test_schematic_opens_in_kicad()` - File validity
### Manual Validation
- Create test schematic in KiCad manually
- Add same connections via MCP
- Compare results
- Verify electrical connectivity in KiCad
---
## Success Metrics
### Phase 1 Success:
- [ ] `add_schematic_wire` works (coordinates)
- [ ] `add_schematic_connection` works (pin to pin)
- [ ] Wires appear in KiCad schematic
- [ ] Netlist shows connections
- [ ] 3+ integration tests passing
### Phase 2 Success:
- [ ] Net labels work (VCC, GND, etc.)
- [ ] Multiple components on same net
- [ ] `get_net_connections` returns correct results
- [ ] Netlist includes named nets
- [ ] 5+ integration tests passing
### Phase 3 Success:
- [ ] Junctions at wire intersections
- [ ] Orthogonal routing preferred
- [ ] No-connect flags on unused pins
- [ ] 10+ integration tests passing
### Phase 4 Success:
- [ ] ERC detects errors
- [ ] 95%+ test coverage
- [ ] Complete documentation
- [ ] User can create functional circuits without errors
---
## Risk Assessment
| Risk | Probability | Impact | Mitigation |
|------|------------|--------|------------|
| kicad-skip lacks wire API | High | High | Use S-expression fallback |
| Pin discovery complex | Medium | Medium | Test with multiple symbol types |
| Rotation math errors | Medium | High | Extensive testing, validation |
| Performance issues | Low | Medium | Optimize S-expression parsing |
| KiCad format changes | Low | High | Version detection, compatibility |
---
## Dependencies
**Required:**
- kicad-skip >= 0.1.0 (or compatible)
- sexpdata (already dependency for dynamic loading)
- Python 3.8+
**Optional:**
- KiCad CLI for validation (`kicad-cli sch export netlist`)
---
## Timeline Estimate
**Phase 1:** 1 week (26 hours)
**Phase 2:** 1 week (28 hours)
**Phase 3:** 1.5 weeks (28 hours)
**Phase 4:** 1.5 weeks (28 hours)
**Total:** 5 weeks (110 hours)
**Accelerated path (core features only):** 2-3 weeks (Phases 1-2)
---
## Next Immediate Steps
1. **Research kicad-skip Wire API** (TODAY)
- Test with Python REPL
- Document findings
- Choose implementation approach
2. **Create Test Environment** (TOMORROW)
- Set up test schematic
- Manual wire creation in KiCad
- Export for comparison
3. **Implement Basic Wire** (THIS WEEK)
- Update ConnectionManager.add_wire()
- Test with simple coordinates
- Verify in KiCad
4. **Fix Pin Discovery** (THIS WEEK)
- Parse symbol definitions
- Calculate absolute positions
- Test with rotated symbols
---
## User Communication
**For Issue #26:**
Update users that:
- ✅ Component placement is DONE (with 10,000+ symbols)
- ⏳ Wire/connection tools are IN PROGRESS
- 📅 Estimated completion: 2-3 weeks for core functionality
- 🎯 Goal: Complete functional schematics with wiring
---
**Status:** Ready for implementation
**Owner:** TBD
**Priority:** HIGH (user-blocking feature)