# Klipper Manager

> AI-driven Klipper 3D printer configuration, diagnostics, and calibration via Moonraker API

- Skill: `santiagomoneta/klipper-manager` (Agent Skill, multi-file: 10 files)
- Install (CLI): `npx skillmds@latest add santiagomoneta/klipper-manager`
- Raw SKILL.md: https://api.skillmd.com/api/skills/santiagomoneta/klipper-manager/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: santiagomoneta (https://skillmd.com/u/santiagomoneta)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/santiagomoneta/klipper-manager

---


# Skill: klipper-manager

# Klipper Manager — Full AI-Driven Printer Configuration & Diagnostics

Manages any Klipper printer via Moonraker API: reads and edits printer.cfg, runs diagnostics,
executes calibration sequences, monitors live status, and fixes issues with full config-awareness.

---

## Activation

When the user asks to:
- Connect to / manage a Klipper printer
- Read, change, or fix any printer.cfg setting
- Diagnose a Klipper error or warning
- Run calibration (bed mesh, probe, PID, resonances, pressure advance, axis twist, screws, etc.)
- Monitor temperatures, positions, or print status
- Send GCode commands
- Restart firmware or Klipper

**Always start by reading `state/printer_context.json`** — if it exists, greet the user with
a summary of the known printer. If it is missing or the user provides a new IP, run Phase 1.

---

## Phase 1: Printer Discovery

### Step 1 — Connect to Moonraker

Ask for the printer IP if not already known. Then verify connectivity:

```bash
curl -s "http://<IP>:7125/printer/info"
```

Expected response contains: `state`, `hostname`, `software_version`, `config_file`.

If `state` is not `"ready"`, report it and ask the user to resolve before continuing.

### Step 2 — Fetch printer.cfg

```bash
curl -s "http://<IP>:7125/server/files/config/printer.cfg"
```

Also fetch any included files referenced with `[include ...]`:

```bash
curl -s "http://<IP>:7125/server/files/config/<included_file>"
```

Common includes to auto-fetch: `mainsail.cfg`, `macros/*.cfg`, `KAMP/*.cfg`.

### Step 3 — Parse and Inventory Config

Parse ALL sections from the fetched config. Extract and store in `state/printer_context.json`:

```json
{
  "version": 1,
  "updated": "ISO-8601",
  "moonraker_url": "http://<IP>:7125",
  "klipper_version": "v0.13.x",
  "hostname": "mainsailos",
  "config_file": "/home/pi/printer_data/config/printer.cfg",

  "kinematics": "cartesian | corexy | corexz | delta | ...",
  "build_volume": {"x": 235, "y": 235, "z": 250},

  "steppers": {
    "stepper_x": {"position_max": 246, "position_min": 0, "rotation_distance": 40, "microsteps": 16},
    "stepper_y": {"position_max": 235, "position_min": 0},
    "stepper_z": {"position_max": 250, "position_min": -2}
  },

  "probe": {
    "type": "bltouch | probe | smart_effector | probe_eddy_current | none",
    "x_offset": -62,
    "y_offset": -12,
    "z_offset": 3.439
  },

  "bed_mesh": {
    "mesh_min": [60, 30],
    "mesh_max": [170, 220],
    "probe_count": [5, 5]
  },

  "axis_twist_compensation": {
    "calibrate_start_x": 20,
    "calibrate_end_x": 183,
    "calibrate_y": 117.5
  },

  "safe_z_home": {
    "home_xy_position": [108.5, 117.5]
  },

  "extruder": {
    "nozzle_diameter": 0.4,
    "rotation_distance": 7.687,
    "pressure_advance": null
  },

  "tmc_drivers": {
    "stepper_x": {"driver": "tmc2209", "run_current": 0.750, "stealthchop_threshold": 999999},
    "stepper_y": {"driver": "tmc2209", "run_current": 0.750, "stealthchop_threshold": 999999},
    "stepper_z": {"driver": "tmc2209", "run_current": 0.580, "stealthchop_threshold": 0},
    "extruder": {"driver": "tmc2209", "run_current": 0.580, "stealthchop_threshold": 0}
  },

  "input_shaper": {
    "x": {"type": "3hump_ei", "freq": 66.2},
    "y": {"type": "ei", "freq": 45.0}
  },

  "printer_limits": {
    "max_velocity": 300,
    "max_accel": 7000,
    "max_z_velocity": 15,
    "max_z_accel": 100
  },

  "installed_sections": [],
  "save_config_block": {},

  "known_issues": [],
  "last_diagnostic": null
}
```

