# Kiln Safety Systems

Kiln lets AI agents control 3D printers safely.  Every layer of the stack
enforces hard limits so that even a confused or hallucinating model cannot
damage your hardware, start a fire, or ruin a print without multiple
independent checks failing simultaneously.

---

## Defense in Depth

Kiln does not rely on a single safety gate.  Five independent layers stand
between an AI-generated command and your printer:

1. **Pre-flight checks** -- validates printer state before every print.
2. **G-code validation** -- blocks dangerous commands before they reach firmware.
3. **Per-printer safety profiles** -- enforces model-specific temperature,
   speed, and build-volume limits.
4. **Heater watchdog** -- auto-cools idle heaters to prevent thermal runaway.
5. **Adapter-level validation** -- each printer adapter re-checks temperatures
   against its own safety profile before sending commands.

A command must pass *all* layers.  Failing any one is enough to block it.

---

## Emergency Latch Model (E-stop)

Kiln uses a persistent emergency latch per printer.  When tripped, the latch
remains active across process restarts until an operator explicitly clears it.

### What gets persisted

- `latched` state
- `reason` and `source`
- `triggered_at`, `cleared_at`
- `cleared_by`
- `ack_note`

### What is blocked while latched

- `start_print`
- `resume_print`
- queue/scheduler dispatch for that printer
- hazardous control paths (`send_gcode`, heating commands in `set_temperature`,
  firmware resume)

Blocked calls return `E_STOP_LATCHED` with next-step guidance.

### Clear requirements

Clearing a latch requires all of the following:

1. all critical interlocks engaged
2. explicit acknowledgement note
3. explicit clear action (no implicit auto-resume)

CLI:

```bash
kiln emergency-stop --printer default --reason user_request --source cli
kiln emergency-status --printer default
kiln emergency-clear --printer default --ack-note "Area inspected, safe to resume"
```

MCP tools:

- `emergency_stop`
- `emergency_status`
- `clear_emergency_stop`
- `emergency_trip_input` (for external button/PLC bridges)

---

## Pre-flight Checks

Before every print, Kiln runs a mandatory pre-flight sequence.  This cannot
be skipped -- `start_print`, `download_and_upload` (with auto-print),
`slice_and_print`, and `generate_and_print` all call `preflight_check()`
internally and abort if it fails.

### What gets checked

| Check                | Blocks print? | Details |
|----------------------|:---:|---------|
| Printer connected    | Yes | Printer must be reachable and responding. |
| Printer idle         | Yes | State must be `idle` -- not printing, paused, or errored. |
| No error flags       | Yes | Printer must not be in an error state. |
| Temperatures in range| Yes | Current hotend and bed temps must be within the safety profile limits. |
| Material match       | Configurable | If an expected material is specified, it is checked against the loaded material and the printer intelligence database. Strict mode (default) blocks on mismatch. |
| Local file valid     | Yes (if provided) | G-code file is scanned for blocked commands and temperature violations. |
| Remote file exists   | Yes (if provided) | Verifies the file is present on the printer before starting. |
| Outcome history      | No (advisory) | If past prints on this printer/material combo have a high failure rate, a warning is shown but the print is not blocked. |

By default, `KILN_STRICT_MATERIAL_CHECK=true` -- unknown materials block the
print.  Set to `false` for advisory-only warnings.

---

## G-code Validation

Every G-code command -- whether sent via `send_gcode`, embedded in an uploaded
file, or generated by the slicer -- passes through the G-code safety validator
before reaching the printer.

### Blocking rules (command rejected)

These violations prevent the command from being sent at all:

- **Temperature above safe maximum** -- hotend, bed, and chamber temps are
  checked against hard limits (per-printer or generic defaults of 300/130/80 C).
- **Negative temperatures** -- caught and blocked.
- **Unconditionally blocked commands:**
  - `M112` (emergency stop) -- must use the dedicated `emergency_stop` tool.
  - `M500/M501/M502` (EEPROM save/load/reset) -- agents must not modify
    firmware settings.
  - `M552/M553/M554` (network config) -- agents must not change network
    settings.
  - `M997` (firmware update trigger) -- must use the dedicated firmware tools.
- **Dialect-specific blocks** -- e.g., Klipper blocks M500/M501/M502
  (use SAVE_CONFIG instead); Bambu blocks M600 during prints.
- **Unrecognised command formats** -- arbitrary text is never forwarded to the
  printer firmware.

### Warning rules (command allowed with advisory)

These issues are logged and returned to the caller but do not block the
command:

