Files
OpenNest/AGENTS.md
T
ajandClaude Opus 5.5 81ec6a8125 feat(server): list, reopen and keep server nest jobs once
A server Auto Nest result could only be reviewed in the session that sent it,
and nothing stopped two desktops from keeping the same result. Phase 3 adds
My Server Jobs, so results that finished while OpenNest was closed are easy
to find, and records each review on the server.

- Server: GET /api/nest-jobs lists jobs newest first with state, engine,
  submitter, times, queue position, review and the worker's summary (parts,
  sheets, utilization, unplaced). It filters to active, finished or
  unreviewed jobs and to a submitter (a bare user name matches that user on
  any workstation). An ETag turns unchanged polls into 304s. Schema v17 adds
  nestId, review and summary columns, only where missing.
- Keep once: POST .../keep and .../discard take If-Match on the job revision
  and change an unreviewed result only once. A second desktop gets 409 with
  who kept it. DELETE removes finished jobs. A succeeded job keeps its
  package until it is reviewed, so a later session can rebuild the job.
- Retention: OPENNEST_JOB_RETENTION_DAYS (default 7) deletes finished jobs
  with their results. It runs on claims and list reads. A malformed value
  fails startup instead of deleting results early.
- Worker: reports the result's summary with the transcript. A job cancelled
  while its result arrived keeps no summary (found in the Docker smoke run).
- Desktop: Nest > My Server Jobs polls the list every 3 s; polling rather
  than per-job SSE because the list must show other desktops' jobs and
  removals. Open rebuilds the job from job.json against the open nest's own
  drawings. New per-drawing geometry fingerprints make the freshness check
  work across sessions. Cancel Job and Remove act on the selected job. A
  status-bar item counts this user's results waiting for review; there is
  no popup. Auto Nest's review now records Keep on the server before it
  commits, and records Discard too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 13:18:11 -05:00

14 KiB

OpenNest agent instructions

Shared instructions; keep CLAUDE.md as the thin @AGENTS.md import. OpenNest is a .NET 8 Windows CNC-nesting application with cross-platform libraries.

Working rules

  • Prefer Roslyn Bridge MCP for symbols, references and diagnostics when available; fall back to text search.
  • Use var for locals and namespaces matching project directories. Follow .editorconfig; format only changed C# files with dotnet format OpenNest.sln --include <paths>, then repeat with --verify-no-changes. On Linux, prefix both commands with EnableWindowsTargeting=true.
  • Keep instructions concise: commands, boundaries and non-obvious safeguards, not class inventories or session history. Update affected instructions and user-facing docs with behavior/build changes; put detailed contracts in docs/. User guides and their screenshots live in the separate ajisaacs/opennest-help repo: update or recapture them when a UI change alters a documented screen, and never rename a HelpTopics ID.
  • Never commit design specs, implementation plans, progress notes or temporary benchmark reports. Keep working records under local, ignored .hermes/plans/ or .hermes/progress/; retain reusable verification procedures in docs/.
  • Keep vendor manuals/full-text extracts out of source control unless redistribution is authorized. Write project-specific behavior summaries with citations, separating controller rules, machine macros and unconfirmed behavior.

Build and test

# Full solution: Windows
dotnet build OpenNest.sln

# Cross-platform suites: run independently on Linux/macOS/Windows
# Use Release for routine runs; use Debug explicitly for DEBUG-only work counters.
dotnet test OpenNest.Tests/OpenNest.Tests.csproj -c Release
dotnet test OpenNest.Engine.Tests/OpenNest.Engine.Tests.csproj -c Release
dotnet test OpenNest.IO.Tests/OpenNest.IO.Tests.csproj -c Release
dotnet test OpenNest.Desktop.Tests/OpenNest.Desktop.Tests.csproj -c Release
dotnet test OpenNest.Server.Tests/OpenNest.Server.Tests.csproj -c Release
dotnet test OpenNest.FrontEnd.Tests/OpenNest.FrontEnd.Tests.csproj -c Release

# Windows runtime tests
dotnet test OpenNest.WinForms.Tests/OpenNest.WinForms.Tests.csproj

On Windows, prefer scripts/Test-Hidden.ps1 <dotnet test args> for WinForms tests: it runs them on a hidden desktop so no windows appear or take focus; see hidden-desktop tests.

Only Plan Cutting changes need the problem-nest corpus (Category=ProblemNests, opt-in via OPENNEST_PROBLEM_NESTS_SERVER); never run it for nesting engines, fills, UI, posts or file formats. Limit it to the areas the change touches with OPENNEST_PROBLEM_NESTS_CHECKS (table in that doc); part-order and entries plan every nest. No plate may rank below its baseline, and none may join or climb the near-budget list compared with master's run. Keep desktop-dependent tests in OpenNest.WinForms.Tests, never add a WinForms reference to OpenNest.Tests. Optional CHR fixtures use local OpenNest.Tests/test-config.json and skip when absent. On Linux, build Windows projects with -p:EnableWindowsTargeting=true; this is not Windows runtime verification. The headless console builds independently with dotnet build OpenNest.Console/OpenNest.Console.csproj.

