知識がなくても始められる、AIと共にある豊かな毎日。
AI Coding

Having AI Write a G-code Rewriting Plugin and Checking It — Do the Pause, Temperature and Fan Land on the Right Layer?

swiftwand

Pause at layer 30 to embed a nut, raise the nozzle temperature a little from layer 50, and turn up the part-cooling fan from layer 70. Changes like these, aimed at specific layers, can be added by rewriting the exported G-code afterwards. The question is whether that rewrite really lands at layers 30, 50 and 70 — once each — without breaking other lines.

This article contains affiliate links. As an Amazon Associate, we earn from qualifying purchases.

So we had AI write G-code rewriting code and checked whether it lands on the intended layers. What we had it write was the rewriting part of a Python plugin that post-processes G-code within the slicing pipeline, newly added in OrcaSlicer 2.5.0-alpha (published 2026-10-16, pre-release). We had claude -p write it, extracted only the rewriting function, and applied it to G-code sliced with our local Bambu Studio CLI (2.8.4.57, a Public Beta published 2026-09-22) and, for comparison, with the OrcaSlicer 2.5 CLI. The plugin was not run inside OrcaSlicer.

The results first. The more material we gave the AI, the closer the G-code rewriting got to the target. With no documents, it did not take the form of a plugin (saying it could not confirm the API, it returned a standalone script) and nothing ran. With the official wiki and official samples, it guessed the layer marker wrong and changed nothing. Only in the condition where we also showed an excerpt of real G-code did the pause, temperature and fan all land — on the output we had shown. But when the same plugin was applied to another slicer’s output, the pause landed one layer off. Each condition was run once.

忍者AdMax

Before handing G-code rewriting to AI — “optimization” versus “verification”

In LLM G-code optimization: large language models writing “faster than human” toolpaths (published 2026-02-27), we covered post-processing exported G-code with an LLM to speed it up — reordering travel paths, tuning retraction, converting to Klipper macros. The goal of that article was to rework G-code cleverly.

The goal of this article is closer to the opposite. Rather than reworking anything, we check whether changes a person decided in advance — stop at this layer, change the temperature from that layer — land correctly on the intended layers. G-code rewriting itself is simple; the hard part is reading from the output G-code “where to put it”.

That difference shows up directly in how layer boundaries are written. That article cited ;LAYER_CHANGE as the layer marker for Klipper integration. It is the generic Slic3r-family form, and OrcaSlicer writes it too when a non-Bambu printer is selected. But for Bambu Lab printers, both OrcaSlicer and Bambu Studio write the layer boundary as ; CHANGE_LAYER. The same “layer change” uses a different string, so generalizing ;LAYER_CHANGE as is will miss. As we will see, this is exactly where the AI stumbled.

Where a post-processing plugin receives the G-code — psGCodePostProcess in the Slicing Pipeline

OrcaSlicer 2.5 plugins step into fixed stages of the slicing process (the Slicing Pipeline). There are 13 stages in all, and G-code post-processing is one of them, named Step.psGCodePostProcess. This stage runs after the classic post-processing scripts.

The hand-off is not a string. The G-code is passed as the path of a working file (ctx.gcode_path), and the plugin rewrites that file in place. The description in the official samples also says that at this stage ctx.print and ctx.object are None, and ctx.gcode_path is provided instead. The setting lives in the process settings under Others: Slicing Pipeline Plugin (Advanced).

The shape of the plugin is shown by the official G-code Stamp sample. In short, the capability class has execute(self, ctx), and if it is not the post-processing stage it does nothing and returns success.

class GCodeStamp(orca.slicing.SlicingPipelineCapabilityBase):
    def execute(self, ctx):
        if ctx.step != orca.slicing.Step.psGCodePostProcess:
            return orca.ExecutionResult.success()
        # open the file at ctx.gcode_path and rewrite it

The source is OrcaSlicer’s sample sandboxes/orca_gcode_stamp_plugin_any.py (commit 3880f2c, AGPL-3.0); check the full text via the Sources at the end. Registration calls orca.register_capability from a class decorated with @orca.plugin. A plugin takes the form of a single .py file or a .whl.

