Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# PROJECT KNOWLEDGE BASE

**Generated:** 2026-02-17
**Commit:** 475c468
**Branch:** master

## OVERVIEW

MakerPnP — cross-platform Pick-and-Place machine software for Makers. Pure Rust Cargo workspace (31 crates), using Crux core/shell architecture with egui GUI and CLI frontends.
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation states "31 crates" but the workspace only contains 21 unique crate members according to the root Cargo.toml members list. The actual count is: 6 (common) + 2 (eda) + 2 (gerber) + 1 (pnp) + 10 (planning) = 21 crates. Please update this to reflect the correct number.

Suggested change
MakerPnP — cross-platform Pick-and-Place machine software for Makers. Pure Rust Cargo workspace (31 crates), using Crux core/shell architecture with egui GUI and CLI frontends.
MakerPnP — cross-platform Pick-and-Place machine software for Makers. Pure Rust Cargo workspace (21 crates), using Crux core/shell architecture with egui GUI and CLI frontends.

Copilot uses AI. Check for mistakes.

## STRUCTURE

```
makerpnp/
├── common/ # 6 shared utility crates (see common/AGENTS.md)
├── eda/ # EDA tool integration (eda, eda_units) — DipTrace, KiCad, EasyEDAPro
├── gerber/ # Gerber file handling (gerber, gerber_viewer_egui)
├── pnp/ # Core PnP types (Part, Placement, Package, ObjectPath, LoadOut)
├── planning/ # Assembly planning — 10 crates, largest module (see planning/AGENTS.md)
├── assets/ # Logos, screenshots
├── .github/ # CI workflow (rust.yml)
├── Hacks.md # Documented hack patterns with identifiers
└── KnownIssues.md # Known limitations and workarounds
```

## WHERE TO LOOK

| Task | Location | Notes |
|------|----------|-------|
| Add CLI subcommand | `planning/planner_cli/src/opts.rs` | Uses clap 4.5, add ValueEnum adapters in `common/cli/src/args.rs` |
| Add GUI tab/dialog | `planning/planner_gui_egui/src/` | See `planning/planner_gui_egui/AGENTS.md` |
| Add Crux Event | `planning/planner_app/src/lib.rs` | 70+ events in `Event` enum, handle in `update()` |
| Add EDA tool support | `eda/eda/src/` | Implement parser, add variant to `variantbuilder_cli` |
| Part/Placement types | `pnp/pnp/src/` | Core domain types shared across all crates |
| Planning domain logic | `planning/planning/src/` | Pure domain — no Crux, no I/O |
| Data loading (CSV/file) | `planning/stores/src/` | Aggregates assembly, part_mapper, package_mapper |
| Rule matching | `common/criteria/src/lib.rs` | `FieldCriterion` trait — exact/regex strategies |
| i18n translations | `common/i18n/` + GUI `.ftl` files | Based on egui-i18n + Fluent |
| Gerber rendering | `gerber/` | Uses forked gerber_viewer library |

## ARCHITECTURE

### Crux Core/Shell Pattern

```
User Input → Event → Core.update() → Effect → Shell → Render
↑ ↓
└──────── New Event ───────────────┘
```

- **Core** (`planner_app`, `variantbuilder_app`): Implements `crux_core::App`. Pure functions, no I/O.
- **Shell CLI** (`planner_cli`, `variantbuilder_cli`): `crossbeam-channel` effect loop. Auto-saves on modify.
- **Shell GUI** (`planner_gui_egui`): `PlannerCoreService` wraps Core, converts Effect → PlannerAction for egui.

### Dependency Flow (top → bottom, no cycles)

```
Shells (cli, gui)
→ Crux Cores (planner_app, variantbuilder_app)
→ Domain Support (stores, assembly, part_mapper, package_mapper)
→ Domain Core (planning — pure logic, no I/O)
→ Shared Types (pnp, eda, gerber, common/*)
```

### 4 Executables

| Binary | Crate | Purpose |
|--------|-------|---------|
| `planner_gui_egui` | `planning/planner_gui_egui` | GUI planner (egui + eframe) |
| `planner_cli` | `planning/planner_cli` | CLI planner (same Crux core) |
| `variantbuilder_cli` | `planning/variantbuilder_cli` | EDA → normalized placements |
| `gerber_viewer_egui` | `gerber/gerber_viewer_egui` | Standalone Gerber viewer |

## CONVENTIONS