- **Z below bed plane** (Z < 0) -- risk of nozzle crash.
- **Feedrate above recommended maximum** -- may cause missed steps.
- **Stepper disable** (M18/M84) -- part may shift.
- **Homing** (G28) -- bed should be clear.
- **Stepper current changes** (M906) -- incorrect values can damage hardware.
- **Arc commands without I/J/R parameters** -- undefined arc.
- **Cold extrusion risk** -- hotend below 150 C with extrusion active.

### File-level scanning

`scan_gcode_file()` streams through an entire file line by line without loading
it into memory, fails fast on the first blocked command, and caps warnings at
50.  Files over 500 MB are rejected.  The scanner auto-detects the target
printer from slicer header comments (PrusaSlicer, Cura, OrcaSlicer,
BambuStudio) and applies the matching safety profile automatically.

---

## Per-Printer Safety Profiles

Kiln ships a curated database of safety limits for 26+ printer models.  Each
profile defines:

- **Max hotend temperature** (e.g., 260 C for PTFE-lined Ender 3, 300 C for
  all-metal Prusa MK4)
- **Max bed temperature** (80--120 C depending on model)
- **Max chamber temperature** (where applicable)
- **Max feedrate** (mm/min)
- **Max volumetric flow** (mm^3/s)
- **Build volume** (X/Y/Z dimensions in mm)
- **Safety notes** (e.g., "PTFE-lined hotend -- exceeding 240 C risks toxic
  fumes")

Profiles exist for printers from Creality, Prusa, Bambu Lab, Voron, Rat Rig,
Elegoo, AnkerMake, Artillery, Sovol, FlashForge, and QIDI.  A conservative
generic/default profile (300 C hotend, 130 C bed) applies when no match is
found.

### How profiles are used

1. **G-code validator** -- `validate_gcode_for_printer()` loads the profile
   and uses its limits instead of the generic defaults.
2. **Printer adapter** -- `PrinterAdapter._validate_temp()` cross-checks
   temperature commands against the profile for defense-in-depth.  Even if the
   G-code validator is somehow bypassed, the adapter will reject unsafe temps.
3. **Pre-flight checks** -- current temperatures are compared against the
   profile limits.

Set your printer model via `KILN_PRINTER_MODEL` to enable profile-aware
validation.

---

## Heater Watchdog

The heater watchdog is a background daemon that prevents heaters from being
left on indefinitely when no print is active.

### How it works

1. The watchdog starts automatically with the Kiln server.
2. It tracks the last time heaters were intentionally activated (via
   `set_temperature` or print start).
3. Every 30 seconds, it checks whether:
   - No print is currently running, AND
   - The idle timeout has elapsed (default: 30 minutes), AND
   - Heater targets are still above zero.
4. If all conditions are met, it sends cooldown commands (set hotend and bed
   to 0 C) and emits a `TEMPERATURE_WARNING` event.

### Configuration

Set `KILN_HEATER_TIMEOUT` to the number of minutes before auto-cooldown
(default 30, set to 0 to disable).  The timer resets on print start/end and
`set_temperature` calls, so the watchdog never interferes during active
printing and gives you time to inspect a finished print.

---

## What Kiln Will NOT Do

The safety system actively prevents the following:

- **Send G-code that exceeds your printer's temperature limits.**  Commands
  like `M104 S350` on a 300 C-max printer are blocked before reaching firmware.
- **Start a print without pre-flight validation.**  There is no code path that
  bypasses `preflight_check()`.
- **Allow agents to modify firmware settings.**  EEPROM writes (M500/M501/M502),
  network configuration (M552-M554), and firmware updates (M997) are all
  blocked at the G-code validation layer.
- **Send emergency stop via G-code.**  M112 is blocked -- the dedicated
  `emergency_stop` tool handles safety-stop behavior.
- **Leave heaters on indefinitely.**  The watchdog auto-cools after the
  configured timeout.
- **Forward unvalidated external data to the printer.**  Every adapter
  normalizes API responses to typed dataclasses.  Raw dicts never reach the
  MCP layer.
- **Silently swallow errors.**  Every failure produces a structured error
  response with a clear error code and message.

---

## Safety Audit Trail

Every safety-relevant action is logged and accessible via the `safety_audit`
MCP tool: tool executions, blocked commands, rate-limit violations, pre-flight
failures, and dry-run validations.  Use `safety_status` for a real-time
dashboard and `safety_settings` to review current configuration.

---

## Reporting Safety Issues

If you discover a safety concern -- a command that should be blocked but isn't,
a temperature limit that seems wrong, or any behavior that could risk hardware
damage -- please report it on GitHub Issues with the `safety` label.

Safety reports are treated with the highest priority.  We would rather
over-block than under-block.