There are two cautions. One is that this mechanism is new, and the project states that the API may change. The other is that post-processing (scripts and plugins alike) does not run under the CLI. In both OrcaSlicer and Bambu Studio, the lines that would call post-processing from the CLI are commented out in the source, and the error list contains a message saying the CLI does not support post-processing. That is why this article’s check does not run the plugin in the interface; it extracts the rewriting function and applies it to G-code.

How failures are handled is worth knowing too. If a post-processing plugin raises an exception or returns failure, OrcaSlicer treats it as an ordinary slicing error. The official release notes also say that plugin errors show up as ordinary slicing errors rather than crashing OrcaSlicer. So if post-processing throws or fails, you do not silently get broken G-code; you get a slicing error. But this mechanism only watches for exceptions, failure results and missing output files — it does not catch “returned success, but the content is not what was intended (layers are off)”. Indeed, in this experiment the wiki condition, which changed nothing, and the real-excerpt condition, which was one layer off, both returned success. Whether a change landed as intended can only be counted with an analyzer, separately from this safety behaviour.

Test conditions — have AI write the plugin, then apply it outside OrcaSlicer

The procedure was as follows. First, we had claude -p (Claude Code’s non-interactive mode, in a minimal configuration that loads no tools, MCP servers or settings files) write the psGCodePostProcess part of a post-processing plugin. We varied the material given to the AI three ways.

  • No documents: only the task text
  • Official wiki and official samples: OrcaSlicer’s plugin wiki and the official samples in sandboxes/
  • + real G-code excerpt: in addition, an excerpt of actually sliced G-code — its head and its layer boundaries

We extracted the rewriting function from the plugin it wrote and ran it locally rather than inside OrcaSlicer. We prepared a stand-in for the orca module, set ctx.step to the post-processing stage, ctx.gcode_path to a copy of the G-code, and ctx.print and ctx.object to None (as the official samples specify for this stage), and called execute once. Before applying the AI-written code, we read it to confirm it does nothing besides reading and writing the file.

We extracted only the rewriting function rather than the whole plugin because running the loading and registration parts as well would mix the roughness of our reproduction of the mechanism into the behaviour we wanted to test — “how does it rewrite the G-code”. The stand-in orca module resolves only names present in the reference table built from the source, and calling a non-existent name fails on the spot. So when the AI did not take the form of an OrcaSlicer plugin in the no-document condition and returned a standalone script, the fact that no capability was registered showed up directly.

The test G-code was a 20×20×30 mm box (150 layers at 0.2 mm) sliced with our local Bambu Studio CLI (P1S, 0.4 mm nozzle, Generic PLA, single colour). For comparison, the same box was also sliced with the OrcaSlicer 2.5 CLI. An experiment in having AI check setting values themselves is covered in Having AI catch slicer setting mix-ups — testing material, temperature and plate combinations against official profiles (published 2026-10-14). What this article checks is not whether values are correct, but whether decided changes land on the intended layers.

We fixed three changes before running anything: a pause at layer 30, 230 °C from layer 50, and the part-cooling fan at 50% from layer 70. On a 255-step scale, 50% fan equals 255×50÷100 = 127.5. Fan values are written as integers, so the analyzer accepted 127 or 128 (the AI actually wrote 128). Judgment was done by an analyzer written separately from the AI, comparing the original G-code against the rewritten one. It looks at five things: (1) whether a pause (a stop command such as M400 U1) landed exactly once near the start of the intended layer; (2) whether the temperature is the target value on every extruding move from layer 50 to the end; (3) whether the fan is at the target value (127–128) from layer 70 to the end; (4) whether temperature and fan values are unchanged in layers before the changes; and (5) whether the final state at the end, with heaters and fans turned off, matches the original. It checks extruding-move temperatures, fan values and final state rather than line-by-line invariance. We first confirmed with two controls that the scoring works: the official G-code Stamp sample inserted one comment line and succeeded, and a model plugin written by the experimenter met all five items.