- **Formatting**: `cargo +nightly fmt` — max_width=120, chain_width=40, struct_lit_single_line=false, group_imports=StdExternalCrate
- **Workspace deps**: ALL versions centralized in root `Cargo.toml` `[workspace.dependencies]`. Crates reference via `{ workspace = true }`.
- **Fork deps**: egui, egui_taffy, egui_ltreeview, egui_deferred_table, gerber_viewer — all forked under MakerPnP GitHub org with specific revs.
- **Resolver v2**: Required due to `testing` feature flag on dev-dependencies.
- **CLI adapters**: Internal types → `*Arg` enums in `common/cli/src/args.rs` via `From/Into`.
- **Test frameworks**: `rstest` (parameterized), `assert_cmd` + `assert_fs` (CLI integration).
- **Test data builders**: Builder pattern in `tests/common/` — `TestProject`, CSV builders.
- **Hack documentation**: Document hacks in `Hacks.md` with identifier comment (e.g. `HACK: table-resize-hack`), not scattered TODOs.

## ANTI-PATTERNS (THIS PROJECT)

- **No `as any` / `@ts-ignore` equivalent**: Do not suppress type errors.
- **No scattered TODO/FIXME**: Use `Hacks.md` and `KnownIssues.md` for tracking.
- **GUI must run from source dir**: GUI executables require relative asset paths — run from crate directory.
- **Don't float data-table tabs in debug mode**: Causes panic (egui_dock bug #278).
- **Single task active**: Only one phase task should be started/incomplete at a time.
- **PCB changes require project reload**: Save project → close → edit PCB → reopen.

## COMMANDS

```bash
# Build
cargo build --release

# Test
cargo test --verbose

# Format (requires nightly)
cargo +nightly fmt

# Run GUI (from crate dir)
cd planning/planner_gui_egui && ../../target/release/planner_gui_egui

# Run CLI
./target/release/planner_cli --help
./target/release/variantbuilder_cli --help
```

## NOTES

- **CI**: GitHub Actions on push/PR to master. Ubuntu. Needs `libdbus-1-dev`.
- **Edition mix**: Most crates use 2021, newer GUI crates use 2024.
- **Gerber crates tightly coupled**: gerber_viewer, gerber-types, gerber_parser — ensure only one of each in dependency tree.
- **chrono over time**: Project chose chrono (13k dependents) over time crate (3k dependents).
- **License**: TBD (likely GPL3, Apache, or MIT).
47 changes: 47 additions & 0 deletions common/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# COMMON UTILITIES

**Parent:** [Root AGENTS.md](../AGENTS.md)

## OVERVIEW

6 shared utility crates — foundational types and helpers used across all domain crates.

## STRUCTURE

```
common/
├── args/ # Primitive argument type (`Arg` enum: Boolean, String, Integer) for i18n
├── cli/ # CLI utilities: clap parsers, tracing setup, internal→CLI type adapters
├── criteria/ # Rule matching engine: `FieldCriterion` trait, ExactMatch + RegexMatch strategies
├── i18n/ # Fluent-based i18n: loads .ftl translations, wraps egui_i18n
├── math/ # Numeric utilities: angle, decimal, ratio, math operations
└── util/ # Core utilities: Source enum, sorting, path helpers, dynamic typing, assertions
```

## WHERE TO LOOK

| Task | Crate | Key File | Notes |
|------|-------|----------|-------|
| Add rule matching strategy | `criteria` | `src/lib.rs` | Implement `FieldCriterion` trait — used by `part_mapper` & `package_mapper` |
| Add CLI arg type adapter | `cli` | `src/args.rs` | Internal domain types → `*Arg` enums (clap ValueEnum) |
| Add CLI parser | `cli` | `src/parsers.rs` | Clap argument parsers |
| Configure tracing | `cli` | `src/tracing.rs` | Behind `tracing` feature flag |
| Add math operation | `math` | `src/ops.rs`, `src/angle.rs` | Angle/decimal/ratio math |
| Add file source type | `util` | `src/source.rs` | `Source` enum — file/URL abstraction |
| Add sorting helper | `util` | `src/sorting.rs` | `SortOrder` enum |
| Add dynamic typing | `util` | `src/dynamic/` | `AsAny` + `DynamicEq` traits — enables trait object equality |
| Add test utility | `util` | `src/test/` | Behind `testing` feature flag |
| Add i18n translation | `i18n` | `src/lib.rs` | Loads Fluent `.ftl` files, wraps `egui_i18n` |
| Add i18n argument type | `args` | `src/lib.rs` | `Arg` enum for Fluent argument conversion |

## CONVENTIONS