### Step 4 — Run Auto-Diagnostic

After parsing, always run the full diagnostic (see Phase 3) and report any issues found.

### Step 5 — Present Summary

Show the user a table:

```
Printer    : mainsailos (Klipper v0.13.x)
Kinematics : Cartesian  |  Build: 246 × 235 × 250 mm
Probe      : BLTouch    |  x_offset: -62  y_offset: -12  z_offset: 3.439
Sections   : [printer] [extruder] [heater_bed] [bltouch] [bed_mesh] [axis_twist_compensation]
             [input_shaper] [firmware_retraction] [safe_z_home] [screws_tilt_adjust] ...
Issues     : (list any found by diagnostic, or "None detected")
```

---

## Phase 2: Configuration Management

### Reading a Setting

To read any setting, look up the parsed `printer_context.json` or re-fetch the file:

```bash
curl -s "http://<IP>:7125/server/files/config/printer.cfg"
```

### Editing a Setting

**Workflow for every config change:**

1. Fetch the CURRENT file (never edit a stale copy)
2. Make the targeted change
3. Validate the change (see Phase 3 validation rules)
4. Save to a temp file `C:/Users/<user>/Documents/printer_fix.cfg`
5. Upload via Moonraker:
   ```bash
   curl -s -X POST "http://<IP>:7125/server/files/upload" \
     -F "root=config" \
     -F "file=@C:/Users/<user>/Documents/printer_fix.cfg;filename=printer.cfg"
   ```
6. Firmware restart to apply:
   ```bash
   curl -s -X POST "http://<IP>:7125/printer/firmware_restart"
   ```
7. Wait 5 seconds, verify `state: ready`:
   ```bash
   curl -s "http://<IP>:7125/printer/info"
   ```
8. Update `state/printer_context.json`
9. Clean up temp file

**CRITICAL: Never edit the SAVE_CONFIG block by hand.** Only Klipper's `SAVE_CONFIG` command
should modify that block. When uploading a modified config, preserve the entire `#*# <--- SAVE_CONFIG --->` block exactly as-is unless explicitly removing stale calibration data.

### Multiple Config Files

If the printer uses `[include]` sections, list all config files:

```bash
curl -s "http://<IP>:7125/server/files/list?root=config"
```

Fetch and edit the correct file — do not modify `printer.cfg` when the target section lives in an included file.

---

## Phase 3: Diagnostics & Validation

### Auto-Diagnostic Checklist

Run this every time a config is loaded or after any change. Check ALL rules:

#### 1. Probe Offset Bounds

For every calibration section that uses probe coordinates, the **nozzle** must stay within
`[position_min, position_max]` accounting for probe offsets.

| Section | Coord params | Nozzle position formula |
|---------|-------------|------------------------|
| `[axis_twist_compensation]` | `calibrate_start_x`, `calibrate_end_x`, `calibrate_y` | `nozzle_x = coord_x - probe.x_offset`; `nozzle_y = coord_y - probe.y_offset` |
| `[bed_mesh]` | `mesh_min`, `mesh_max` | `nozzle_x = mesh_x - probe.x_offset`; `nozzle_y = mesh_y - probe.y_offset` |
| `[screws_tilt_adjust]` | `screw1..N` (x,y) | `nozzle_x = screw_x - probe.x_offset`; `nozzle_y = screw_y - probe.y_offset` |
| `[safe_z_home]` | `home_xy_position` | These are NOZZLE coords directly (no offset subtraction needed) |
| `[delta_calibrate]` | `radius` | probe must land within radius from center accounting for offset |

**Validate for each axis:**
```
nozzle_x >= stepper_x.position_min  AND  nozzle_x <= stepper_x.position_max
nozzle_y >= stepper_y.position_min  AND  nozzle_y <= stepper_y.position_max
```

**Fix formula:**
```
max_coord_x = stepper_x.position_max + probe.x_offset   (when x_offset is negative)
min_coord_x = stepper_x.position_min - probe.x_offset   (when x_offset is positive)
```

#### 2. Bed Mesh Bounds

`mesh_min` and `mesh_max` must be within the reachable probe area:

```
mesh_min.x >= stepper_x.position_min - probe.x_offset
mesh_max.x <= stepper_x.position_max + probe.x_offset  (when x_offset < 0)
mesh_min.y >= stepper_y.position_min - probe.y_offset
mesh_max.y <= stepper_y.position_max + probe.y_offset  (when y_offset < 0)
```

#### 3. Safe Z Home Position

`home_xy_position` must be reachable for the NOZZLE:
```
home_xy.x >= stepper_x.position_min AND home_xy.x <= stepper_x.position_max
home_xy.y >= stepper_y.position_min AND home_xy.y <= stepper_y.position_max
```

Also validate that at the home position, the PROBE is over the bed (not hanging off the edge).

#### 4. SAVE_CONFIG / Calibration Consistency

After a config change, check if saved calibration data in `#*# SAVE_CONFIG` is still valid:

- If `axis_twist_compensation` bounds changed → old `z_compensations` / `compensation_start_x` / `compensation_end_x` may be stale → warn user to re-run `AXIS_TWIST_COMPENSATION_CALIBRATE`
- If `bltouch.z_offset` or `probe.z_offset` was manually changed → warn that `PROBE_CALIBRATE` should be re-run
- If `bed_mesh` bounds changed → existing mesh profiles may be out of bounds → warn to re-run `BED_MESH_CALIBRATE`

#### 5. TMC Driver Warnings

- `stealthchop_threshold: 999999` on extruder with pressure advance → warn (reduced torque, but often acceptable)
- `hold_current` configured → warn (can cause vibration, Klipper docs recommend omitting)
- `run_current` > rated motor current × 0.85 → warn (thermal risk)
- `interpolate: True` with high-precision requirements → note positional deviation (~0.006mm at 16 microsteps)

#### 6. Input Shaper

- `shaper_type: 3hump_ei` or `2hump_ei` → complex resonance signature → recommend belt tension check
- No `[input_shaper]` section → recommend running `SHAPER_CALIBRATE`
- Shaper frequency < 20Hz → likely miscalibrated or very heavy toolhead

#### 7. Pressure Advance

- `pressure_advance` not set (0 or absent) in `[extruder]` → recommend calibration
- `pressure_advance > 1.0` → unusually high, check rotation_distance and extruder type

#### 8. Rotation Distance Sanity

For extruder:
- Direct drive: `rotation_distance` should be 4–10 (typical 7–8 for BMG-style)
- Bowden: `rotation_distance` should be 20–40

For motion axes:
- GT2 belt, 20-tooth pulley: `rotation_distance = 40`
- GT2 belt, 16-tooth pulley: `rotation_distance = 32`
- T8 leadscrew (2mm pitch, 4 starts): `rotation_distance = 8`
- T8 leadscrew (2mm pitch, 1 start): `rotation_distance = 2`

#### 9. PID Tuning

- `control: watermark` → old method, recommend PID calibration
- `pid_Kp`, `pid_Ki`, `pid_Kd` absent → heater has no PID, may be unstable

#### 10. Missing Recommended Sections

Flag as warnings (not errors):
- No `[exclude_object]` → object cancellation unavailable
- No `[firmware_retraction]` → runtime retraction tuning unavailable
- No `[gcode_arcs]` → arc support unavailable
- No `[respond]` → macro feedback may be silent
- No `[pause_resume]` → pause/cancel prints may not work

---

## Phase 4: Live Status Monitoring

### Query Printer Objects

Klipper exposes live state via Moonraker's objects API:

```bash
# Query everything
curl -s "http://<IP>:7125/printer/objects/query?toolhead&extruder&heater_bed&bed_mesh&probe&print_stats"

# Query specific fields
curl -s "http://<IP>:7125/printer/objects/query?toolhead=position,max_velocity,max_accel&extruder=temperature,target,pressure_advance"
```

Key objects and fields:

| Object | Key fields |
|--------|-----------|
| `toolhead` | `position`, `homed_axes`, `max_velocity`, `max_accel`, `stalls` |
| `extruder` | `temperature`, `target`, `pressure_advance`, `can_extrude` |
| `heater_bed` | `temperature`, `target`, `power` |
| `probe` or `bltouch` | `last_query`, `last_probe_position` |
| `bed_mesh` | `profile_name`, `mesh_min`, `mesh_max`, `probed_matrix` |
| `print_stats` | `state`, `filename`, `total_duration`, `filament_used` |
| `idle_timeout` | `state`, `printing_time` |
| `motion_report` | `live_position`, `live_velocity` |
| `firmware_retraction` | `retract_length`, `retract_speed` |
| `input_shaper` | (queried from configfile) |
| `tmc2209 stepper_x` | `run_current`, `hold_current`, `drv_status`, `temperature` |
| `configfile` | `save_config_pending`, `settings.<section>.<key>` |
| `webhooks` | `state`, `state_message` |
| `system_stats` | `sysload`, `cputime`, `memavail` |