The test G-code was sliced with the Bambu Lab P1S settings, and commands such as the M400 U1 pause follow how this printer’s profile writes them.

USD 499.99 on Amazon.com (as of 2026/09/21)

How to count the target layer — 1-based and 0-based numbering mixed in one G-code

Before talking about the offset, we need to fix how “layer N” is counted. The analyzer reads the G-code from the top, advances the layer number each time ; CHANGE_LAYER appears, and treats the layer starting at the N-th ; CHANGE_LAYER as layer N (the first layer is layer 1). The start G-code contains many temperature and fan commands, but since the first ; CHANGE_LAYER has not appeared yet, they are not counted as values of any layer. An extruding move is a move that pushes material forward (positive E).

The tricky part is that numbers counted from 1 and numbers counted from 0 are mixed within the same layer. In Bambu Studio’s output, near each layer boundary there is a progress M73 L and a “layer num/total_layer_count” comment, both 1-based, alongside M991 S0 P, which is 0-based. On the first layer you find M73 L1, the comment 1/150 and M991 S0 P0 together. The total layer count is written before the body as ; total layer number: 150.

This mixture is an entry point for the AI to mistake the layer number. For example, reading the P of M991 S0 P directly as the layer number puts you off by one. To insert a change at the start of the target layer, it must go after the ; CHANGE_LAYER line and before that layer’s first extrusion (a move with X or Y that pushes material forward). The wipe right after the layer boundary (a retracting move) is not an extrusion, so the change must not go there.

Results — the more material, the closer it got, and only the real-excerpt condition landed

Here are the results in a table. Each condition was run once. Across the columns are three of the analyzer’s five items — pause, temperature and fan — plus whether the layers before the changes and the end were left as original.

Material givenSource of G-codeOutcomePauseTemperatureFanEarlier layersEnd
No documentsOrcaSlicer 2.5No capability registered; nothing ran×××MatchMatch
No documentsBambu StudioSame as above×××MatchMatch
Wiki + samplesOrcaSlicer 2.5Layer marker not found; no change×××MatchMatch
Wiki + samplesBambu StudioSame as above×××MatchMatch
+ real excerptOrcaSlicer 2.5Processed 150 layers○○○MatchMatch
+ real excerptBambu StudioProcessed 150 layers× (layer 31)× (from layer 51)○MatchMatch

With no documents, the AI said it “could not confirm the API specification” and did not take the form of an OrcaSlicer plugin. What it returned was a standalone script that takes a G-code path and rewrites it (run via main and arguments), with no part that registers a capability for OrcaSlicer to load. OrcaSlicer’s actual mechanism registers a capability class with orca.register_capability, so without registration the post-processing is never called. As a result, both G-code files stayed as they were.

With the official wiki and samples, the plugin’s form became correct. But it guessed the layer marker as ;LAYER_CHANGE (the generic Slic3r-family form), which did not match the real files written with ; CHANGE_LAYER, so it changed nothing in either G-code. The wording of the layer-marker comment could not be guessed without seeing the real thing.

Only in the condition where we also showed an excerpt of real G-code did changes finally land. Everything was correct, though, only when applied to the same OrcaSlicer 2.5 output whose excerpt we had shown the AI. The pause landed once at the start of layer 30, the temperature was 230 °C from layer 50 to the end, the fan was at the target value from layer 70 to the end, and earlier layers and the end were unchanged.

Results like these depend heavily on what context the model sees. If you want to get better at assembling that context, this book is a good place to start.

USD 54.51 on Amazon.com (as of 2026/09/22)

The same plugin was one layer off on Bambu Studio output

The problem appeared when the same plugin was applied to Bambu Studio’s output. The pause landed at layer 31 rather than 30, and the temperature changed from layer 51 (layer 50 stayed original). Everything shifted back by one layer.