- **`testing` feature**: `util/src/test/` gated behind `#[cfg(any(test, feature = "testing"))]` — prevents test utilities from polluting release builds.
- **Dynamic equality**: `criteria` uses `AsAny` + `DynamicEq` from `util/dynamic/` for trait object equality (`dyn FieldCriterion`).
- **i18n feature flags**: `i18n` has `json` and `args` features for different Fluent argument conversion strategies.
- **Edition mix**: `i18n`, `math`, `args` use Rust edition 2024; `cli`, `criteria`, `util` use 2021.

## ANTI-PATTERNS

- Do NOT add domain-specific logic here — these crates are cross-cutting utilities only.
- Do NOT bypass `FieldCriterion` trait for rule matching — always implement the trait interface.
65 changes: 65 additions & 0 deletions planning/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# PLANNING MODULE

**Parent:** [Root AGENTS.md](../AGENTS.md)

## OVERVIEW

Assembly planning — 10 crates implementing the Crux core/shell architecture for PCB assembly job management.

## STRUCTURE

```
planning/
├── planning/ # Pure domain logic (Project, Phase, Process, Placement) — NO Crux, NO I/O
├── planner_app/ # Crux Core — implements crux_core::App, 70+ Events, Model, Effects
├── planner_cli/ # Crux Shell (CLI) — crossbeam-channel effect loop, auto-save
├── planner_gui_egui/ # Crux Shell (GUI) — egui frontend (see planner_gui_egui/AGENTS.md)
├── variantbuilder_app/ # Crux Core — EDA file normalization (separate from planner)
├── variantbuilder_cli/ # Crux Shell (CLI) — DipTrace/KiCad/EasyEDAPro → normalized placements
├── stores/ # Data source abstraction — CSV/file loading, aggregates assembly+mappers
├── assembly/ # Assembly variant processing — filters placements by variant rules
├── part_mapper/ # Part mapping rules engine — matches parts via criteria
└── package_mapper/ # Package mapping rules engine — matches packages via criteria
```

## WHERE TO LOOK

| Task | Location | Notes |
|------|----------|-------|
| Add new Event | `planner_app/src/lib.rs` | Add variant to `Event` enum + handle in `update()` |
| Add CLI subcommand | `planner_cli/src/opts.rs` (719 lines) | Clap derive, map to Event in `main.rs` |
| Add project domain logic | `planning/src/project.rs` (2722 lines) | Pure logic — `Project` struct methods |
| Add new Phase/Process behavior | `planning/src/phase.rs`, `planning/src/process.rs` | State machine transitions |
| Add data source | `stores/src/` | Implement loader, register in stores aggregator |
| Add part/package mapping rule | `part_mapper/src/`, `package_mapper/src/` | Uses `criteria` crate for matching |
| Add EDA tool support | `variantbuilder_app/src/lib.rs` + `variantbuilder_cli/` | Add parser in `eda/`, wire through app |
| Placement sorting | `planning/src/placement.rs` | `PlacementSortingItem`, `PlacementSortingMode` |

## DEPENDENCY FLOW

```
Shells (planner_cli, planner_gui_egui, variantbuilder_cli)
→ Cores (planner_app, variantbuilder_app)
→ stores
→ assembly, part_mapper, package_mapper
→ planning (pure domain)
→ pnp, eda, common/*
```

No cycles. All dependencies flow downward.

## CONVENTIONS

- **Crux pattern**: Core is pure — all side effects via `Effect` enum, handled by Shell.
- **CLI auto-save**: Shell checks `view.project_modified` / `view.pcbs_modified` after every Render effect.
- **Sequence tests**: `planner_cli/tests/planner.rs` (4324 lines) — uses static mutex + sequence numbering for ordered test execution.
- **Test builders**: `tests/common/` — `TestProject`, `LoadOutCSVBuilder`, `PhasePlacementsCSVBuilder` etc.
- **ObjectPath**: Unified locator format `/pcb_instance/pcb_unit/ref_des` (e.g. `/1/2/R1`).
- **Process state machine**: Process → Operations → Tasks, three-level status tracking.
- **`testing` feature flag**: Dev-dependencies use `features = ["testing"]` to avoid polluting release builds.

## ANTI-PATTERNS

- Do NOT add I/O to `planning/` crate — it must stay pure domain logic.
- Do NOT handle `Effect::ProjectView` / `Effect::PcbView` in CLI shell — only GUI uses those.
- Do NOT start multiple phase tasks simultaneously — only one should be active.
75 changes: 75 additions & 0 deletions planning/planner_gui_egui/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# PLANNER GUI (egui)