### Send GCode

```bash
curl -s -X POST "http://<IP>:7125/printer/gcode/script" \
  -H "Content-Type: application/json" \
  -d '{"script": "QUERY_ENDSTOPS"}'
```

### Query Endstops

```bash
curl -s "http://<IP>:7125/printer/query_endstops/status"
```

---

## Phase 5: Calibration Sequences

### Probe Z-Offset (PROBE_CALIBRATE)

1. Verify printer is homed: send `G28`
2. Start calibration: `PROBE_CALIBRATE`
3. Guide user through paper test at nozzle
4. Accept: `TESTZ Z=-0.1` (adjust in steps)
5. Finalize: `ACCEPT`
6. Save: `SAVE_CONFIG` (triggers firmware restart automatically)

### Bed Mesh Calibration

1. Home all axes: `G28`
2. Optional: heat bed to print temp first
3. Run: `BED_MESH_CALIBRATE`
4. Save profile: `BED_MESH_PROFILE SAVE=default`
5. Save to config: `SAVE_CONFIG`

### Axis Twist Compensation

**Before running, always validate calibrate_end_x:**
```
max_safe_end_x = stepper_x.position_max + probe.x_offset
```
If `calibrate_end_x > max_safe_end_x` → fix it first (see Phase 2 edit workflow)

Then:
1. Home: `G28`
2. Run: `AXIS_TWIST_COMPENSATION_CALIBRATE`
3. Follow prompts for paper test at each probe point
4. Save: `SAVE_CONFIG`

### PID Tuning

Hotend:
```gcode
PID_CALIBRATE HEATER=extruder TARGET=200
SAVE_CONFIG
```

Bed:
```gcode
PID_CALIBRATE HEATER=heater_bed TARGET=60
SAVE_CONFIG
```

### Pressure Advance

Method 1 — Tuning tower (manual):
```gcode
SET_VELOCITY_LIMIT SQUARE_CORNER_VELOCITY=1 ACCEL=500
TUNING_TOWER COMMAND=SET_PRESSURE_ADVANCE PARAMETER=ADVANCE START=0 FACTOR=.005
```
Print a tuning tower model. Measure optimal layer. Calculate:
`PA = START + FACTOR × best_layer_height_mm`

Method 2 — Set directly after finding value:
```gcode
SET_PRESSURE_ADVANCE ADVANCE=0.04
```
Then add to `[extruder]` in config and `SAVE_CONFIG`.

### Resonance / Input Shaper Calibration

1. Verify `[adxl345]` or other accelerometer configured
2. Home: `G28`
3. Test accelerometer: `ACCELEROMETER_QUERY`
4. Measure noise baseline: `MEASURE_AXES_NOISE`
5. Calibrate X: `SHAPER_CALIBRATE AXIS=X`
6. Calibrate Y: `SHAPER_CALIBRATE AXIS=Y`
7. Review results and apply recommended shaper
8. `SAVE_CONFIG`

### Screws Tilt Adjust

1. Home: `G28`
2. Run: `SCREWS_TILT_CALCULATE`
3. Read output — each screw shows turn direction (CW/CCW) and amount (HH:MM)
4. Re-run until all screws show < 0:05 deviation

### TMC Driver Diagnostics

Dump driver state:
```gcode
DUMP_TMC STEPPER=stepper_x
DUMP_TMC STEPPER=stepper_y
DUMP_TMC STEPPER=stepper_z
DUMP_TMC STEPPER=extruder
```

Adjust current at runtime (test only — add to config to persist):
```gcode
SET_TMC_CURRENT STEPPER=stepper_x CURRENT=0.8 HOLDCURRENT=0.5
```

---

## Phase 6: Troubleshooting

Use `references/troubleshooting.md` for the full error → cause → fix database.

**Workflow for any error message the user pastes:**