The cause was in how layers were counted. The AI counted layers to match the OrcaSlicer 2.5 output we had shown in the excerpt. The sequence of comments and markers near layer boundaries differs slightly between OrcaSlicer and Bambu Studio output. Because the code counted according to the sequence it had seen, the boundary detection was off by one on Bambu Studio output, where the markers appear differently. As noted above, M991’s P is 0-based; mixtures of 1-based and 0-based numbering and the presence or absence of markers breed offsets like this.

The fan, on the other hand, came out as intended on both outputs. The reason is that the AI did not just insert one line; it rewrote every one of the slicer’s own part-cooling fan commands (M106) from layer 70 to the end. There are two stages here: F1 (did it get inserted) and F2 (does it stay in effect). The original G-code was sliced with Generic PLA, so 39 layers in the body had the slicer’s own M106. Inserting just one line would be overwritten by the slicer’s later M106, and the value would not stay changed from layer 70. The AI avoided this by rewriting every M106 from layer 70 onward. On the Bambu Studio output, the newly inserted line actually landed at layer 71 (because of the layer offset), but since the existing M106 lines from layer 70 onward were rewritten, the value was right from layer 70. So the fan passed, but this is a different operation from “insert one fixed line in one place”.

What this run tells us is that even if the plugin API is used correctly (passing syntax and function checks), changes do not land on the intended layer unless you look at the dialect of the output G-code — its layer markers and layer counting. And code that fits the dialect you showed it can be off by one when applied to another dialect.

A one-layer offset looks small, but it is hard to notice without checking. If the layer where you wanted a pause and the layer where it actually landed differ by one, you cannot tell by eye from the G-code; you only discover “it stopped one layer off” after printing. That is why it is worth counting, with separate code, whether a change landed on the intended layer before printing. The analyzer here is simple — it picks up pauses, temperatures and fans per layer and matches them against the specified numbers 30, 50 and 70 — but it was enough to catch the one-layer offset. When you have AI write code, prepare the yardstick that checks its output with as much care as the code itself.

What the inserted commands mean — M400 U1, M104 and fan numbers

How the inserted commands themselves are written also differs by slicer and printer. Here we base our answers on Bambu Studio’s source and profiles, and refer to the official Marlin documentation only for general meaning. The P1S firmware is Bambu Lab’s own; the profile’s gcode_flavor being marlin is merely a setting for the slicer’s output format.

  • Pause: the G-code Bambu Studio’s P1S profile uses for a pause is M400 U1. The Bambu Lab printer profiles bundled with OrcaSlicer have the same value. We did not check whether M0 or M600 work on the P1S, so “incorrect” was judged by whether it differs from how Bambu Studio writes it
  • Temperature: we treated M104 S230, which changes the target without waiting, as correct. In the Marlin documentation, M109 waits until the target is reached, so whether to include a wait was decided before running and counted separately
  • Fan: in Bambu Studio’s source, the M106 fan number P1 is the part-cooling fan, P2 the auxiliary fan and P3 the chamber fan. However, the part-cooling fan the slicer writes in the body takes the form M106 S<value> with no P, and stopping it is written M106 S0. S ranges from 0 to 255 (S255 is 100%). 50% equals 255×50÷100 = 127.5, but values are written as integers, so the analyzer accepted 127 or 128 (the AI wrote 128). M106 P2 and M106 P3 are different fans, so landing there counted as incorrect

M400 U1, M73 L, M991 and M106 P1/P2/P3 are all Bambu’s way of writing things, and they are either absent from the Marlin documentation or mean something different. That is why, for checking G-code rewriting, we set “the form this slicer writes for this printer” as the correct answer rather than “Marlin in general”.

If you stop mid-print to embed a nut, having a complete set of M3 screws and nuts on hand makes it easier to size the pocket.

USD 8.99 on Amazon.com (as of 2026/09/21)

You can also insert per-layer changes from the interface or with scripts

The same thing can be done from the slicer interface or with post-processing scripts. Here they are side by side.