**Parent:** [Planning AGENTS.md](../AGENTS.md)

## OVERVIEW

egui/eframe GUI shell for the Planner Crux core — 65 source files, largest frontend in the project.

## STRUCTURE

```
planner_gui_egui/src/
├── main.rs # Entry point — eframe::run_native, i18n init, profiling setup
├── lib.rs # Module declarations
├── ui_app.rs (940 lines) # Root app state — manages projects, pcbs, tabs, toolbar
├── planner_app_core.rs # PlannerCoreService — wraps Crux Core, Effect → PlannerAction
├── config.rs # Persistent app configuration (JSON)
├── command.rs # Command pattern for UI actions
├── ui_app/
│ └── app_tabs/ # Top-level tab types (home, new_project, new_pcb, project, pcb)
├── project/
│ ├── mod.rs (2995 lines)# Project view — largest file, orchestrates all project tabs
│ ├── toolbar.rs # Project-specific toolbar
│ ├── process.rs # Process management UI
│ ├── tabs/ # 9 tabs: overview, explorer, pcb, unit_assignments, parts,
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment states "9 tabs" but then lists 10 tabs (overview, explorer, pcb, unit_assignments, parts, load_out, placements, phase, process, issues), which matches the actual number of tab files in the project/tabs/ directory. Please correct "9 tabs" to "10 tabs".

Suggested change
│ ├── tabs/ # 9 tabs: overview, explorer, pcb, unit_assignments, parts,
│ ├── tabs/ # 10 tabs: overview, explorer, pcb, unit_assignments, parts,

Copilot uses AI. Check for mistakes.
│ │ # load_out, placements, phase, process, issues
│ ├── tables/ # Data tables: placements, parts, load_out
│ └── dialogs/ # Dialogs: add_phase, placement_orderings, package_sources, errors
├── pcb/
│ ├── mod.rs (1190 lines)# PCB editor view
│ └── tabs/ # panel, configuration, gerber_viewer, explorer
├── ui_components/ # Reusable UI components (gerber_viewer_ui)
├── widgets/ # Custom widgets (list_box, augmented_list_selector)
├── dialogs/ # App-level dialogs (manage_gerbers)
├── forms/ # Form validation utilities
├── filter/ # Data filtering logic
├── i18n/ # GUI-specific i18n conversions
├── runtime/ # Async runtime (tokio_runtime, legacy_runtime)
├── task/ # Background task management
├── fonts.rs # Font configuration
├── profiling.rs # puffin profiling integration
├── tabs.rs # Tab trait and egui_dock integration
├── toolbar.rs # Shared toolbar components
├── file_picker.rs # File dialog integration (rfd)
└── ui_util.rs # UI helper functions
```

## WHERE TO LOOK

| Task | Location | Notes |
|------|----------|-------|
| Add project tab | `project/tabs/` | Create `*_tab.rs`, register in `project/mod.rs` |
| Add PCB editor tab | `pcb/tabs/` | Create `*_tab.rs`, register in `pcb/mod.rs` |
| Add data table | `project/tables/` | Uses `egui_deferred_table` (forked) |
| Add dialog | `project/dialogs/` or `dialogs/` | Project-scoped vs app-scoped |
| Add toolbar button | `project/toolbar.rs` or `toolbar.rs` | Project vs app level |
| Modify Crux integration | `planner_app_core.rs` | Effect → PlannerAction mapping |
| Add widget | `widgets/` | Reusable across views |
| Change app layout | `ui_app.rs` | egui_dock tab management |
| Add i18n key | `i18n/conversions.rs` + `.ftl` files | Fluent format |
| Background async work | `runtime/`, `task/` | tokio-based |

## CONVENTIONS

- **Effect handling**: `PlannerCoreService.update(event)` returns `Vec<PlannerAction>` — caller processes actions sequentially.
- **Tab system**: Uses `egui_dock` for dockable/floatable tabs. Each tab implements a trait.
- **Large view files**: `project/mod.rs` (2995 lines) and `pcb/mod.rs` (1190 lines) orchestrate their respective views — read these first when understanding UI flow.
- **Edition 2024**: This crate uses Rust edition 2024 (newer than most crates in workspace).
- **Assets required**: Must run from crate directory — logos and i18n `.ftl` files loaded via relative paths.

## ANTI-PATTERNS

- Do NOT float tabs containing data tables in debug mode — causes panic (egui_dock #278).
- Do NOT add business logic here — belongs in `planner_app` (Crux Core) or `planning` (domain).
- Do NOT bypass `PlannerCoreService` — all state changes go through Crux Events.
Loading