Releases: follow the release procedure and scripts/Publish-Windows.ps1; workflow artifacts are candidates, not published releases. GitHub (ajisaacs/OpenNest) is the primary repository; Gitea is a read-only backup mirror.

Project map and boundaries

  • OpenNest.Core: domain (Nest -> Plate -> Part -> Drawing -> CNC.Program), geometry, cutting strategies and diagnostics. Angles are radians; use Tolerance.Epsilon for geometry comparisons. OpenNest.Math shadows System.Math, so qualify the latter.
  • OpenNest.Engine: whole-job API in Jobs/, interactive proposals via PlateFillService, fill strategies, best-fit pairs, packing, sequencing and rapid planning. INestingEngine.Solve(NestJob) returns stock IDs/poses; boundary adapters map drawings and materialize results. NestJobRunner validates its candidates before committing demand/stock accounting. Do not assume arbitrary plug-in output or interactive paths received that validation. Job identity is reference-based, not drawing-name-based.
  • Built-in whole-job engines live in OpenNest.Engine/NestingEngines/<Name>/, named for the jobs they suit; see nesting engines. A change must beat that engine's current benchmark result with every layout valid. External plug-ins implement INestingEngine with a public parameterless constructor and load from Engines/ beside the host; keep their projects out of this solution.
  • OpenNest.IO: ACadSharp and SVG import/export and ZIP-based .nest persistence; depends on Core only (an IO.Tests guard enforces it). Best fits persist only when callers pass BestFitCacheStore.Shared as NestReader/NestWriter.BestFitStore. All DXF-to-Drawing conversion goes through CadImporter: Import + BuildDrawing for editable/reporting flows, ImportDrawing for headless callers. Preserve source offsets, entity IDs, suppressed entities and bends. Bend repair is opt-in, requires explicit source units and may not alter cut geometry or unrelated marks.
  • OpenNest: WinForms UI (Forms/, Controls/PlateView, Actions/). OpenNest.Data holds cross-platform persistence; new-nest defaults live in %APPDATA%\OpenNest\defaults.json (in Database mode, the server's shared copy once it holds one). WinForms Properties.Settings persist to %APPDATA%\OpenNest\user-settings.json through AppDataSettingsProvider, never inside the Velopack install folder; OpenNest.WinForms.Tests redirects them to a temp file, so a test run never writes the user's settings. Posts live in Posts/OpenNest.Posts.<Name>/ and deploy to the desktop output's Posts/ directory. Desktop nest edits go through BeginChange/RecordChange; see undo and redo.
  • OpenNest.Desktop (net8.0): toolkit-neutral desktop logic shared by the WinForms app and OpenNest.Avalonia, the cross-platform desktop in progress. It must not reference WinForms/WindowsDesktop, System.Drawing.Common or Avalonia (OpenNest.Desktop.Tests guards this, including transitive packages); put toolkit-specific rendering, dialogs and settings behind adapters in the front ends.
  • OpenNest.Server: nest storage HTTP service, kept off Engine and IO. OpenNest.Server.Worker: the server nesting worker, shipped in the same image.
  • OpenNest.Console, OpenNest.Mcp, OpenNest.Api: front ends; OpenNest.Benchmark: whole-job engine comparisons; OpenNest.Gpu: GPU evaluators; OpenNest.Training: ML data collection and the Python sketch-search prototype (sketch-search/README.md). Benchmark timing comparisons require --parallel 1; validate layouts and fulfillment, not just elapsed time.

Geometry and ownership safeguards

  • Marks are not material: use SpecialLayers.IsMaterial when deriving nesting/collision geometry; exclude rapid and scribe moves without removing them from display, cutting time or posts.
  • Engine/validator collision paths retain the hand-written Collision kernel; its GPU port is on hold. Material-overlap diagnostics use Clipper2 per pair for connected shared-material islands and interior markers; see material-overlap diagnostics. Polygon consumers use ClipperBridge; directional-distance consumers retain native-arc offsets. Validation uses OffsetForValidation and NestTolerances.SpacingSlack, not conservative display/preparation padding; Auto Nest's layout check, the runner's candidate validation and the pre-post part-spacing review all find spacing candidates with Core's SpacingOutline and confirm them on NativeContours (the outline circumscribes arcs by more than the slack), so they agree; NestLayoutCheck.Clears skips the confirmation and stays stricter for engine certification. Do not loosen tolerances to hide failures.
  • FillLinear geometry caches are per public call, keyed by Program reference identity; never share them across calls/threads. PartOverlapChecker is per check; parts/programs must not mutate during its lifetime.
  • FillScore ranks count, utilization, compactness; exact ties keep the current layout. Custom comparers remain authoritative. Preserve extents' negative/nonfinite-input fallback, pair preparation and adjusted-column overlap checks. Do not remove bounds recomputations without threshold/rounding characterization.
  • ObservableList events own drawing/plate quantity tracking; avoid double accounting. Cutoff parts are excluded from quantity, utilization and overlap checks.
  • Plate.Outline/NestPlateStock.Outline (SheetOutline) make a sheet irregular; Size stays its bounding box. Only Irregular fills it (PackBoundary eroded by the largest edge spacing); every other engine and fill strategy must place nothing on it, validation must reject parts outside it or over its obstacles, and automatic cut-offs refuse it. See irregular stock.
  • Cutoffs persist as definitions on Plate.CutOffs; apply through RegenerateCutOffs, never preview parts. Preserve sequence positions. Batch planning must finish before mutation and roll back on failure. Use PlateSequencing.Apply for automatic cutoff dependencies, with nominal spans/reference identity rather than trimmed geometry/names.
  • A cutoff starts only at the origin-side edge: stock can be oversize, so the far edge is unknown. Only a head-locked overcut (CutOff.HeadLockOvercut, HeadHeightLock markers) may start its far-edge segment there; posts refuse it without lock codes.
  • Fixed emissions (locked programs, drawing-pinned contours) are accepted as given: their violations warn on an UNVERIFIED proposal and never steer the search, while every planner-chosen motion stays strict. Plates without them must keep the PlanningCharacterizationTests digests.
  • A HeadRaise marker (a rapid made head-up over cut parts) is the safest-route fallback's last resort, added only after the strict search fails; the strict search never marks a rapid. Every post must raise before a marked rapid or refuse the nest.
  • An empty diagnostic is not a clear result unless IsComplete. Posting must run checks before writing CNC output; warnings require explicit per-attempt consent, never a persisted bypass. Keep inputs stable through analysis/cancellation.
  • Preserve symbolic G-code variable definitions/references in file round trips. Keep training bitmaps by default; inference checks predictor availability before scalar-only extraction.

Read the relevant contract before changing its behavior:

  • Nest file format
  • SVG import and export: SVG numbers are not drawing units; import never guesses a scale
  • Irregular stock: outlined sheets, what honors the outline and what refuses it
  • Directional slides and pair-spacing limits
  • Lead-in placement (including the planner's eroded pierce for cutouts too small for their lead-in and the stop at a feature's center line) and pierce zones: opt-in PierceDiameter clearance, the hole pole fallback and the planner's perimeter scrap fallback
  • Breakoffs: tabbed scrap; Break-layer open cuts that are cut but are not material
  • Tabbed cutouts: holes cut in pieces around Tab-layer spans that are material but never cut; nesting reads material through NestingMaterial.ForNesting, so nothing nests in them
  • Dimensions: CAD Converter annotations that store placement only, are measured from the cut geometry when shown and never affect the program
  • Support tabs: the nest's support grid, the center-of-gravity check, and Plan Cutting's tab placement for parts the grid cannot hold level
  • Material-overlap diagnostics
  • Automatic cutoffs and sequencing
  • Pre-post verification
  • Machine cutting defaults: the nest's machine supplies leads, kerf and cut-off settings for plates without their own parameters
  • Shared settings: in Database mode machines, post settings, clamps and nest defaults come from the server once it holds them; offline uses the last copy read, read-only
  • Server nesting: Database-mode Auto Nest queued to the server's worker container (OPENNEST_ROLE=worker), one job at a time with no time limit, streaming progress and the best plan so far over SSE; the desktop replays the recorded engine answers to validate and bind locally. My Server Jobs reopens results in later sessions, and each result is kept at most once (If-Match Keep). The HTTP server stays off Engine/IO
  • Cut-time estimates: simulator/Calculate Cut Time acceleration planner and placeholder machine limits
  • Cincinnati CL and CI Fiber
  • Fill verification: opt-in benchmarks, frozen oracles, Debug-only counters and predictor initialization. Zero Release counters do not prove work removal.
  • Desktop auto-update: GitHub Releases by default, opt-in rolling dev-build pre-release from green master pushes, the nest server's /updates mirror first in Database mode (GitHub fallback), UpdateFeedUrl for a self-hosted feed, release Velopack assets and Deploy-OpenNest.ps1.
  • Undo and Redo: whole-nest history, the recording rule, what a restore rebuilds and what is excluded.
  • Desktop help: WebView2 help window, topic IDs and the pinned help release both packaging scripts install.