diff --git a/OpenNest.Posts.Cincinnati/CincinnatiPreambleWriter.cs b/OpenNest.Posts.Cincinnati/CincinnatiPreambleWriter.cs
new file mode 100644
index 0000000..8cbf0c0
--- /dev/null
+++ b/OpenNest.Posts.Cincinnati/CincinnatiPreambleWriter.cs
@@ -0,0 +1,72 @@
+using System;
+using System.IO;
+using OpenNest;
+
+namespace OpenNest.Posts.Cincinnati;
+
+///
+/// Emits the main program header and variable declaration subprogram
+/// for a Cincinnati laser post-processor output file.
+///
+public sealed class CincinnatiPreambleWriter
+{
+ private readonly CincinnatiPostConfig _config;
+
+ public CincinnatiPreambleWriter(CincinnatiPostConfig config)
+ {
+ _config = config;
+ }
+
+ ///
+ /// Writes the main program header block.
+ ///
+ public void WriteMainProgram(TextWriter w, string nestName, string materialDescription, int sheetCount)
+ {
+ w.WriteLine(CoordinateFormatter.Comment($"NEST {nestName}"));
+ w.WriteLine(CoordinateFormatter.Comment($"CONFIGURATION - {_config.ConfigurationName}"));
+ w.WriteLine(CoordinateFormatter.Comment(DateTime.Now.ToString("MM-dd-yyyy hh:mm:ss tt")));
+
+ if (!string.IsNullOrEmpty(materialDescription))
+ w.WriteLine(CoordinateFormatter.Comment($"Material = {materialDescription}"));
+
+ if (_config.UseExactStopMode)
+ w.WriteLine("G61");
+
+ w.WriteLine(CoordinateFormatter.Comment("MAIN PROGRAM"));
+
+ w.WriteLine(_config.PostedUnits == Units.Millimeters ? "G21" : "G20");
+
+ w.WriteLine("M42");
+
+ if (_config.ProcessParameterMode == G89Mode.LibraryFile && !string.IsNullOrEmpty(_config.DefaultLibraryFile))
+ w.WriteLine($"G89 P {_config.DefaultLibraryFile}");
+
+ w.WriteLine($"M98 P{_config.VariableDeclarationSubprogram} (Variable Declaration)");
+
+ w.WriteLine("GOTO1 (GOTO SHEET NUMBER)");
+
+ for (var i = 1; i <= sheetCount; i++)
+ {
+ var subNum = _config.SheetSubprogramStart + (i - 1);
+ w.WriteLine($"N{i}M98 P{subNum} (SHEET {i})");
+ }
+
+ w.WriteLine("M42");
+ w.WriteLine("M30 (END OF MAIN)");
+ }
+
+ ///
+ /// Writes the variable declaration subprogram block.
+ ///
+ public void WriteVariableDeclaration(TextWriter w, ProgramVariableManager vars)
+ {
+ w.WriteLine("(*****************************************************)");
+ w.WriteLine($":{_config.VariableDeclarationSubprogram}");
+ w.WriteLine("(Variable Declaration Start)");
+
+ foreach (var line in vars.EmitDeclarations())
+ w.WriteLine(line);
+
+ w.WriteLine("M99 (Variable Declaration End)");
+ }
+}
diff --git a/OpenNest.Tests/Cincinnati/CincinnatiPreambleWriterTests.cs b/OpenNest.Tests/Cincinnati/CincinnatiPreambleWriterTests.cs
new file mode 100644
index 0000000..7481913
--- /dev/null
+++ b/OpenNest.Tests/Cincinnati/CincinnatiPreambleWriterTests.cs
@@ -0,0 +1,97 @@
+using System.IO;
+using System.Text;
+using OpenNest.Posts.Cincinnati;
+
+namespace OpenNest.Tests.Cincinnati;
+
+public class CincinnatiPreambleWriterTests
+{
+ [Fact]
+ public void WriteMainProgram_EmitsHeader()
+ {
+ var config = new CincinnatiPostConfig
+ {
+ ConfigurationName = "CL940",
+ PostedUnits = Units.Inches,
+ DefaultLibraryFile = "MS135N2PANEL.lib"
+ };
+ var sb = new StringBuilder();
+ using var sw = new StringWriter(sb);
+ var writer = new CincinnatiPreambleWriter(config);
+
+ writer.WriteMainProgram(sw, "TestNest", "Mild Steel, 10GA", 2);
+
+ var output = sb.ToString();
+ Assert.Contains("( NEST TestNest )", output);
+ Assert.Contains("( CONFIGURATION - CL940 )", output);
+ Assert.Contains("G20", output);
+ Assert.Contains("M42", output);
+ Assert.Contains("G89 P MS135N2PANEL.lib", output);
+ Assert.Contains("M98 P100 (Variable Declaration)", output);
+ Assert.Contains("GOTO1 (GOTO SHEET NUMBER)", output);
+ Assert.Contains("N1M98 P101 (SHEET 1)", output);
+ Assert.Contains("N2M98 P102 (SHEET 2)", output);
+ Assert.Contains("M30 (END OF MAIN)", output);
+ }
+
+ [Fact]
+ public void WriteMainProgram_EmitsG21ForMetric()
+ {
+ var config = new CincinnatiPostConfig { PostedUnits = Units.Millimeters };
+ var sb = new StringBuilder();
+ using var sw = new StringWriter(sb);
+ var writer = new CincinnatiPreambleWriter(config);
+
+ writer.WriteMainProgram(sw, "Test", "", 1);
+
+ Assert.Contains("G21", sb.ToString());
+ }
+
+ [Fact]
+ public void WriteMainProgram_EmitsG61_WhenExactStop()
+ {
+ var config = new CincinnatiPostConfig { UseExactStopMode = true };
+ var sb = new StringBuilder();
+ using var sw = new StringWriter(sb);
+ var writer = new CincinnatiPreambleWriter(config);
+
+ writer.WriteMainProgram(sw, "Test", "", 1);
+
+ Assert.Contains("G61", sb.ToString());
+ }
+
+ [Fact]
+ public void WriteMainProgram_OmitsG61_WhenNotExactStop()
+ {
+ var config = new CincinnatiPostConfig { UseExactStopMode = false };
+ var sb = new StringBuilder();
+ using var sw = new StringWriter(sb);
+ var writer = new CincinnatiPreambleWriter(config);
+
+ writer.WriteMainProgram(sw, "Test", "", 1);
+
+ Assert.DoesNotContain("G61", sb.ToString());
+ }
+
+ [Fact]
+ public void WriteVariableDeclaration_EmitsSubprogram()
+ {
+ var config = new CincinnatiPostConfig();
+ var vars = new ProgramVariableManager();
+ vars.GetOrCreate("LeadInFeedrate", 126, "[#148*0.5]");
+ vars.GetOrCreate("CircleFeedrate", 128, ".8");
+
+ var sb = new StringBuilder();
+ using var sw = new StringWriter(sb);
+ var writer = new CincinnatiPreambleWriter(config);
+
+ writer.WriteVariableDeclaration(sw, vars);
+
+ var output = sb.ToString();
+ Assert.Contains(":100", output);
+ Assert.Contains("(Variable Declaration Start)", output);
+ Assert.Contains("#126=", output);
+ Assert.Contains("#128=", output);
+ Assert.Contains("M99 (Variable Declaration End)", output);
+ }
+}