FiberCAD builds on lessons from a prior CAD patch pipeline (mattganzak/cad, 22,700 LOC) that took a fundamentally different approach — editing existing drawings rather than generating new designs. FiberCAD then started as a vision for a full cloud-native GIS platform, evolved through four major architectural pivots driven by timeline constraints, domain expertise extraction, and rigorous architecture review. The result is a focused design generator that complements the prior patch system and outperforms the original scope on every dimension that matters to the customer.
mattganzak/cad)Before FiberCAD, a separate system was built to automate fiber design work. This system (mattganzak/cad, 22,700 LOC across 3 modules) took a fundamentally different approach: patching existing drawings rather than generating new designs from scratch.
Existing DWG ──► C# AutoCAD Plugin ──► JSON Snapshot ──► LLM (DeepSeek)
(EXPORTDWGFULLJSON) │
Design Understanding
Edit Brief
Patch JSON
│
◄─────┘
Validated Patch ──► C# Plugin ──► Updated DWG ──► Integrity Check
(APPLYJSONPATCH)
| Phase | Action | Output |
|---|---|---|
| Phase 1 | Create working DWG from template + polygon | original/working.dwg |
| Phase 2 | Export full CAD snapshot via C# plugin | design_snapshot.json |
| Phase 3 | Build protection baseline (buildings, parcels, roads locked) | protected_geometry_baseline.json |
| Phase 5 | LLM generates understanding → brief → patch JSON | design_patch.json |
| Phase 4 | Validate patch ops against protection rules | patch_validation.json |
| Phase 6 | Apply patch to DWG, re-export, verify integrity | updated.dwg |
| Module | LOC | Purpose |
|---|---|---|
cad_automation/ | ~8,000 | Core pipeline: run.py, phase5_iterate.py, phase6_apply.py, LLM prompts, protection baseline, QA loop |
backend/ | ~6,000 | FastAPI web server: auth (JWT), Celery task queue, PostgreSQL, Docker compose, job submission API |
demo/ | ~5,000 | Prototyping: Ollama experiments, routing MVP, client rules registry, JSON design format exploration |
frontend/ | skeleton | React/Next.js (not implemented) |
| Limitation | Impact |
|---|---|
| Requires Windows + AutoCAD at runtime | Cannot run on Linux/Mac, cannot run in CI, cannot demo without AutoCAD license |
| LLM is the core intelligence | DeepSeek generates patches; when it hallucinates targets or drifts off-domain, the system falls back to constrained recovery. Direct patch generation "not consistently strong enough yet" |
| Patch scale limited | Best proven output: 4-edit review bundle. "Current client-style output is still much smaller than a real large production patch set" |
| No network planning | Cannot generate boundary groups, splitter placement, conduit routing, or BOM. Assumes someone already designed the network. |
| No design validation | No rules engine checking conduit length, drop count, splitter separation. Validates patch ops, not design correctness. |
| No GIS data acquisition | Cannot fetch building footprints, roads, or addresses from OSM. Relies on pre-existing DWG content. |
The project started with a research phase: codebase review (14 AutoLISP scripts, Lumos V6 standards, Hampton Heights project files, 2.1GB training videos) and competitive analysis (3-GIS, VETRO FiberMap, IQGeo/Comsof, FibPlanner, OSPInsight). The initial architecture was designed as a full-scale 3-GIS replacement:
WEB CLIENT
Map Canvas (MapLibre GL) + Design Canvas (Fabric.js)
Real-time collaboration (WebSocket)
|
API LAYER
REST + WebSocket + File I/O (DWG/PDF/GeoJSON)
| | | | | |
GIS Graph Rule Doc LLM Equipment
Engine Engine Engine Gen Agent Catalog
|
PostGIS DB
(Spatial + Network)
| Layer | Technology | Scope |
|---|---|---|
| Frontend | React + MapLibre GL JS + Fabric.js/Konva | Map canvas + CAD-like drawing surface |
| Backend | Python (FastAPI) or Go | REST API + WebSocket server |
| Database | PostgreSQL + PostGIS | Spatial queries, network topology storage |
| LLM | Claude API (Anthropic) | Design agent, QC review, documentation |
| File I/O | Open Design Alliance SDK | DWG read/write (requires ODA licensing) |
| Real-time | WebSocket (Socket.io) | Multi-user collaborative editing |
| Hosting | AWS/GCP with containers | Managed PostGIS, compute for LLM pipelines |
| Mobile | React Native or PWA | Field crew markup and as-built updates |
The build sequence was planned across 5 phases over several months:
With the 3-day deadline established, the cloud platform was scoped down to a Python CLI engine (Approach C from brainstorming: engine + DXF output + HTML map report). This was the first working Python architecture:
fibercad/
├── cli.py # argparse entry point
├── ingest/
│ ├── osm.py # Overpass API fetch
│ ├── geocode.py # Nominatim geocoding
│ └── importers.py # CSV/GeoJSON loaders
├── model/
│ ├── network.py # Road graph + Dijkstra
│ ├── elements.py # Equipment dataclasses
│ ├── geometry.py # haversine, snap, centroid
│ └── schema.py # Single FiberJSON schema
├── planning/
│ ├── boundary_groups.py # Clustering algorithm
│ ├── splitter_placement.py # 1x8/1x4 placement
│ ├── routing.py # Conduit routing
│ └── optimizer.py # Cost optimization
├── rules/
│ ├── engine.py # Rule checker
│ └── profiles/lumos_v6.py # 12 rules from standards doc
├── output/
│ ├── fiberjson.py # JSON serializer (SHA-256 only)
│ ├── dxf.py # DXF with primitive shapes
│ ├── report_html.py # Simple Leaflet map
│ └── workbook.py # BOM Excel
└── llm/
├── client.py # Claude API client
└── design_review.py # LLM sends/receives raw data
| Gap | Risk |
|---|---|
| No microkernel / plugin dispatch | Modules tightly coupled, hard to extend |
| No security module | OSM input unsanitized, prompt injection possible |
| No integrity chain | No tamper detection, no audit trail |
| No rate limiter | Nominatim bans at >1 req/sec |
| No checkpoint/resume | 10K-address geocoding crashes = restart from zero |
| No baremetal tools | LLM processes raw geometry (slow, unreliable, expensive) |
| No planning orchestration layer | CLI directly calls algorithms (no separation of concerns) |
| No sanity checks | Degenerate outputs (zero-address groups, disconnected roads) go undetected |
| No standalone verifier | Third-party can't audit without installing FiberCAD |
| Only 12 rules | Missing 9 critical rules that lived in tribal knowledge (videos) |
| Generic DXF shapes | Output doesn't match what designers expect in AutoCAD |
Two things then happened that transformed this into the final architecture:
The architecture review (informed by the Rapsody sister project's microkernel patterns) restructured the codebase from a flat script collection into a layered, production-grade engine.
| Component | Purpose | Pattern Source |
|---|---|---|
kernel/plugin.py | Dispatch chain (Handled/NotHandled) | Chain of responsibility |
kernel/http.py | Testable, swappable HTTP backend | Strategy pattern |
kernel/errors.py | Typed errors with exit codes + guidance | Error hierarchy |
kernel/security.py | Input sanitization, injection defense, secret redaction | Input filter chain |
kernel/rate_limiter.py | Token bucket for API rate limits | Token bucket |
kernel/checkpoint.py | Resume batch operations after crash | Checkpoint/resume |
kernel/keys.py | Ed25519 keypair management (mode 0600) | Trust-on-first-use |
tools/*.py | 7 MCP-compatible deterministic tools | Tool-use protocol |
verify/fibercad_verify.py | Standalone integrity verifier (no deps) | Independent audit |
planning/service.py | Orchestration layer for both CLI and LLM paths | Service layer |
planning/sanity.py | Post-planning degenerate output detection | Defensive checks |
Single monolithic JSON file containing the entire network design — addresses, GIS data, topology, physical layout, and validation results in one blob.
{
"type": "FiberNetwork",
"network": {
"elements": [...],
"boundary_groups": [...],
"addresses": [...]
},
"validation": { ... }
}
Five separate layer files, each building on the previous, with SHA-256 hashes and Ed25519 signatures forming an integrity chain.
L0_input.fiberjson (what we're given) L1_gis.fiberjson (what exists there) L2_topology.fiberjson (network decisions) L3_physical.fiberjson (placed on ground) L4_compliance.fiberjson (validated)
| Property | Monolithic | Layered |
|---|---|---|
| Selective regeneration | Impossible — regenerate everything | Change one layer, keep others |
| Provenance tracking | None — all data mixed | Each layer cites its input + hash |
| Integrity verification | One hash for entire file | Chain of hashes + signatures |
| File size per operation | Read/write entire blob every time | Touch only the layer you need |
| Algorithm versioning | One version for everything | Per-layer algorithm versions |
LLM as the primary intelligence layer — send network data to Claude, get back design decisions, optimization suggestions, and documentation.
Baremetal deterministic tools as the intelligence layer. LLM is an optional review advisor that calls tools — never processes raw data or makes final decisions.
"BG-03: 34 homes, 2847 ft conduit, 0 violations" (~30 tokens) instead of 3,000 tokens of GeoJSON coordinates.| Operation | LLM-First | Tools-First |
|---|---|---|
| Measure distance | ~200 tokens + inference latency | haversine_ft() in microseconds |
| Validate design | Send entire design + rules as prompt | Deterministic rule engine, exact results |
| Count homes in area | Parse GeoJSON, count, risk hallucination | Spatial index query, O(log n) |
| Verify integrity | Cannot verify cryptographic signatures | verify_chain() — exact math |
| API down? | System broken | System works fine, just no review |
Five training videos (2.1 GB, 3,115 lines of transcription) were processed via speech-to-text. The extracted domain knowledge changed the rules engine significantly.
| Rule | Source | Impact |
|---|---|---|
| 1x4 and 1x8 cannot share a handhole | 1x4 & 1x8 Explanation [8:30], CAD Training [33:52] | Splitter placement algorithm was generating invalid designs |
| Two-tier run length: 500ft warning, 650ft error | HLD Part 1 [61:06] | Previous rule was binary 500ft — missed the exception allowance |
| Handhole sizing: MED for 1x8, SM for 3-way, SPLT for 1x4 | HLD Part 1 [24:01], CAD Training [39:20] | All handholes were generic HH — wrong for construction |
| 150ft bend rule | HLD Part 1 [50:41] | Was placing handholes at every bend unnecessarily |
| Fiber numbering from back (highest first) | 1x4 & 1x8 Explanation [18:07], LLD [1:28] | Required for correct LLD fiber assignment |
| Feeder/secondary ribbon separation | LLD [25:17] | Required for correct splice diagrams |
| Cul-de-sac routing prohibition | HLD Part 2 [14:27] | Routing algorithm was circumnavigating dead-ends |
| Max 2 same-type splitters per handhole | CAD Training [34:03], 1x4 & 1x8 [19:58] | Was overpacking handholes |
| Cable naming convention | LLD [1:41-2:17] | Required for correct callout annotations |
12 rules from the written Lumos V6 standards document.
18 rules total (15 implemented, 3 planned). Plus complete naming conventions, equipment specs, handhole sizing matrix, and cable structure documentation.
A formal architecture review against the Rapsody sister project's patterns identified 21 specific findings across 5 dimensions. The key additions that resulted:
| Finding | What Was Added | Why It Matters |
|---|---|---|
| No circuit breaker for OSM API | kernel/circuit_breaker.py (planned) | Prevents hammering a flapping API with 10K geocoding requests |
| No checkpoint/resume | kernel/checkpoint.py | 30-min geocoding job can resume after crash instead of restarting |
| No rate limiting | kernel/rate_limiter.py | Nominatim enforces 1 req/sec — violating gets you banned |
| GIS input unsanitized | kernel/security.py | OSM is publicly editable — attacker can inject path traversal in street names |
| No prompt injection defense | strip_prompt_injection() at dispatch | Tool results flowing to LLM context need sanitization |
| Two registries for same concept | Merged into dispatch chain pattern | One dispatch system, not two competing registries |
| Layer corruption unhandled | Typed verification results per layer | Standalone verifier distinguishes hash mismatch vs signature failure vs missing file |
| LLM suggestions in signed layers | Ephemeral-only policy | Audit trail must record tool decisions, not LLM suggestions |
| No standalone verifier | verify/fibercad_verify.py | Third-party auditor can verify chain without installing FiberCAD |
The DXF output initially used primitive shapes (squares for handholes, circles for loops). By extracting the real Lumos template blocks from the project DWG files, the output now uses production-standard symbols.
| Element | Before | After |
|---|---|---|
| Handholes | Small square | TELCO HANDHOLE_V2 block (10 entities) |
| 1x4 Splitters | Triangle | 1X4 SPLITTER_MODEL block (9 entities) |
| 1x8 Splitters | Triangle | 1X8 SPLITTER_MODEL block (9 entities) |
| Splices | Cross (two lines) | FIBER_SPLICE block (3 entities) |
| Slack Loops | Circle | SLACK_LOOP_MODEL block (3 entities) |
| Layers | 14 generic layers | 81 Lumos-standard layers imported |
| Text Styles | Standard only | 23 Lumos text styles (FTTH, CALLOUT, LOOP, ROMANS, etc.) |
libredwg from source to convert the Lumos template DWG to DXF. Stripped WIPEOUT entities (AutoCAD-proprietary masking) that caused compatibility issues. Result: clean block library that AutoCAD opens without errors.
| Capability | Status | Detail |
|---|---|---|
| OSM data ingestion | Shipping | Buildings, roads, addresses from any bounding box |
| CSV address import | Shipping | --csv flag on CLI |
| Boundary group planning | Shipping | Constrained geographic clustering, ~32 homes per group |
| Splitter placement | Shipping | Two-stage 1x8/1x4 hierarchy with separation enforcement |
| Conduit routing | Shipping | MST on road network with auto handhole insertion at 500ft |
| Rules engine (15 rules) | Shipping | Lumos V6 profile with video-derived rules |
| Ed25519 integrity chain | Shipping | Signed layers, key management, standalone verifier |
| DXF with Lumos blocks | Shipping | 33 blocks, 81 layers, 23 text styles from template |
| HTML map report | Shipping | Tabbed: Map (3 basemaps, layer controls) + Stats + BOM + Network Graph + Violations |
| DXF viewer | Shipping | SVG vector rendering, pan/zoom, collapsible sidebar |
| BOM workbook | Shipping | 5-sheet Excel: Summary, Equipment, Conduit, Groups, Addresses |
| MCP tools (7 tools) | Shipping | project_summary, validate_design, measure_distance, etc. |
| LLM design review | Shipping | Claude tool_use agent with fallback mode |
| Rate limiter + checkpoint | Shipping | Token bucket + resumable batch operations |
| Security module | Shipping | Path sanitization, prompt injection defense, secret redaction |
| 150ft bend rule | Shipping | From video analysis |
| Cul-de-sac routing | Planned (Week 2) | Routing heuristic for dead-end streets |
| Fiber strand assignment | Planned (Week 2) | LLD-level fiber numbering from back |
| Splice diagrams | Planned (Week 2) | From network graph + fiber assignments |
| Multiple provider profiles | Planned (Week 2) | Pluggable standards beyond Lumos |
| Rust port | Planned (future) | Architecture designed for migration |