print-bench

Behind the scenes

How the machine works.

Between a one-line idea and a merged, printable design sits a pipeline that gates every change, regenerates its own artifacts, and runs itself. Here is what it does under the hood — and where the generic half ends and the 3D-printing half begins.

7designs, every one gated in CI
3seams join the platform to the design layer
0derived files committed by hand

Overview

The shape of it

Two machines in one repo

print-bench is a generic pipeline with a 3D-print workshop bolted on. The whole design is drawn so those two halves come apart — which is what makes the CI half reusable as a template. They meet at exactly three seams.

Domain layer — the part you replace

3D-print / OpenSCAD design

The geometry, the printability gates, the co-design loop. Nothing here is generic — swap it and the same machine builds something else.

  • design unit
  • gate stack
  • shared libraries
  • styles & lineage
  • co-design loop
3 seams
Classifywhich gates run for this diff
Regeneraterebuild derived files, commit them back
Gaterun whatever was selected

Platform layer — generic, the template

CI & automation

Selects its own checks, keeps derived files honest, proposes new gates, and turns issues into draft PRs on its own. It never mentions millimetres.

  • gate selection
  • regenerate-and-commit
  • smart CI
  • autonomy engine
  • telemetry
SeamPlatform sideDomain side
Classificationa CI job asks "what runs for this diff?"ci-classify.sh maps changed paths → gates
Regenerationa job commits derived artifacts backrender.sh, gallery.sh produce them
Gatingthe gate job runs the selected checksgate.sh, check.sh are the gates

Full write-up: docs/architecture/README.md.

The short version

From an idea to a part in your hand

Strip out the engineering and this is the whole story: you describe what you need, an AI helps you model it, the machine proves it will actually print, and you download a file that's ready to slice.

1 Describe it Say what you need — thesize, the fit, what it holds. 2 Design it together You and an AI shape themodel, previewing afterevery change. 3 It gets checked Automatic checks confirmit's solid and actuallyprintable — before it ships. 4 Print it Download the ready-to-slicefile — designed to printwithout supports.
No jargon: describe it, design it together, let the checks confirm it prints, then print it.

New here?

The path you'll take

Bring an idea or claim a queued one, and the repo walks you from a blank directory to a merged, printable design. Every station is one command or one skill; the review round in the middle repeats until the gates pass.

repeat until green 1the site / README Arrive 2Orient read How it works 3a design-brief issue Pick work 4Scaffold /new-design 5render, review previews Iterate 6Preflight /preflight 7a draft PR Open PR 8Ship CI gates, then merge
The route from landing on the site to a merged design. Stations 4–6 are the co-design loop, run until /preflight comes back green.

The pipeline

Step through it

Follow a change through the machine

The same pipeline, one step at a time — from the diff you push to the single gate that lets it merge, then how the machine regenerates and runs itself. Step through with the arrows or the dots.

What a change goes through

A design is done when it survives the gate — not when it renders

Push a change to a model and the pipeline gates only the designs it touches (plus anything derived from them). The check that actually decides is gate.sh --slice: a model that renders cleanly can still fail to be watertight, or fail to slice.

  1. 1

    render.sh

    Renders the STL and a 4-view contact sheet (including a bottom view, to catch overhangs and bed contact).

  2. 2

    check.sh

    Fast pass: syntax-checks every model, CGAL-renders the library demos, and fires the guard / mate negative tests — the checks a render alone can't make.

  3. 3

    gate.sh --slice

    The real bar. Runs the printcheck analyzer (watertight, thin walls, overhangs) on each printable part, then test-slices it in PrusaSlicer.

  4. 4

    readme-gate.sh

    Every design ships a complete product page — pitch, embedded preview, print settings, tunable parameters.

  5. 5

    style-check.sh

    If the design declares a style, its geometry is held to that style's measured rules.

One local command mirrors all of it. /preflight runs this exact set, scoped the way CI scopes it, and answers "would CI pass?" before you push.

The domain layer in full: docs/architecture/design-workflow.md.

Derived files are the pipeline's job

A committed image can never be older than its source

Previews, animation GIFs, studio product shots, the gallery — anything derived from a model — are not hand-committed. CI regenerates them in the same run that gates the source and commits them back to the branch. So the presence-only gates on those images stay honest: the picture beside a model cannot depict geometry the model no longer has.

Input fingerprint

A design re-renders only when its inputs actually changed; the stamp is written in the same commit as the artifacts, so it can't claim a freshness they don't have.

Loop guard

The commit-back re-triggers CI, so a non-reproducible renderer could push forever. The job recognises its own last commit and refuses a second push.

Fork fallback

CI can't push to a fork, so there it fails with the exact list of files to regenerate by hand — never a silent skip.

Committing back turns on a quirk worth stating plainly: a push made with the default token triggers no workflow. The pipeline uses that fact in both directions.

PushTokenWhy
regenerated artifacts → a PRPATmust re-trigger CI so the required checks attach to the commit that ships
a newly-approved gatePATsame — the enabled gate has to run
the telemetry roll-updefault tokenmust not re-trigger, or it would gate, record itself, and commit forever

The platform layer in full: docs/architecture/ci-platform.md.

It decides what to run

Deterministic gate selection, one source of truth

The changes job classifies a diff and every other job keys off it — a docs-only change skips the render jobs, a one-design change gates one design, an infra change gates everything. That decision lives in one script, ci-classify.sh, that both CI and the local pre-push check run — so "would CI pass?" locally can't drift from what CI does.

Above it sits smart CI (tools/ci-gates): it detects checks that don't exist yet — a shell script with no shellcheck gate, a new top-level directory the classifier doesn't cover — and proposes them in a sticky PR comment a maintainer crosses with one command.

Skipped is not the same as passed. GitHub treats a skipped required check as still-pending, so a single aggregating ci-ok job gates the branch: it passes only when every other job is green or was deliberately skipped. New blocking checks stay proposals until a human opts in — nothing lands unannounced.

Runs itself

It runs itself

From an idea in an issue to a draft PR

A scheduled routine picks one opted-in issue and runs it to a draft PR for a human to review. The reusable core is a pure, tested selector (tools/backlog-burn) that chooses at most one issue per firing and excludes anything already claimed by a lock, an open PR, or a human-decision hold. Three routines share that one selector, each pointed at a different label:

  • ship an issue
  • run a design brief
  • chunk an oversized issue

Two safety properties are load-bearing. Arming takes two keys — a committed config and a live repo switch must agree, so a clone can't silently arm it and a human can disarm it in seconds. And when an agentic run hits a yes/no question only a human should answer, it parks the issue with a label and stops, rather than guessing.

It measures itself

Every gate run leaves a record

Each gate run writes one JSON record — printcheck scores, per-design wall time, preview-budget headroom, what was skipped and why — and default-branch runs append it to a committed log (telemetry/log.ndjsontelemetry/REPORT.md). The self-running features read that log, so their decisions rest on measured history rather than a guess.

One more thing

This page is built the same way everything here is

The site invents no content: every word and image traces to a committed, CI-gated file or a first-party record. That holds for this page too — its copy is a presentation of the architecture docs in the repo, and each mechanism above links to the file that implements it. A local link that doesn't resolve fails the build rather than 404ing in production.