1. Extract the error pattern (error type + coordinates/values if present)
2. Match against known patterns in the troubleshooting reference
3. Pull the relevant config sections from `printer_context.json`
4. Compute the specific fix values using the validation formulas
5. Present the diagnosis with the exact lines to change
6. Offer to apply the fix automatically (Phase 2 edit workflow)

**Common error patterns (quick reference):**

| Error | Cause | Fix |
|-------|-------|-----|
| `Move out of range: X Y Z [step]` | Nozzle would exceed axis limit; often probe offset not accounted in calibration coords | Reduce `calibrate_end_x` / `mesh_max` by `abs(probe.x_offset)` |
| `Must home axis first` | Axes not homed before move command | Run `G28` |
| `Endstop stepper_x still triggered` | Endstop stuck or wiring fault | Check `QUERY_ENDSTOPS`, check endstop pin polarity |
| `Unable to read tmc uart ... IFCNT` | TMC UART comms failure | Check motor power and UART wiring; power cycle |
| `TMC reports error: ... OvertempError` | TMC driver too hot | Reduce `run_current`, improve cooling |
| `TMC reports error: ShortToGND` | Shorted motor wire | Check motor wiring |
| `TMC reports error: Undervoltage` | PSU voltage dip | Check PSU and wiring connections |
| `Heater extruder not heating at expected rate` | PID tuning needed or heater/sensor issue | Run `PID_CALIBRATE HEATER=extruder TARGET=200` |
| `Probe triggered prior to movement` | BLTouch in wrong state or z_offset too high | Run `BLTOUCH_DEBUG COMMAND=reset` then re-home |
| `Timeout on connect` | Moonraker not running or wrong IP | Verify printer IP and that Moonraker is running |
| `Lost communication with MCU` | USB disconnect or firmware crash | Run `FIRMWARE_RESTART`; check USB cable |

---

## Phase 7: Config Section Reference

Use `references/config_sections.md` for the complete parameter reference.

Key sections and their most commonly tuned parameters:

### [printer]
```ini
kinematics: cartesian          # cartesian|corexy|corexz|delta|deltesian|polar
max_velocity: 300              # mm/s — runtime tunable via SET_VELOCITY_LIMIT
max_accel: 7000                # mm/s² — runtime tunable
max_z_velocity: 15             # mm/s (cartesian only)
max_z_accel: 100               # mm/s² (cartesian only)
minimum_cruise_ratio: 0.5      # 0.0–1.0, reduces top speed of short moves
square_corner_velocity: 5.0    # mm/s, higher = less deceleration at corners
```

### [stepper_x/y/z]
```ini
rotation_distance: 40          # mm per full motor rotation
microsteps: 16                 # 8|16|32|64|128
position_min: 0                # soft limit minimum
position_max: 246              # soft limit maximum — CRITICAL for range checks
position_endstop: 0            # endstop position (must match position_min or position_max)
homing_speed: 80               # mm/s
```

### [extruder]
```ini
rotation_distance: 7.687       # mm per motor rotation (direct drive ~7-8, bowden ~20-40)
nozzle_diameter: 0.400
pressure_advance: 0.04         # 0 = disabled; typical range 0.02–0.12 for direct
pressure_advance_smooth_time: 0.04
max_extrude_cross_section: 5   # max mm² cross section (4 × nozzle_diameter² is safe default)
```

### [bltouch] / [probe]
```ini
x_offset: -62                  # probe X position relative to nozzle (negative = left of nozzle)
y_offset: -12                  # probe Y position relative to nozzle (negative = in front)
# z_offset: stored in SAVE_CONFIG block
samples: 3                     # number of probe samples
samples_result: median         # average|median
sample_retract_dist: 5.0
samples_tolerance: 0.01        # max deviation between samples (mm)
samples_tolerance_retries: 3
```

### [bed_mesh]
```ini
mesh_min: 60, 30               # PROBE coordinates (not nozzle!)
mesh_max: 170, 220             # PROBE coordinates
probe_count: 5, 5              # grid points per axis
algorithm: bicubic             # lagrange (≤3×3) | bicubic (≥4×4 recommended)
fade_start: 1                  # mm height to start fading mesh correction
fade_end: 10                   # mm height where mesh correction reaches zero (0=disabled)
```

