diff --git a/WhiteMagic/Assembly/IAssembler.cs b/WhiteMagic/Assembly/IAssembler.cs
new file mode 100644
index 0000000..321c4d8
--- /dev/null
+++ b/WhiteMagic/Assembly/IAssembler.cs
@@ -0,0 +1,17 @@
+namespace WhiteMagic.Assembly;
+
+///
+/// Abstraction over an x86/x64 assembler. The default
+/// hand-emits calling-convention trampolines (no parsing, zero dep). An optional
+/// (Phase 8) handles arbitrary mnemonics via the Iced
+/// library.
+///
+public interface IAssembler
+{
+ ///
+ /// Assembles text mnemonics into machine code.
+ ///
+ /// The assembly text (Intel syntax).
+ /// The base address for relative encodings.
+ byte[] Assemble(string assemblyText, ulong origin = 0);
+}
diff --git a/WhiteMagic/Assembly/StubAssembler.cs b/WhiteMagic/Assembly/StubAssembler.cs
new file mode 100644
index 0000000..2d24a59
--- /dev/null
+++ b/WhiteMagic/Assembly/StubAssembler.cs
@@ -0,0 +1,49 @@
+namespace WhiteMagic.Assembly;
+
+///
+/// The default backend. Hand-emits calling-convention
+/// trampolines and injection stubs using deterministic byte emitters
+/// (, , ). Has
+/// no native or third-party dependency — no FASM, no Iced.
+///
+///
+/// is not supported by this backend (it is a parse-free
+/// emitter, not a text assembler). Use (Phase 8) for
+/// arbitrary mnemonics.
+///
+public class StubAssembler : IAssembler
+{
+ ///
+ /// Always thrown. StubAssembler does
+ /// not parse text assembly; use IcedAssembler for that.
+ public byte[] Assemble(string assemblyText, ulong origin = 0)
+ {
+ throw new NotSupportedException(
+ "StubAssembler does not parse text assembly. " +
+ "Use IcedAssembler (Phase 8) for arbitrary mnemonics.");
+ }
+
+ // ── Emit primitives ────────────────────────────────────────────────────
+
+ /// Appends a single byte to .
+ public void EmitU8(List buffer, byte value)
+ {
+ buffer.Add(value);
+ }
+
+ /// Appends as 4 little-endian bytes.
+ public void EmitU32(List buffer, uint value)
+ {
+ buffer.Add((byte)value);
+ buffer.Add((byte)(value >> 8));
+ buffer.Add((byte)(value >> 16));
+ buffer.Add((byte)(value >> 24));
+ }
+
+ /// Appends as 8 little-endian bytes.
+ public void EmitU64(List buffer, ulong value)
+ {
+ EmitU32(buffer, (uint)value);
+ EmitU32(buffer, (uint)(value >> 32));
+ }
+}
diff --git a/WhiteMagicTest/StubAssemblerTests.cs b/WhiteMagicTest/StubAssemblerTests.cs
new file mode 100644
index 0000000..e004a53
--- /dev/null
+++ b/WhiteMagicTest/StubAssemblerTests.cs
@@ -0,0 +1,78 @@
+using WhiteMagic.Assembly;
+
+namespace WhiteMagicTest;
+
+///
+/// Tests for emit primitives (,
+/// , ) and the
+/// interface contract.
+///
+public class StubAssemblerTests
+{
+ private static StubAssembler Create() => new();
+
+ // ── Emit primitives ────────────────────────────────────────────────────
+
+ [Fact]
+ public void EmitU8_appends_a_single_byte()
+ {
+ var sut = Create();
+ var buffer = new List();
+ sut.EmitU8(buffer, 0xAB);
+ Assert.Equal([0xAB], buffer);
+ }
+
+ [Fact]
+ public void EmitU32_appends_little_endian()
+ {
+ var sut = Create();
+ var buffer = new List();
+ sut.EmitU32(buffer, 0x11223344);
+ Assert.Equal([0x44, 0x33, 0x22, 0x11], buffer);
+ }
+
+ [Fact]
+ public void EmitU32_appends_zero()
+ {
+ var sut = Create();
+ var buffer = new List();
+ sut.EmitU32(buffer, 0);
+ Assert.Equal([0x00, 0x00, 0x00, 0x00], buffer);
+ }
+
+ [Fact]
+ public void EmitU64_appends_little_endian()
+ {
+ var sut = Create();
+ var buffer = new List();
+ sut.EmitU64(buffer, 0x1122334455667788);
+ byte[] expected = [0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11];
+ Assert.Equal(expected, buffer);
+ }
+
+ [Fact]
+ public void EmitU64_appends_high_bits()
+ {
+ var sut = Create();
+ var buffer = new List();
+ sut.EmitU64(buffer, 0xDEADBEEF_CAFEBABE);
+ byte[] expected = [0xBE, 0xBA, 0xFE, 0xCA, 0xEF, 0xBE, 0xAD, 0xDE];
+ Assert.Equal(expected, buffer);
+ }
+
+ // ── IAssembler interface ───────────────────────────────────────────────
+
+ [Fact]
+ public void StubAssembler_is_an_IAssembler()
+ {
+ var sut = Create();
+ Assert.IsAssignableFrom(sut);
+ }
+
+ [Fact]
+ public void Assemble_from_StubAssembler_throws_NotSupported()
+ {
+ var sut = Create();
+ Assert.Throws(() => sut.Assemble("nop", 0));
+ }
+}