SlicerX talks to printers and to two home services through connectors that share one interface. Each guide below has two parts: what a person sets up on the printer, and what someone integrating or extending the connector needs to know.
| Guide | Covers |
|---|---|
| bambu-lan.md | Bambu Lab X1, P1, A1 and H2D in LAN mode |
| moonraker.md | Klipper printers with Moonraker |
| creality.md | Creality K1, K1 Max, K1C, K2 Plus, Ender-3 V3 series and Hi, on stock firmware or Klipper |
| snapmaker.md | Snapmaker U1 and Snapmaker 2.0 (A150, A250, A350) |
| prusalink.md | Prusa printers with PrusaLink (MK4S, MK3.9, MINI+, XL, Core One) |
| octoprint.md | OctoPrint servers |
| duet.md | Duet boards running RepRapFirmware 3 |
| elegoo.md | Elegoo Centauri Carbon (SDCP) |
| camera.md | Live camera video: what each printer gives, quality, and the stream protocol |
| export.md | Printers with no supported connection: save G-code and carry it over |
| finding-printers.md | How scanning finds printers, what it sends, and what to do when it finds nothing |
| printer-catalog.md | The catalog of brands and models that first-run setup reads |
| spoolman.md | Spoolman filament inventory |
| home-assistant.md | Home Assistant power plugs, lights and fans |
Setting up your first printer
- Pick your printer from the catalog, or search for it. The catalog knows the model's build volume, nozzle sizes and how it connects.
- Follow the guide for that connection. Each one lists, screen by screen, where to read the IP address and the access code or key on the printer itself.
- Choose Scan to let SlicerX find it, or enter the IP address. See finding-printers.md.
All screen names in these guides come from the printers' documentation. None has been read off a printer yet, and menus move between firmware versions.
How connectors behave
- Everything stays on your network. A connector talks straight to the printer, or to Spoolman or Home Assistant on your LAN. No printer traffic goes through a SlicerX server. Printers and service URLs must be on the local network (private addresses,
.localnames). - Reading is free, changing needs approval. Status, temperatures, filament slots and camera frames are read without asking. Uploading a file, starting, pausing, resuming, canceling, sending G-code and changing inventory or home devices each need an approval you give in the app. An approval covers one action on one printer with the exact parameters shown to you, and it is used up when it is spent.
- Credentials (access codes, API keys, passwords, pairing tokens) are stored in your operating system keychain. They are never written to logs, never shown again and never sent to the model.
- Scanning is user started. See finding-printers.md for what each scan sends.
- Printers that go offline show as offline. They do not raise errors in the printers list.
None of these connectors has been run against a physical printer yet. Each guide has an "Untested on hardware" section that lists what to check first if something does not behave.
Capabilities at a glance
| Connector | Status | Events | Upload | Start, pause, resume, cancel | Camera | Filament slots | G-code console |
|---|---|---|---|---|---|---|---|
| Bambu LAN | yes | push | yes | yes | A1 and P1 | AMS | yes |
| Moonraker | yes | polled | yes | yes | if a webcam is configured | no | yes |
| PrusaLink | yes | polled | yes | yes | if a camera is configured | no | no |
| OctoPrint | yes | polled | yes | yes | if a webcam is configured | no | yes |
| Duet | yes | polled | yes | yes | no | no | yes |
| Creality (stock) | yes | push | yes | yes | K1, Ender, Hi | no | yes |
| Snapmaker 2.0 | yes | polled | yes | yes | no | no | yes |
| Elegoo Centauri Carbon | yes | push | yes | yes | yes | no | no |
For integrators
The interface
Rust crate sx-connect. A PrinterConnector opens a PrinterSession for one printer. Sessions expose status, events, upload, start, pause, resume, cancel, snapshot and send_gcode. Service plugins (Spoolman, Home Assistant) implement ServicePlugin::call(tool, args, token). The TypeScript side is PrinterHost in @slicerx/contracts. Browsers reach real printers through sx-link, a localhost bridge, using @slicerx/link-client. @slicerx/fleet-sim implements the same PrinterHost in memory for demos and tests.
Plugin manifest
Every plugin has a manifest (manifests.json is the single source for the Rust crate and the simulator):
{
"id": "moonraker",
"name": "Moonraker (Klipper)",
"version": "0.1.0",
"kind": "printer",
"protocols": ["http", "websocket-jsonrpc"],
"capabilities": ["status", "events", "upload", "start", "pause", "resume", "cancel", "camera", "gcode_console"],
"tools": [{ "name": "moonraker.status", "permission": "read", "description": "...", "inputSchema": { "type": "object" } }],
"network": ["lan:7125", "lan:80", "lan:443"]
}tools are what Pilot may call. Their permission is read, queue (upload), start (heat or move a printer, or control a job) or profile (change inventory). network lists the hosts and ports the plugin may reach; lan: means the local network only.
Normalized status
state is one of idle, preparing, printing, paused, finished, error, offline. Also job name, progress (0 to 1), layer and layer count, time left in seconds, nozzle, bed and chamber temperatures (current and target), filament slots (id, material, color, remaining percent), camera availability and a message.
Approvals
Calls that change something take an approval token. Pairing a printer that needs a tap on its own screen (Snapmaker 2.0) is not one of them; it changes nothing on the printer. The connector checks it through an ApprovalGate before sending any byte. The check receives the action (printer.upload, printer.start, printer.pause, printer.resume, printer.cancel, printer.gcode, plugin.call), the target (printer or plugin id) and the canonical JSON of the parameters: upload {printerId, name, sha256}, start {printerId, name, opts}, pause, resume and cancel {printerId}, G-code {printerId, line}, plugin tools {pluginId, tool, input}. A token for one action, target or parameter set fails for another and works once.
Errors
Every failure has a code: unreachable, auth, not_supported, approval_required, approval_invalid, not_found, bad_state, protocol. Messages never contain credentials or URLs.
Events
Sessions expose a stream of status, job_finished and error events. Bambu Lab, Elegoo and stock Creality push. The others poll every pollMs milliseconds (default 1000, minimum 50) and emit only when something other than the timestamp changed. A job is reported finished when a printing or paused printer becomes finished, or becomes idle after reaching at least 98 percent.
Testing against the mocks
@slicerx/mock-printers runs fakes for every protocol, driven by demo-fleet.json (Bay 1 X1 Carbon with AMS, Bay 2 P1S with AMS, Bay 3 MK4S, Bay 4 Voron 2.4 350, Bay 5 K1 Max offline). Start them with pnpm --filter @slicerx/mock-printers start -- --state idle; it prints ports and throwaway credentials as JSON. cargo test -p sx-connect starts the mocks itself and runs the driver contract suite: status, events, upload, start, pause, resume, cancel, wrong state, missing, forged, reused and mismatched tokens, G-code and camera. pnpm --filter @slicerx/fleet-sim test runs the same checks against the in-memory host.
Adding a printer family
- Add a manifest to
manifests.json. - Implement
PrinterConnectorandPrinterSessionundersrc/drivers/<name>/. Call the gate first in every method that changes something. Map the printer's states onto the normalized ones. Usepoll_eventswhen the protocol has no push channel. - Register it in
drivers::all. - Write a fake in
mock-printers/src/<name>.tsthat speaks the real protocol on top ofMockMachine, and add it tostartMocks. - Add a case to
tests/drivers.rs. The contract suite intests/common/mod.rsdoes the rest. - Write the guide for it here, with the protocol's public documentation as sources.
If the printer runs Klipper and Moonraker, skip steps 2 to 5: wrap MoonrakerConnector::for_plugin(id, default_port, gate). The Creality and Snapmaker connectors do that and add a second protocol, chosen by probing (PrinterConfig.protocol overrides the probe). Printers that need pairing implement PrinterConnector::authorize.