### [axis_twist_compensation]
```ini
calibrate_start_x: 20         # PROBE X coordinate — nozzle = start_x - x_offset
calibrate_end_x: 183          # PROBE X coordinate — nozzle = end_x - x_offset
calibrate_y: 117.5            # PROBE Y coordinate — nozzle = calibrate_y - y_offset
# Rule: nozzle must be within [position_min, position_max]
# Formula: calibrate_end_x <= position_max + x_offset  (when x_offset < 0)
```

### [safe_z_home]
```ini
home_xy_position: 108.5, 117.5  # NOZZLE position for Z homing (not probe!)
speed: 120
z_hop: 10
z_hop_speed: 5
```

### [tmc2209 stepper_x]
```ini
run_current: 0.750             # Amps RMS — start at 70% rated current
hold_current: 0.500            # Optional — Klipper docs recommend omitting
stealthchop_threshold: 999999  # 999999=always stealthChop; 0=always spreadCycle
interpolate: True              # micro-step interpolation (small positional error)
driver_SGTHRS: 255             # stallGuard threshold for sensorless homing (if used)
```

### [input_shaper]
```ini
shaper_type_x: 3hump_ei        # mzv|ei|2hump_ei|3hump_ei|zv|zvd
shaper_freq_x: 66.2            # Hz — from SHAPER_CALIBRATE
shaper_type_y: ei
shaper_freq_y: 45.0
```

### [firmware_retraction]
```ini
retract_length: 0.5            # mm — direct drive: 0.4–1.0; bowden: 4–7
retract_speed: 60              # mm/s
unretract_extra_length: 0
unretract_speed: 60
```

---

## Moonraker API Quick Reference

Base URL: `http://<IP>:7125`

| Method | Endpoint | Purpose |
|--------|----------|---------|
| GET | `/printer/info` | Klipper state, version, hostname |
| GET | `/server/files/config/printer.cfg` | Read printer.cfg |
| GET | `/server/files/list?root=config` | List all config files |
| POST | `/server/files/upload` (multipart) | Upload/overwrite a config file |
| POST | `/printer/firmware_restart` | Firmware restart (apply config changes) |
| POST | `/printer/gcode/script` | Send GCode command (JSON body: `{"script":"..."}`) |
| GET | `/printer/objects/list` | List all queryable printer objects |
| GET | `/printer/objects/query?<obj>=<fields>` | Query live printer state |
| GET | `/printer/query_endstops/status` | Endstop states |
| POST | `/printer/gcode/script` `{"script":"SAVE_CONFIG"}` | Persist calibration data |
| GET | `/server/info` | Moonraker version, registered components |
| POST | `/machine/reboot` | Reboot the host (Pi) |
| POST | `/machine/shutdown` | Shutdown the host |

### File Upload (curl)
```bash
curl -X POST "http://<IP>:7125/server/files/upload" \
  -F "root=config" \
  -F "file=@/path/to/printer.cfg;filename=printer.cfg"
```

### GCode Send (curl)
```bash
curl -X POST "http://<IP>:7125/printer/gcode/script" \
  -H "Content-Type: application/json" \
  -d '{"script": "G28"}'
```

### Object Query (curl)
```bash
curl "http://<IP>:7125/printer/objects/query?extruder&heater_bed&toolhead"
```

---

## Platform Notes

The AI performs all config fetching, parsing, and editing **inline** using `curl` (available
on both Windows and Linux) and direct text analysis. The scripts in `scripts/` are provided
as reference implementations and work on **Linux/macOS** (require `python3`). On Windows,
the AI executes the equivalent logic directly — do not rely on the shell scripts.

When running on the Klipper host directly (via SSH), the scripts work without modification.

---

## File Structure

```
klipper-manager/
├── SKILL.md                         # This file
├── references/
│   ├── config_sections.md           # Full parameter reference for all config sections
│   ├── gcodes.md                    # All supported G-codes and extended commands
│   ├── troubleshooting.md           # Error patterns → causes → fixes
│   └── moonraker_api.md             # Full Moonraker API reference
├── scripts/
│   ├── fetch_config.sh              # Fetch printer.cfg from Moonraker
│   ├── upload_config.sh             # Upload modified config
│   ├── send_gcode.sh                # Send a GCode command
│   ├── query_status.sh              # Query printer status objects
│   └── diagnose.sh                  # Full diagnostic run
└── state/
    └── printer_context.json         # Persisted printer state (auto-created)
```

Base directory: `file:///C:/Users/santi/.config/opencode/skills/klipper-manager`

