Home 3D Printing
Drive the printer through $PC (printctl) — the source of truth; this skill is the runbook. Physical hardware that heats and moves: safety gates are not optional, and no step may route around them.
This setup is not hardcoded. Printer host, model, nozzle, material and safety caps all live in $AXON_PERSONAL_ROOT/config/printing.json and are surfaced (and, when the printer is on, live-discovered) by $PC doctor. Run $PC doctor first and read the real values off it — never assume a printer model or temp from this document.
Variables
| var |
value |
notes |
$PC |
scripts/printctl |
launcher → $AXON_ROOT/capabilities/printing/printctl.py (runs via uv) |
$HOST $MODEL $MATERIAL $NOZZLE_MAX $BED_MAX |
(from config) |
host, printer model, loaded filament, hard temp caps — all read from the overlay config; $PC doctor prints them. Never inline them here. |
$STL |
— |
model to slice (.stl/.3mf) |
$GCODE |
${STL%.*}.gcode |
slice output, sits next to $STL |
$FN |
$(basename $GCODE) |
filename as the printer sees it (arm/start key) |
$WALLS / $INFILL |
4–6 / 40–50% gyroid |
generic strength-part guidance, not a fixed setting |
Safety model — non-negotiable
- Caps (
$NOZZLE_MAX/$BED_MAX) enforced on sliced gcode and at arm. Above → refused.
- Arm-before-heat:
start/resume refuse unless $FN was armed. Arming IS the human "go"; after it, start+monitor run unattended within caps.
- Runaway temp/motion →
$PC estop immediately (halts Klipper; needs FIRMWARE_RESTART after).
- Never curl the heat/move endpoints directly to skip the gate.
Preflight — gate on the output
$PC doctor, then branch:
moonraker: REACHABLE ✓ → continue.
moonraker: unreachable → printer off/asleep or off-LAN. Stop, ask the user to power it on. Do not retry blindly.
- any preset shows
(unset) or not found → headless slicing unconfigured. Read references/setup.md, stop at the one-time GUI step (needs the user).
Print workflow
- [ ] 1. doctor green (reachable + presets ✓)
- [ ] 2. slice → $GCODE, temps ≤ caps
- [ ] 3. upload → printer
- [ ] 4. arm → state plan, get user go
- [ ] 5. start + monitor
$PC slice $STL → writes $GCODE, prints resolved nozzle/bed. Refuses over caps. "process not compatible with printer" → config points at system presets, not saved user presets → references/setup.md.
$PC upload $GCODE.
- State part +
$MATERIAL + expected temps to the user; on their go: $PC arm $FN --local $GCODE (re-checks temps).
$PC start $FN then $PC monitor. start REFUSED → $FN wasn't armed (gate working) → do step 3.
Other commands
$PC status (json) · $PC files · $PC pause · $PC resume $FN · $PC cancel · $PC estop. Ad-hoc Moonraker beyond printctl → references/moonraker-api.md.
Strength parts (mounts, brackets under load)
Strength process preset, $WALLS walls, $INFILL, $MATERIAL (PETG/ASA, not PLA), orient so layer lines are not parallel to the pull force, brim on small parts. Worked example (personal): $AXON_PERSONAL_ROOT/documents/vanmoof-s3-phone-mount-3d-print.md.
Provenance and maintenance
Verified 2026-07-09: printer at $HOST (overlay config), OrcaSlicer 2.4.2, $PC → $AXON_ROOT/capabilities/printing/printctl.py. Re-verify on drift:
- reachable + config:
$PC doctor
- safety gates intact:
$PC selftest (must end ALL PASS ✓)
- printctl path:
test -f "$AXON_ROOT/capabilities/printing/printctl.py" && echo ok
- OrcaSlicer preset limitation is a standing constraint, not a bug →
references/setup.md §3.
1---2name: home-3d-printing3description: Slices models and drives a home Klipper/Moonraker 3D printer via the local printctl CLI — slice with OrcaSlicer, upload, arm, start, monitor, pause/cancel, e-stop — with hard temperature caps and an arm-before-heat gate. Works with any Klipper/Moonraker printer; the specific model, material and caps come from config (run `printctl doctor`). Use when the user wants to 3D-print at home, slice an STL/3MF, or check/control the printer. Do not use for CAD/mesh modeling, cloud/non-local printers, or non-Klipper firmware.4---56# Home 3D Printing78Drive the printer through **`$PC`** (printctl) — the source of truth; this skill is the runbook. Physical hardware that heats and moves: safety gates are not optional, and no step may route around them.910**This setup is not hardcoded.** Printer host, model, nozzle, material and safety caps all live in `$AXON_PERSONAL_ROOT/config/printing.json` and are surfaced (and, when the printer is on, live-discovered) by `$PC doctor`. **Run `$PC doctor` first** and read the real values off it — never assume a printer model or temp from this document.1112## Variables13| var | value | notes |14|-----|-------|-------|15| `$PC` | `scripts/printctl` | launcher → `$AXON_ROOT/capabilities/printing/printctl.py` (runs via uv) |16| `$HOST` `$MODEL` `$MATERIAL` `$NOZZLE_MAX` `$BED_MAX` | *(from config)* | host, printer model, loaded filament, hard temp caps — all read from the overlay config; `$PC doctor` prints them. Never inline them here. |17| `$STL` | — | model to slice (`.stl`/`.3mf`) |18| `$GCODE` | `${STL%.*}.gcode` | slice output, sits next to `$STL` |19| `$FN` | `$(basename $GCODE)` | filename as the printer sees it (arm/start key) |20| `$WALLS` / `$INFILL` | `4–6` / `40–50% gyroid` | generic strength-part guidance, not a fixed setting |2122## Safety model — non-negotiable23- **Caps** (`$NOZZLE_MAX`/`$BED_MAX`) enforced on sliced gcode and at `arm`. Above → refused.24- **Arm-before-heat:** `start`/`resume` refuse unless `$FN` was `arm`ed. Arming IS the human "go"; after it, start+monitor run unattended within caps.25- Runaway temp/motion → `$PC estop` immediately (halts Klipper; needs FIRMWARE_RESTART after).26- Never curl the heat/move endpoints directly to skip the gate.2728## Preflight — gate on the output29`$PC doctor`, then branch:30- `moonraker: REACHABLE ✓` → continue.31- `moonraker: unreachable` → printer off/asleep or off-LAN. **Stop, ask the user to power it on.** Do not retry blindly.32- any preset shows `(unset)` or `not found` → headless slicing unconfigured. Read `references/setup.md`, stop at the one-time GUI step (needs the user).3334## Print workflow35```36- [ ] 1. doctor green (reachable + presets ✓)37- [ ] 2. slice → $GCODE, temps ≤ caps38- [ ] 3. upload → printer39- [ ] 4. arm → state plan, get user go40- [ ] 5. start + monitor41```421. `$PC slice $STL` → writes `$GCODE`, prints resolved nozzle/bed. Refuses over caps. "process not compatible with printer" → config points at system presets, not saved user presets → `references/setup.md`.432. `$PC upload $GCODE`.443. State part + `$MATERIAL` + expected temps to the user; on their go: `$PC arm $FN --local $GCODE` (re-checks temps).454. `$PC start $FN` then `$PC monitor`. `start` REFUSED → `$FN` wasn't armed (gate working) → do step 3.4647## Other commands48`$PC status` (json) · `$PC files` · `$PC pause` · `$PC resume $FN` · `$PC cancel` · `$PC estop`. Ad-hoc Moonraker beyond printctl → `references/moonraker-api.md`.4950## Strength parts (mounts, brackets under load)51Strength process preset, `$WALLS` walls, `$INFILL`, `$MATERIAL` (PETG/ASA, not PLA), orient so layer lines are **not** parallel to the pull force, brim on small parts. Worked example (personal): `$AXON_PERSONAL_ROOT/documents/vanmoof-s3-phone-mount-3d-print.md`.5253## Provenance and maintenance54Verified 2026-07-09: printer at `$HOST` (overlay config), OrcaSlicer 2.4.2, `$PC` → `$AXON_ROOT/capabilities/printing/printctl.py`. Re-verify on drift:55- reachable + config: `$PC doctor`56- safety gates intact: `$PC selftest` (must end `ALL PASS ✓`)57- printctl path: `test -f "$AXON_ROOT/capabilities/printing/printctl.py" && echo ok`58- OrcaSlicer preset limitation is a standing constraint, not a bug → `references/setup.md` §3.