In both Bambu Studio and OrcaSlicer, right-clicking the handle of the preview layer slider offers “Add Pause” and “Add Custom G-code” (confirmed in the source; we did not operate the interface). PrusaSlicer’s official instructions are to right-click the orange plus icon on the slider and choose “Insert pause print (M601)”. This pause is inserted before the chosen layer starts printing. A pause Bambu Studio itself inserts at a layer also comes “before that layer starts printing”.

There are also post-processing scripts that rewrite exported G-code with an external program. PrusaSlicer 2.x has them under “Print settings – Output options – Post-processing scripts”, and Bambu Studio and OrcaSlicer have a setting under Others in the process settings (the PrusaSlicer 3.0 alpha does not have post-processing scripts yet). They receive the G-code path as an argument and rewrite it in place, which makes them very similar to the post-processing done by this plugin. It is not a feature of any single vendor.

So what is the point of entrusting rewriting to a plugin? Right-clicking in the interface is manual work, and you re-enter the same change every time. With a post-processing script or a plugin, the rules for the change can be written in code. And as code, it can be written by AI. But as we saw, if you have it written without looking at the output dialect, the changes do not land on the intended layers.

What this check cannot tell you

Here are the limits to keep in mind when reading the results.

  • Each condition was run once: three ways of giving material × two slicers’ outputs, once each. These are not numbers to generalize as an accuracy rate
  • The plugin was not run inside OrcaSlicer. The check covers extracting the rewriting function and applying it to G-code produced by the CLI. We did not observe behaviour when loaded as a plugin in the interface
  • We did not check whether post-processing results appear in the preview. The documents contradict each other on this, so this article does not cover it
  • We did not check whether a real printer stops or changes temperature. Judgment stops at “does it match how Bambu Studio writes it”; this site does not use a real printer for these tests
  • The basis for M400 U1 and the fan numbers is Bambu Studio’s source and profiles. We did not check official documentation where Bambu Lab explains this from the firmware side
  • The fan came out as intended because the slicer’s own M106 lines were also rewritten. It is not a single-line insertion. If the original G-code had no later M106 lines, one line might have been enough
  • The original G-code was Generic PLA, single colour, a straight box. With colour changes, sequential printing or vase mode, the mapping between layer markers and layer numbers is no longer simple

Even so, this run shows that G-code rewriting gets closer to the target as more material is given, and that even after seeing the real dialect, the code was one layer off on another slicer’s output.

Summary

  • OrcaSlicer 2.5’s post-processing plugins receive G-code as the path of a working file and rewrite it in place. We had claude -p write this rewriting part, extracted the function and applied it to G-code from the Bambu Studio and OrcaSlicer CLIs (it was not run inside OrcaSlicer)
  • With no documents it did not take a plugin’s form (it returned a standalone script) and did nothing; with the wiki and samples it guessed the layer marker as ;LAYER_CHANGE and changed nothing; only with a real excerpt did the pause, temperature and fan all land on the OrcaSlicer output it had seen
  • Applying the same plugin to Bambu Studio output put the pause at layer 31 and the temperature from layer 51 — one layer off — because layer markers and counting differ between outputs
  • We set “the form this slicer writes for this printer” as the correct command: M400 U1 for the pause, M104 S230 for temperature, and M106 without P for the fan (50% is 127.5; integers 127–128 were accepted)
  • If you entrust G-code rewriting to AI, include the dialect of the G-code it will be applied to in the material — not just whether it can write the plugin API correctly. And do not stop at inserting one line per layer; count with a separate analyzer how the change interacts with commands the slicer rewrites later (such as fans). Change the dialect, and the same code can land one layer off

Sources

ブラウザだけでできる本格的なAI画像生成【ConoHa AI Canvas】
ABOUT ME
swiftwand
swiftwand
AIを使って、毎日の生活をもっと快適にするアイデアや将来像を発信しています。 初心者にもわかりやすく、すぐに取り入れられる実践的な情報をお届けします。 Sharing ideas and visions for a better daily life with AI. Practical tips that anyone can start using right away.
記事URLをコピーしました