<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://fjzeit.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://fjzeit.github.io/" rel="alternate" type="text/html" /><updated>2026-08-08T12:02:15+00:00</updated><id>https://fjzeit.github.io/feed.xml</id><title type="html">fjzeit.github.io</title><author><name>fj zeit</name></author><entry><title type="html">Lode Coded Project vs Raw Code</title><link href="https://fjzeit.github.io/lode/lode-vs-raw" rel="alternate" type="text/html" title="Lode Coded Project vs Raw Code" /><published>2026-05-01T00:00:00+00:00</published><updated>2026-05-01T00:00:00+00:00</updated><id>https://fjzeit.github.io/lode/lode-vs-raw</id><content type="html" xml:base="https://fjzeit.github.io/lode/lode-vs-raw"><![CDATA[<p>Here I compare two reports run against the same repo.</p>

<p>The project, SP/M, is a hardware bring-up OS for ESP32 microcontrollers. It provides an interactive shell for GPIO/I2C/SPI/ADC experimentation, a script interpreter for automated diagnostics and prototyping, and a built-in ed editor. The goal is fast iteration during hardware development. Allowing developers to test their board, and their software without compile/flash cycles.</p>

<h2 id="setup">Setup</h2>

<p>The reports were generated using my own micro-IDE which is specifically designed to support the lode coding method and other conversational AI assisted development.</p>

<p>In <em>Report A</em> the model had exposure to the entire project, including its lode.</p>

<p>In <em>Report B</em> the lode was removed, leaving only the code. I also had to remove the .git folder as on first run the model decided to extract the lode files from git history… surprisingly.</p>

<p>Each report was generated from a fresh empty session.</p>

<h2 id="comparison-overview">Comparison Overview</h2>

<p>This comparison reveals something important about knowledge representation for code understanding, and Lode Coding in particular.</p>

<p>The lode-enabled model had structured knowledge built as a byproduct of lode coding the SP/M system. This knowledge shaped how the model understood the system and responded to the question <em>“explain the OS aspects of this implementation”</em>.</p>

<p>The lode provided additional project history and context that source code alone cannot. Specifically:</p>

<ul>
  <li>
    <p><strong>Conceptual framing</strong>: The CP/M heritage and design philosophy came through clearly in Report A. Source code shows how things work, but the lode captures why they were designed that way.</p>
  </li>
  <li>
    <p><strong>Architecture-first thinking</strong>: Report A’s clean layering diagram and “what’s NOT there” section shows how the lode captured high-level design decisions. Reading code bottom-up makes it harder to extract these architectural choices.</p>
  </li>
  <li>
    <p><strong>Domain context</strong>: Terms like “TPA”, “jump table”, “Harvard architecture implications” were used with more precision in Report A with the lode providing the conceptual vocabulary that made these explanations clearer.</p>
  </li>
  <li>
    <p><strong>Pedagogical structure</strong>: Report A’s flow (architecture → process → memory → filesystem → loading) shows the lode captured a narrative and mental model, not just facts.</p>
  </li>
</ul>

<p>Report B is mostly correct and demonstrates the model successfully reverse-engineered the OS
from source. Although it does infer some behaviours from the technology used, and hallucinates the meaning of the name SP/M.</p>

<p>Report A reads like it was written by someone who designed the system, while Report B reads like it was
written by someone who studied it. The lode captures design intent and conceptual models that are not visible from the code alone.</p>

<p>This is a compelling argument for structured knowledge representation and Lode Coding by providing the conceptual scaffolding necessary for sustained development and quality model interaction.</p>

<p>I have provided both reports below in case you’re interested.</p>

<h2 id="stats">Stats</h2>

<p>Model: Kimi-K2.6 (Ollama Cloud, 256K context)</p>

<table>
  <thead>
    <tr>
      <th>Report</th>
      <th>Time</th>
      <th>Turns</th>
      <th>Tool Calls</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>A</td>
      <td>46s</td>
      <td>8</td>
      <td>19</td>
    </tr>
    <tr>
      <td>B</td>
      <td>1m 27s</td>
      <td>9</td>
      <td>24</td>
    </tr>
  </tbody>
</table>

<h2 id="report-a---generated-from-the-full-project-include-its-lode">Report A - generated from the full project, include its Lode</h2>

<p><strong>Prompt</strong>: <em>explain the OS aspects of this implementation</em></p>

<hr />
<p><em>[intermediate turns redacted for brevity]</em></p>

<p><em>The user wants me to explain the OS aspects of this implementation. I now have a comprehensive understanding from the lode files and source code. Let me synthesize this into a clear, structured explanation covering the key OS aspects:</em></p>

<ol>
  <li><em><strong>System Architecture &amp; Layering</strong> - How SP/M is structured as an OS</em></li>
  <li><em><strong>Process Model</strong> - What runs and how (CCP shell, transient programs, scripts)</em></li>
  <li><em><strong>Memory Management</strong> - TPA, IRAM/DRAM split, Harvard architecture handling</em></li>
  <li><em><strong>File System</strong> - VFS, mount points, aliases</em></li>
  <li><em><strong>Program Loading &amp; Execution</strong> - .SPM format, relocations, jump table (syscall interface)</em></li>
  <li><em><strong>Concurrency</strong> - Dual-core model (Core 0 vs Core 1)</em></li>
  <li><em><strong>Device/Hardware Interface</strong> - HAL, shell commands</em></li>
  <li><em><strong>What’s NOT there</strong> - No MMU, no preemptive multitasking, no networking</em></li>
</ol>

<p><em>Let me provide a comprehensive but concise explanation.</em></p>

<hr />

<p>SP/M is a minimal operating system for ESP32 microcontrollers, built on top of FreeRTOS/ESP-IDF but presenting its own distinct OS personality. Here are the key OS aspects:</p>

<h3 id="1-system-architecture--layering">1. System Architecture &amp; Layering</h3>

<p>SP/M follows a layered design with clear separation between kernel services and user code:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>┌────────────────────────────────────────────┐
│  User Space: Scripts (.sps)                │
│  Transient Programs (.spm)                 │
├────────────────────────────────────────────┤
│  Kernel: CCP   │ VFS │ Loader │ Script     │
│          Shell │     │        │ Interpreter│
├────────────────────────────────────────────┤
│  HAL (GPIO, UART, I2C, SPI, ADC)           │
├────────────────────────────────────────────┤
│  ESP-IDF (FreeRTOS, drivers)               │
└────────────────────────────────────────────┘
</code></pre></div></div>

<p>The kernel is monolithic — all services (shell, filesystem, loader, interpreter) compile into a single binary (~440KB).</p>

<h3 id="2-process-model">2. Process Model</h3>

<p>SP/M has <strong>no processes</strong> in the traditional sense. Instead, it has three execution contexts:</p>

<table>
  <thead>
    <tr>
      <th>Context</th>
      <th>Type</th>
      <th>Lifetime</th>
      <th>Core</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>CCP Shell</strong></td>
      <td>Infinite loop</td>
      <td>Forever</td>
      <td>Core 0</td>
    </tr>
    <tr>
      <td><strong>Transient Programs</strong></td>
      <td>Loaded binary</td>
      <td>Until exit</td>
      <td>Core 1 (dual-core)</td>
    </tr>
    <tr>
      <td><strong>Scripts</strong></td>
      <td>Interpreted text</td>
      <td>Until completion</td>
      <td>Core 0</td>
    </tr>
  </tbody>
</table>

<p>There is <strong>no preemptive multitasking</strong>. Only one transient program or script runs at a time. The shell blocks during script execution and remains responsive during transient program execution (because programs run on Core 1).</p>

<h3 id="3-memory-management">3. Memory Management</h3>

<p>SP/M runs on ESP32’s <strong>Harvard architecture</strong>, which has separate executable (IRAM) and data (DRAM) memory regions. The OS handles this explicitly:</p>

<ul>
  <li><strong>TPA (Transient Program Area)</strong>: Dynamically allocated region for loading user programs
    <ul>
      <li><strong>IRAM region</strong>: 32KB for <code class="language-plaintext highlighter-rouge">.text</code> (code), allocated with <code class="language-plaintext highlighter-rouge">MALLOC_CAP_EXEC</code></li>
      <li><strong>DRAM region</strong>: 16KB for <code class="language-plaintext highlighter-rouge">.rodata</code>, <code class="language-plaintext highlighter-rouge">.data</code>, <code class="language-plaintext highlighter-rouge">.bss</code>, allocated with <code class="language-plaintext highlighter-rouge">MALLOC_CAP_8BIT</code></li>
      <li><strong>Stack</strong>: 8KB provided by FreeRTOS</li>
    </ul>
  </li>
</ul>

<p>The loader performs <strong>IRAM-safe memory operations</strong> because IRAM requires 32-bit aligned access — byte-level <code class="language-plaintext highlighter-rouge">memcpy</code>/<code class="language-plaintext highlighter-rouge">memset</code> will crash. The loader uses word-aligned copies.</p>

<p>There is <strong>no virtual memory</strong>, <strong>no memory protection</strong>, and <strong>no address space isolation</strong>. Everything shares the same physical address space.</p>

<h3 id="4-file-system--vfs">4. File System &amp; VFS</h3>

<p>SP/M implements a <strong>Virtual File System</strong> layer on top of ESP-IDF’s VFS:</p>

<table>
  <thead>
    <tr>
      <th>Mount Point</th>
      <th>Backend</th>
      <th>Purpose</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">/void/</code></td>
      <td>Virtual</td>
      <td>Always exists, always empty (graceful degradation)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">/nv0/</code></td>
      <td>Internal flash (LittleFS)</td>
      <td>Persistent config/scratch</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">/sd0/</code></td>
      <td>SD card (FAT32)</td>
      <td>Removable storage</td>
    </tr>
  </tbody>
</table>

<p><strong>Path aliases</strong> provide named shortcuts:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">sys:</code> → <code class="language-plaintext highlighter-rouge">/sd0/system/</code> → <code class="language-plaintext highlighter-rouge">/nv0/system/</code> → <code class="language-plaintext highlighter-rouge">/void/</code> (cascading fallback)</li>
  <li><code class="language-plaintext highlighter-rouge">null:</code> → <code class="language-plaintext highlighter-rouge">/void/</code></li>
</ul>

<p>The VFS root <code class="language-plaintext highlighter-rouge">/</code> is a virtual namespace — it lists mount points but cannot be opened with <code class="language-plaintext highlighter-rouge">opendir()</code>.</p>

<h3 id="5-program-loading--execution-model">5. Program Loading &amp; Execution Model</h3>

<p>SP/M’s most distinctive OS feature is its <strong>transient program system</strong> — a deliberate homage to CP/M’s COM files:</p>

<h4 id="the-spm-format">The .SPM Format</h4>

<p>A custom binary format (28-byte header + sections + relocation table):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[header: magic, version, entry, sizes]
[.text section]
[.rodata section]
[.data section]
[relocation table]
</code></pre></div></div>

<h4 id="loading-process">Loading Process</h4>

<ol>
  <li>Read header, validate magic (<code class="language-plaintext highlighter-rouge">SPM\x01</code>) and version</li>
  <li>Allocate IRAM (for code) and DRAM (for data) separately</li>
  <li>Copy sections into respective regions</li>
  <li><strong>Apply relocations</strong> — translate addresses from the original contiguous ELF layout to the split IRAM/DRAM runtime layout</li>
  <li>Launch program</li>
</ol>

<h4 id="the-jump-table-system-call-interface">The Jump Table (System Call Interface)</h4>

<p>Transient programs cannot call ESP-IDF directly. Instead, the kernel passes a <strong>function pointer table</strong> (<code class="language-plaintext highlighter-rouge">spm_table_t</code>) at program entry:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="n">spm_table</span> <span class="p">{</span>
    <span class="c1">// Console I/O</span>
    <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">putchar_fn</span><span class="p">)(</span><span class="kt">int</span> <span class="n">c</span><span class="p">);</span>
    <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">getchar_fn</span><span class="p">)(</span><span class="kt">void</span><span class="p">);</span>
    
    <span class="c1">// File I/O (POSIX-like)</span>
    <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">open_fn</span><span class="p">)(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">path</span><span class="p">,</span> <span class="kt">int</span> <span class="n">flags</span><span class="p">);</span>
    <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">read_fn</span><span class="p">)(</span><span class="kt">int</span> <span class="n">fd</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">buf</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">n</span><span class="p">);</span>
    <span class="c1">// ...</span>
    
    <span class="c1">// Hardware</span>
    <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">gpio_set_level</span><span class="p">)(</span><span class="kt">int</span> <span class="n">pin</span><span class="p">,</span> <span class="kt">int</span> <span class="n">level</span><span class="p">);</span>
    <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">i2c_write</span><span class="p">)(</span><span class="kt">uint8_t</span> <span class="n">addr</span><span class="p">,</span> <span class="k">const</span> <span class="kt">uint8_t</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">len</span><span class="p">);</span>
    <span class="c1">// ...</span>
<span class="p">}</span> <span class="n">spm_table_t</span><span class="p">;</span>
</code></pre></div></div>

<p>This is SP/M’s <strong>system call interface</strong>. The SDK header (<code class="language-plaintext highlighter-rouge">sdk/spm.h</code>) shadows ESP-IDF function names with macros that transparently call through the jump table, enabling <strong>dual-target compilation</strong> — the same source compiles as either a transient program or native ESP-IDF firmware.</p>

<h3 id="6-concurrency--multicore">6. Concurrency &amp; Multicore</h3>

<p>On <strong>dual-core ESP32</strong> (ESP32, ESP32-S3):</p>

<ul>
  <li><strong>Core 0</strong>: SP/M kernel, CCP shell, built-in commands, script interpreter</li>
  <li><strong>Core 1</strong>: Transient programs</li>
</ul>

<p>This means you can run a program and still interact with the shell — a deliberate design choice for hardware debugging.</p>

<p>On <strong>single-core variants</strong> (ESP32-C3, ESP32-C6):</p>

<ul>
  <li>Programs run on the same core, blocking the shell until completion.</li>
</ul>

<h3 id="7-command-dispatch--shell">7. Command Dispatch &amp; Shell</h3>

<p>The <strong>CCP (Console Command Processor)</strong> is the OS shell:</p>

<ol>
  <li>Reads lines with full VT100 editing (arrows, history, word navigation)</li>
  <li>Parses into arguments</li>
  <li>Dispatches via hardcoded <code class="language-plaintext highlighter-rouge">if/else</code> chain to built-in commands</li>
  <li>If no built-in matches, attempts to load as transient program (<code class="language-plaintext highlighter-rouge">.spm</code> file)</li>
  <li>Falls back to “Unknown command” if no file found</li>
</ol>

<p>This is <strong>not</strong> a modular command system — built-ins are compiled into the kernel, not loadable modules.</p>

<h3 id="8-what-spm-does-not-have">8. What SP/M Does NOT Have</h3>

<p>These absences are as important as its features:</p>

<ul>
  <li><strong>No MMU / memory protection</strong> — Single address space, programs can access anything</li>
  <li><strong>No preemptive multitasking</strong> — Cooperative execution only</li>
  <li><strong>No networking stack</strong> — Focus is local hardware debugging</li>
  <li><strong>No user/supervisor mode</strong> — Everything runs at the same privilege level</li>
  <li><strong>No dynamic linking</strong> — Programs are statically linked against the jump table ABI</li>
  <li><strong>No process IDs or scheduling</strong> — Just “run until done”</li>
</ul>

<h3 id="summary">Summary</h3>

<p>SP/M is a <strong>single-user, single-tasking, embedded OS</strong> with a deliberately retro design philosophy. It provides just enough OS services to support interactive hardware debugging: a shell, filesystem, program loader with relocations, and a hardware abstraction layer. The jump table mechanism gives it a clean binary interface for user programs without the overhead of a full syscall trap mechanism. It trades completeness for simplicity and fast iteration during hardware bring-up.</p>

<h2 id="report-b---generated-without-a-lode">Report B - Generated without a Lode</h2>

<p><strong>Prompt</strong>: <em>explain the OS aspects of this implementation</em></p>

<hr />
<p><em>[intermediate turns redacted for brevity]</em></p>

<p><em>The user asked me to explain the OS aspects of this implementation. I have gathered enough information to provide a comprehensive answer. Let me summarize the OS-like aspects of this SP/M (Script Processing Module) system:</em></p>

<ol>
  <li><em><strong>Kernel/Shell Architecture</strong>: It’s a single-user, single-tasking command-line OS with a shell (CCP - Console Command Processor) that runs in a loop.</em></li>
  <li><em><strong>Process Model / Transient Programs</strong>: It loads and executes <code class="language-plaintext highlighter-rouge">.spm</code> files (transient programs) via a loader with a jump table (system call interface). This is similar to CP/M or early DOS TPA (Transient Program Area) model.</em></li>
  <li><em><strong>Memory Management</strong>: Split IRAM/DRAM allocation for transient programs, with explicit memory regions (TPA_IRAM_SIZE, TPA_DRAM_SIZE, TPA_STACK_SIZE). Uses ESP32 heap_caps_malloc with MALLOC_CAP_EXEC for executable memory.</em></li>
  <li><em><strong>Multicore/Tasking</strong>: Uses FreeRTOS tasks. Shell runs on Core 0, transient programs run on Core 1 (if dual-core). The shell blocks waiting for the transient program to complete (cooperative multitasking from the shell’s perspective).</em></li>
  <li><em><strong>Virtual File System</strong>: VFS layer with mount points (/void, /sd0, /sd1, /nv0), path resolution, aliases (sys:), and CWD support.</em></li>
  <li><em><strong>Hardware Abstraction Layer (HAL)</strong>: Abstracts GPIO, I2C, SPI, ADC, UART, timers across ESP32 variants.</em></li>
  <li><em><strong>System Call Interface (Jump Table)</strong>: The <code class="language-plaintext highlighter-rouge">spm_table_t</code> provides a structured system call interface for transient programs, shadowing ESP-IDF/FreeRTOS APIs.</em></li>
  <li><em><strong>Scripting Engine</strong>: Built-in interpreter with lexer, parser, AST, and executor - provides an interpreted language environment.</em></li>
  <li><em><strong>Line Editor</strong>: Built-in line editing for the shell.</em></li>
  <li><em><strong>Boot/Initialization Sequence</strong>: NVS init, console init, VFS init, SFT init, then shell.</em></li>
</ol>

<p><em>This is essentially a miniature operating system for ESP32, modeled after classic CP/M concepts but with modern embedded features. Let me provide a clear, structured explanation.</em></p>

<hr />

<p>This project is a miniature <strong>single-user, single-tasking OS for ESP32</strong> called SP/M. It is explicitly modeled after classic CP/M concepts (the name, “Transient Program Area,” <code class="language-plaintext highlighter-rouge">.spm</code> binaries, and the jump-table syscall interface), but built on top of FreeRTOS and ESP-IDF. Here are its OS aspects:</p>

<hr />

<h3 id="1-kernel-architecture">1. Kernel Architecture</h3>

<p>The system follows a <strong>monolithic kernel</strong> design with a clear separation between the resident kernel and transient user programs:</p>

<ul>
  <li><strong>Resident kernel</strong> (<code class="language-plaintext highlighter-rouge">main.c</code>, <code class="language-plaintext highlighter-rouge">ccp/</code>, <code class="language-plaintext highlighter-rouge">exec/</code>, <code class="language-plaintext highlighter-rouge">vfs/</code>, <code class="language-plaintext highlighter-rouge">hal/</code>): Always in memory. Handles hardware, filesystems, shell, and program loading.</li>
  <li><strong>Transient programs</strong> (<code class="language-plaintext highlighter-rouge">.spm</code> files): Loaded into the TPA, executed, and then discarded.</li>
</ul>

<p>The boot sequence in <code class="language-plaintext highlighter-rouge">app_main()</code> is typical of a small OS:</p>

<ol>
  <li>Initialize NVS (non-volatile storage subsystem)</li>
  <li>Initialize console (UART VFS)</li>
  <li>Initialize VFS (mount filesystems)</li>
  <li>Initialize serial file transfer (SFT)</li>
  <li>Drop into the shell (<code class="language-plaintext highlighter-rouge">ccp_run()</code>)</li>
</ol>

<hr />

<h3 id="2-process-model-the-tpa-and-program-loader">2. Process Model: The TPA and Program Loader</h3>

<p>SP/M implements a <strong>CP/M-style Transient Program Area (TPA)</strong> with explicit memory segmentation:</p>

<table>
  <thead>
    <tr>
      <th>Region</th>
      <th>Size</th>
      <th>Purpose</th>
      <th>Allocation</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>IRAM (code)</td>
      <td>32 KB</td>
      <td><code class="language-plaintext highlighter-rouge">.text</code> section</td>
      <td><code class="language-plaintext highlighter-rouge">MALLOC_CAP_EXEC \| MALLOC_CAP_32BIT</code></td>
    </tr>
    <tr>
      <td>DRAM (data)</td>
      <td>16 KB</td>
      <td><code class="language-plaintext highlighter-rouge">.rodata</code>, <code class="language-plaintext highlighter-rouge">.data</code>, <code class="language-plaintext highlighter-rouge">.bss</code></td>
      <td><code class="language-plaintext highlighter-rouge">MALLOC_CAP_8BIT</code></td>
    </tr>
    <tr>
      <td>Stack</td>
      <td>8 KB</td>
      <td>Program stack</td>
      <td>Part of FreeRTOS task</td>
    </tr>
  </tbody>
</table>

<p>The loader (<code class="language-plaintext highlighter-rouge">exec/loader.c</code>) is the core of the process model:</p>

<ul>
  <li>Reads a structured <code class="language-plaintext highlighter-rouge">.spm</code> binary (header + sections + relocation table)</li>
  <li>Splits code and data into <strong>IRAM</strong> (executable) and <strong>DRAM</strong> (byte-accessible)</li>
  <li>Applies absolute relocations to fix up addresses for the split layout</li>
  <li>Spawns a FreeRTOS task (<code class="language-plaintext highlighter-rouge">program_task</code>) to run the program</li>
  <li><strong>On dual-core ESP32</strong>: Shell stays on <strong>Core 0</strong>, transient programs run on <strong>Core 1</strong></li>
  <li>The shell <strong>blocks</strong> (<code class="language-plaintext highlighter-rouge">while (!s_exec_ctx.done)</code>) until the program exits, then frees TPA memory</li>
</ul>

<p>This is effectively <strong>cooperative multitasking</strong> from the shell’s perspective: only one user program runs at a time, and the kernel waits for it to finish.</p>

<hr />

<h3 id="3-system-call-interface-jump-table">3. System Call Interface (Jump Table)</h3>

<p>SP/M provides a <strong>structured syscall interface</strong> via the <code class="language-plaintext highlighter-rouge">spm_table_t</code> jump table (<code class="language-plaintext highlighter-rouge">sdk/spm.h</code>, <code class="language-plaintext highlighter-rouge">exec/spm_table.c</code>). This is the only way transient programs interact with the kernel:</p>

<ul>
  <li><strong>Console I/O</strong>: <code class="language-plaintext highlighter-rouge">putchar_fn</code>, <code class="language-plaintext highlighter-rouge">getchar_fn</code></li>
  <li><strong>File I/O</strong>: <code class="language-plaintext highlighter-rouge">open_fn</code>, <code class="language-plaintext highlighter-rouge">read_fn</code>, <code class="language-plaintext highlighter-rouge">write_fn</code>, <code class="language-plaintext highlighter-rouge">close_fn</code> (pass-through to POSIX/VFS)</li>
  <li><strong>System</strong>: <code class="language-plaintext highlighter-rouge">exit_fn</code>, <code class="language-plaintext highlighter-rouge">delay_ms_fn</code></li>
  <li><strong>Hardware</strong>: GPIO, I2C, SPI, ADC</li>
</ul>

<p>The SDK header (<code class="language-plaintext highlighter-rouge">spm.h</code>) shadows ESP-IDF and FreeRTOS APIs as macros that dereference the jump table. This means the <strong>same source code</strong> can compile as either:</p>

<ul>
  <li>A native ESP-IDF app (links against real drivers)</li>
  <li>A transient SP/M program (links against the jump table)</li>
</ul>

<p>This is analogous to how DOS <code class="language-plaintext highlighter-rouge">.COM</code> files used INT 21h or how modern OSes use libc as a syscall wrapper.</p>

<hr />

<h3 id="4-virtual-file-system-vfs">4. Virtual File System (VFS)</h3>

<p>The VFS layer (<code class="language-plaintext highlighter-rouge">vfs/</code>) provides a <strong>Unix-like namespace</strong> on top of ESP-IDF’s VFS:</p>

<ul>
  <li><strong>Mount points</strong>: <code class="language-plaintext highlighter-rouge">/void/</code> (virtual empty), <code class="language-plaintext highlighter-rouge">/sd0/</code>, <code class="language-plaintext highlighter-rouge">/sd1/</code> (SD cards), <code class="language-plaintext highlighter-rouge">/nv0/</code> (internal LittleFS flash)</li>
  <li><strong>Path resolution</strong>: Supports aliases (<code class="language-plaintext highlighter-rouge">sys:</code>), absolute paths, and relative paths with CWD</li>
  <li><strong>CWD tracking</strong>: The shell maintains a current working directory (<code class="language-plaintext highlighter-rouge">ccp_get_cwd()</code>)</li>
</ul>

<p>This abstracts the underlying storage (SD via FAT, internal flash via LittleFS) behind a unified path interface.</p>

<hr />

<h3 id="5-hardware-abstraction-layer-hal">5. Hardware Abstraction Layer (HAL)</h3>

<p>The HAL (<code class="language-plaintext highlighter-rouge">hal/hal.h</code>) isolates the kernel from ESP32-specific peripherals, providing a consistent API for:</p>

<ul>
  <li>GPIO (including PWM and interrupt-based “watch”)</li>
  <li>I2C (multi-bus)</li>
  <li>SPI (full-duplex, GPIO-controlled CS)</li>
  <li>ADC (with attenuation config)</li>
  <li>UART (console)</li>
  <li>System (chip info, reset, memory queries)</li>
</ul>

<p>This is the standard OS HAL pattern: the kernel and transient programs talk to the HAL, and the HAL talks to ESP-IDF drivers.</p>

<hr />

<h3 id="6-shell-and-command-processor-ccp">6. Shell and Command Processor (CCP)</h3>

<p>The <strong>Console Command Processor</strong> (<code class="language-plaintext highlighter-rouge">ccp/ccp.c</code>) is the user-facing OS shell:</p>

<ul>
  <li>Reads lines with a line editor (<code class="language-plaintext highlighter-rouge">line_edit.c</code>)</li>
  <li>Parses commands into <code class="language-plaintext highlighter-rouge">argc</code>/<code class="language-plaintext highlighter-rouge">argv</code></li>
  <li>Dispatches to <strong>built-in commands</strong> (<code class="language-plaintext highlighter-rouge">help</code>, <code class="language-plaintext highlighter-rouge">ls</code>, <code class="language-plaintext highlighter-rouge">cd</code>, <code class="language-plaintext highlighter-rouge">cat</code>, <code class="language-plaintext highlighter-rouge">gpio</code>, <code class="language-plaintext highlighter-rouge">i2c</code>, etc.)</li>
  <li>Falls back to <strong>transient program execution</strong> (<code class="language-plaintext highlighter-rouge">.spm</code> files) if no built-in matches</li>
  <li>Tracks exit codes (<code class="language-plaintext highlighter-rouge">last_error</code>) like <code class="language-plaintext highlighter-rouge">$?</code> in Unix shells</li>
</ul>

<hr />

<h3 id="7-scripting-engine">7. Scripting Engine</h3>

<p>Beyond binary transient programs, the OS includes a full <strong>interpreted language runtime</strong> (<code class="language-plaintext highlighter-rouge">script/</code>):</p>

<ul>
  <li>Lexer, parser, AST, expression evaluator, and executor</li>
  <li>This makes SP/M a self-hosted environment where you can write scripts without compiling <code class="language-plaintext highlighter-rouge">.spm</code> binaries</li>
</ul>

<hr />

<h3 id="summary-1">Summary</h3>

<p>SP/M is a <strong>real operating system</strong> in miniature. It has:</p>

<ul>
  <li>A bootloader/initializer</li>
  <li>A resident kernel with HAL</li>
  <li>A process loader with memory management (TPA)</li>
  <li>A system call interface (jump table)</li>
  <li>A virtual file system with mount points</li>
  <li>A command shell</li>
  <li>A scripting runtime</li>
</ul>

<p>Its architecture is closest to <strong>CP/M</strong> (transient programs, TPA, jump table) or early <strong>MS-DOS</strong>, but running on a dual-core ESP32 with FreeRTOS as its microkernel foundation.</p>]]></content><author><name>fj zeit</name></author><summary type="html"><![CDATA[How the lode influences outcomes by providing richer context.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://fjzeit.github.io/assets/cards/lode-coding-toolkit.png" /><media:content medium="image" url="https://fjzeit.github.io/assets/cards/lode-coding-toolkit.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Getting Started with Lode Coding</title><link href="https://fjzeit.github.io/coding/lode-coding-basics" rel="alternate" type="text/html" title="Getting Started with Lode Coding" /><published>2025-11-30T00:00:00+00:00</published><updated>2025-11-30T00:00:00+00:00</updated><id>https://fjzeit.github.io/coding/lode-coding-getting-started</id><content type="html" xml:base="https://fjzeit.github.io/coding/lode-coding-basics"><![CDATA[<p><em><strong>Note:</strong> This article was updated on 27 Jan 2026 to cover a stepwise improvement in the approach. The lode-overview.md has been removed and replaced with a system prompt which you can either append on the command line or add to an AGENTS.md or equivalent. The system prompt has been refined to mostly automate the lode method. You no longer need to manually source files to seed the session. Additionally, the agent will find relevant lode documents when it requires them.</em></p>

<h2 id="what-problem-does-this-solve">What Problem Does This Solve?</h2>

<p>When you use AI coding assistants, you’ve probably noticed something frustrating: the AI doesn’t truly know your project. It can see your code, but it doesn’t understand your architecture, your naming conventions, or why you made certain decisions. The deeper context, the stuff that lives in your head and your team’s conversations, isn’t accessible to it.</p>

<p>Lode Coding solves this by giving you a flexible approach to capture and share that deeper project knowledge with your AI coding assistant.</p>

<h2 id="the-core-idea">The Core Idea</h2>

<p>Imagine having a body of knowledge about your project. One that is effortlessly created and maintained, that explains how things work, why they’re built that way, and what patterns to follow. Now imagine referencing this body of knowledge whenever you work with your AI coding assistant.</p>

<p>While you can recall why you made a decision in the past your AI coding assistant cannot. The lode bridges this gap by capturing knowledge from previous sessions, giving the AI access to context it would otherwise never have.</p>

<p>That’s Lode Coding.</p>

<p>The word “lode” comes from mining. A lode is a rich vein of valuable ore. Your project’s lode is a rich vein of valuable knowledge, accrued over time as you solve problems and deliver features.</p>

<h2 id="what-goes-in-a-lode">What Goes in a Lode?</h2>

<p>The coding assistant will decide what goes into the lode and you can prompt it for further refinement. A lode is a collection of markdown files (<code class="language-plaintext highlighter-rouge">.md</code>) organized in a folder. These files describe:</p>

<ul>
  <li><strong>What your project does</strong> and how it’s structured</li>
  <li><strong>Design decisions</strong> and why you made them</li>
  <li><strong>Patterns</strong> you use repeatedly</li>
  <li><strong>How things connect</strong> to each other</li>
  <li><strong>Lessons learned</strong> from past problems</li>
  <li><strong>Useful Historical</strong> gathered during sessions</li>
</ul>

<p>You don’t write these files manually. They emerge as a byproduct of your design, planning, and implementation conversations with the AI. You’re not setting out to write documentation. You’re solving problems, and the lode captures what you learn along the way.</p>

<h2 id="the-lode-structure">The Lode Structure</h2>

<p>The coding agent will create this if it does not exist. It will also populate and maintain the lode content.
You do not have to do anything other than ensure that you enrich your agent via one of the following methods:</p>

<ul>
  <li>using the claude script in the <a href="https://github.com/fjzeit/lode">lode repo</a></li>
  <li>placing the contents of <a href="https://github.com/fjzeit/lode/blob/main/prompts/SystemPrompt.txt">SystemPrompt.txt</a> in your project’s AGENTS.md (or vendor-specific equivalent)</li>
</ul>

<p>A typical baseline structure that the agent will create looks like this:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>project/
└── lode/
    ├── summary.md            # What is this project?
    ├── terminology.md        # What is this project?
    ├── practices.md          # Patterns and practices relevant to this project
    ├── lode-map.md           # hierarchical index of all lode files
    ├── plans/                # roadmaps &amp; TODOs
    ├── tmp/                  # git-ignored session scraps
    └── [any-domain]/         # e.g. parser/, auth/, ui/, billing/
        └── summary.md + *.md # one focused topic per file (kebab-case)
</code></pre></div></div>

<p>The structure and content will grow as you orchestrate development.</p>

<h2 id="conversational-orchestration">Conversational Orchestration</h2>

<p>Conversational orchestration is key to the success of this method. You converse with the agent as if you
were pairing or mentoring a junior or mid-level colleague. A unique colleague at that, one who types
extremely fast, has considerable knowledge of languages, protocols, and other theory, but lacks any experience in building quality sustainable software and is prone to making foolish mistakes.</p>

<p>Converse with the agent in this manner and you will naturally provide the level of detail required to 
enrich the session, resulting in more productive output and high quality information placed in the lode.</p>

<h3 id="planning">Planning</h3>

<p>Instead of writing markdown files up front, behave like you would if you were coding organically.
Ensure you have a good understanding of the requirements, a reasonable idea about the overarching design,
and a mental list of steps you plan to implement, as well as the checkpoints you’ll use to verify results.</p>

<p>Conduct a two-way conversation with the agent as if it were a colleague. Explain the problem, your vision, plan, and other pertinent details. The two-way conversation is important because you receive feedback from the agent about its understanding and the opportunity to correct it. This is considerably more effective than up-front detailed hand-written markdown.</p>

<p>If your agent has a planning mode you should use it for this step as it will result in a comprehensive plan you can review before starting.</p>

<p>When the agent presents you with a plan you should review it and provide feedback, ask clarifying questions, and if necessary continue the conversation to raise the quality of the plan. No different to mentoring a colleague.</p>

<p>Once you’re happy. It’s time to implement.</p>

<h3 id="implementation">Implementation</h3>

<p>This phase has become a lot simpler since Q4 2025 when agents and models seemed to take a dramatic step forward in ability. In the following I will present the more controlling approach but you should find that you can relax a little more and leverage the benefits of these new agent and model capabilities.</p>

<p>By now you should have been presented with a plan. One that maps well to the vision and instruction you provided during planning. <em>*This is not the time to go grab a cup of tea*</em>. This is the time to work.</p>

<p>Our primary goal is to ensure we have quality, maintainable, and acceptable code by the end of the session. No long rework, no manual refactors or clean up.</p>

<p>Keep your agent’s permissions as tight as possible. How tight is going to depend on the complexity of the
work at hand, your comfort with the lode coding method, and your level of trust with the model and agent.</p>

<ul>
  <li>Watch the agent as it works</li>
  <li>Review every file change</li>
  <li>Intervene when appropriate</li>
</ul>

<p><em>Intervention</em> is important. If you see the agent start to do something that is unacceptable, hit the ESC key
and have a pep talk with it. This might involve asking it what it’s doing, or it might just be a straightforward correction.</p>

<p>Correcting via conversation is important in lode coding. The agent will automatically update the lode on completing work. So it’s important that any clarifications or direction changes are provided to the agent if you want those retained for future sessions.</p>

<h3 id="the-iteration-cycle">The Iteration Cycle</h3>

<p>Planning and implementation aren’t phases you complete once. They form a tight cycle: plain, decide, review, implement + intervene, repeat. The agent will automatically update the lode as it goes.</p>

<p>Work with small incremental changes. Avoid trying to one-shot anything, especially entire features. Work to your own pace. Don’t let the marketing hype push you into trying to 100x your work. Speed is an inherent properly of coding agents, but your primary goal here is to retain full understanding of the code and to enforce a level of quality that encourages sustainability and changeability.</p>

<h3 id="session-handover">Session Handover</h3>

<p>Sometimes its helpful to move an implementation to a fresh session. To do this simply ask the agent to create a handover lode. It will then create a lode in <code class="language-plaintext highlighter-rouge">lode/plan/</code> and leave handover instructions for the next session. You can resume a handover by simply mentioning the handover file in your first prompt:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>   resume from lode/plans/name-of-handover.md
</code></pre></div></div>

<p>It’s useful to not include an @ prefix when doing this.</p>

<h2 id="lode-maintenance">Lode Maintenance</h2>

<p>From time to time you will want to conduct a lode audit. You can do this by simply asking the agent:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>audit the lode and ensure it correctly describes the system as implemented
</code></pre></div></div>

<p>The agent will conduct an interactive review with you and update the lode.</p>

<h2 id="merging">Merging</h2>

<p>As far as merging goes, the agent is quite capable of looking at the two branches and reconciling the lode after you have conducted the merge. If you have any lode merge conflicts, just accept the incoming changes and then explain to the agent that it should resolve any inconsistencies in the lode. Provide helpful information relating to relevant branches or commits. The agent will do most of the work for you and verify the lode is correct.</p>

<h2 id="existing-projects">Existing Projects</h2>

<p>Lode Coding works with existing projects. When you start a lode coding session the agent will attempt to read the lode. If the lode does not exist, it will ask you if it can create one. Accept this request. The agent will examine the project and create the baseline lode structure.</p>

<p>If your project is relatively small the agent might then add additional lode files to give itself full coverage but in most cases it will suggest updating the lode as it goes.</p>

<p>If you want a full lode created you can simply ask the agent for one. Large lode creation is better done in phases so be sure to enter planning mode and have the agent work in tranches. Create a fresh session for each tranch. Also, watch your token usage. :)</p>

<h2 id="additional-thoughts">Additional Thoughts</h2>

<h3 id="own-the-code">Own the Code</h3>

<p>AI coding assistants are tools, not authors. When code goes into your project, it becomes your responsibility. Bugs, security issues, maintenance: all yours.</p>

<p>Lode Coding forces you to stay engaged. You’re not copying and pasting blindly. You’re not feeding in
a markdown requirements document and hoping for the best. You’re undertaking context management, then you’re reviewing, understanding, and accepting only what you’d be comfortable defending.</p>

<h3 id="knowledge-compounds">Knowledge Compounds</h3>

<p>Every session adds to your lode. Over time, your AI coding assistant becomes remarkably effective because it has access to rich, accurate context about your project. The assistant will also proactively refresh knowledge when it becomes stale due to change, and add missing information as gaps are discovered.</p>

<p>Every new session, the AI will already know your conventions, your architecture, and your preferences.</p>

<h3 id="tools-change-knowledge-stays">Tools Change, Knowledge Stays</h3>

<p>Today you might use Claude Code. Tomorrow it might be something else. Your lode is markdown files. They work with any AI tool that can read text. You can even use multiple tools simultaneously: developing on your desktop with one assistant while submitting issues for automatic completion by another. Both have access to the same rich information, and you can reference lode files in your issue text as well.</p>

<p>You’re not locked in. Your knowledge investment stays with you regardless of what tooling you use.</p>

<h2 id="getting-started-today">Getting Started Today</h2>

<p>Visit the <a href="https://github.com/fjzeit/lode">Lode Coding Repo</a> and either clone it and run the <code class="language-plaintext highlighter-rouge">lode</code> script  to start, or use the custom agent in Anthropic’s Claude Code or Github’s Copilot, or grab the <a href="https://github.com/fjzeit/lode/tree/main/prompts">System Prompt</a>, and save it in your AGENTS.md.</p>

<p>That’s it. You’re ready to Lode Coding.</p>

<h2 id="further-reading">Further Reading</h2>

<p>Once you’re comfortable with the basics, explore these resources for deeper insight.</p>

<h3 id="core-resources">Core Resources</h3>

<ul>
  <li><a href="https://github.com/fjzeit/lode">Lode Repo</a>: Current prompt and scripts</li>
  <li><a href="/lode">Lode Coding Toolkit</a>: The home for all Lode Coding resources</li>
</ul>

<h3 id="articles">Articles</h3>

<ul>
  <li><a href="/coding/lode-coding">Lode Coding</a>: The original methodology and workflow patterns</li>
  <li><a href="/coding/lode-coding-revisited">Lode Coding Revisited</a>: Refinements and lessons learned from practice</li>
</ul>

<p><br /></p>

<div class="artsoclink">
<a href="https://x.com/fjzeit/status/1994984945413165160"><i class="lni lni-thumbs-up-3"></i></a>
&nbsp;&nbsp;
<a href="https://x.com/fjzeit/status/1994984945413165160"><i class="lni lni-comment-1"></i></a>
&nbsp;&nbsp;
<a href="https://x.com/fjzeit/status/1994984945413165160"><i class="lni lni-x"></i></a>
</div>]]></content><author><name>fj zeit</name></author><summary type="html"><![CDATA[Note: This article was updated on 27 Jan 2026 to cover a stepwise improvement in the approach. The lode-overview.md has been removed and replaced with a system prompt which you can either append on the command line or add to an AGENTS.md or equivalent. The system prompt has been refined to mostly automate the lode method. You no longer need to manually source files to seed the session. Additionally, the agent will find relevant lode documents when it requires them.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://fjzeit.github.io/assets/cards/lode-coding.png" /><media:content medium="image" url="https://fjzeit.github.io/assets/cards/lode-coding.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Lode Coding Revisited</title><link href="https://fjzeit.github.io/coding/lode-coding-revisited" rel="alternate" type="text/html" title="Lode Coding Revisited" /><published>2025-09-10T00:00:00+00:00</published><updated>2025-09-10T00:00:00+00:00</updated><id>https://fjzeit.github.io/coding/lode-coding-revisited</id><content type="html" xml:base="https://fjzeit.github.io/coding/lode-coding-revisited"><![CDATA[<blockquote>
  <p>Lode Coding is simple, repeatable, low friction, and effective.</p>
</blockquote>

<p>Back in April I wrote a short piece on Lode Coding, a disciplined approach to AI-assisted coding. If you’re not familiar with Lode Coding then please read the <a href="/coding/lode-coding">original Lode Coding article first</a>.</p>

<p>Today I am revising this topic to share a few refinements to the approach. If you want to know about my background then there’s plenty of info in my <a href="/bio">bio</a>.</p>

<p>Lode Coding’s primary goal is to enhance my own disciplined approach to software development through the use of llms. It’s not a one-shot-wowfest, but an incremental adoption of modern tooling to improve existing, well established, practices.</p>

<h2 id="keep-it-simple-try-it-take-what-works">Keep It Simple, Try It, Take What Works</h2>

<p>I’ve found this approach to be extremely effective. It lacks the <em>ego-lifting-circle-jerk-feelgood-factor</em> that seems to attract attention. But I hope some find it as useful as I have.</p>

<p>Lode Coding is simple, repeatable, low friction, and effective. Try it, take what works, leave the rest, or ignore it. I am sharing it for those who will find it useful. It works for me but ymmv.</p>

<h2 id="revisiting-some-key-points">Revisiting Some Key Points</h2>

<h3 id="its-a-switch-not-a-dial">It’s a Switch, not a Dial</h3>

<p>One thing I should have made quite explicit in my original article is that Lode Coding is a switch, not a dial. I don’t mix Lode Coding with traditional coding. I have two distinct forms of development practice:</p>

<p><strong>Traditional coding</strong> is where I code manually and deliberately. When I’m coding like this there is no copy/paste. No prompting for implementation. Just good old fashioned discipline, knowledge, and reference material. I don’t use AI auto-complete nor AI-suggestions. I do what I’ve always done. And there are plenty of scenarios where this remains the best approach.</p>

<p><strong>Lode Coding</strong> is all about 100% prompting. No code editing. My editor becomes my window into the model’s output. I’m not coding, I’m orchestrating, anchoring, reviewing, and iteratively refining. I’m sharing my experience with the model and building up an effective context window that enables good coding outcomes. And, when I’m done, I’m getting the model to sow that knowledge back into the lode. This differs considerably from Vibe Coding: my focus is on knowledge capture, lode enrichment, ownable outcomes, and quality results.</p>

<p>I’ll talk more about how I segue from one to the other in the next section.</p>

<h3 id="i-dont-write-the-lodes">I don’t Write the Lodes</h3>

<p>I can’t emphasise this enough. I never write a single lode myself. The model creates and maintains all of them. It’s surprising sometimes how insightful these lodes become. Leaving the llm to write the lodes encourages me to share the knowledge, perspectives, and design objectives required to meet the goal.</p>

<h3 id="tooling-agnosticism-pays-off">Tooling Agnosticism Pays Off</h3>

<p>This has proven invaluable. I switch between Github Copilot, Claude Code, and Jetbrains Junie with zero friction. Very helpful considering how the pricing landscape is changing on what seems like a weekly basis. I can seed a session for any assistant and get at minimum the same baseline outcomes. I’ve never used the memory features in any of the tools, they aren’t worth the lock-in.</p>

<p>Currently I pay US$10/m for Github Copilot, US$20/m or US$100/m for Claude Code (depending on how busy I am), and I have access to Jetbrains Junie through my All Products pack. Being able to move between vendor offerings with zero friction is extremely useful, especially considering that Github Copilot has a number of “unlimited” models.</p>

<h3 id="chatagent-mode-is-less-important-now">Chat/Agent Mode is Less Important Now</h3>

<p>I have found myself being less concerned about chat vs agent mode. Most models will respond to questions without running ahead. But sometimes I find it useful to be explicit that this is a chat or planning session.</p>

<h3 id="early-anchoring">Early Anchoring</h3>

<p>Once the lodes are enriched enough early anchoring becomes relatively simple. Introducing the lode overview at the start of a session is usually enough. I’ve also found that the model will create a system overview lode without being asked, so I’ll usually source this early too.</p>

<p>In the next section I’ll expand on how I’ve adapted early anchoring.</p>

<h3 id="take-ownership-of-the-outcome">Take Ownership of the Outcome</h3>

<p>This one is absolutely key. Taking ownership of the outcomes, being prepared to call the work my own, being able to maintain it when there’s no agent available. Ultimately the code the model produces reflects my own goals. I am always pushing the development forward with my prompting, not being pulled forward by the model’s decisions.</p>

<p>Nothing gets pushed unless it’s 100% understood, 100% ownable, and at an acceptable level of quality. I can switch to traditional coding practices with all of the Lode Coding outcomes. Just as if it had been written by me or another team member.</p>

<h2 id="enhancing-the-approach">Enhancing the Approach</h2>

<p>So what enhancements have I made since the last article? Well there are a few that are worth reporting on now. Some I will hold off on until I’ve tried them a bit longer. But let’s delve (!!) into the former.</p>

<h3 id="planning-lodes">Planning Lodes</h3>

<p>In the original article I mentioned the <code class="language-plaintext highlighter-rouge">~/lode/tmp</code> folder as being a special location for temporal information that I don’t want in the repo. This includes planning lodes. I’ll kick off a planning session, seed it with relevant lodes, have a conversation with the model, ask for it to propose a plan, iterate a refinement of that plan, get the model to document the plan to a tmp lode - including relevant information from other lodes. Then I’ll start a new session, source that one tmp lode, and prompt: <em>make it so</em>.</p>

<p>Planning sessions are 100% discussion based. Lode maintenance is zero effort due to sourcing the lode-overview and relevant lodes as part of that discussion.</p>

<h3 id="early-anchoring-1">Early Anchoring</h3>

<p>I find this less useful now due to the planning lodes. It’s far more effective to start a session, source relevant lodes, discuss the session outcomes, create a planning lode, clear the session and then run the next session from that planning lode. Sometimes I can’t just <em>make it so</em> and will have a conversation that produces iterative outcomes.</p>

<h3 id="switching-between-lode-coding-and-traditional-coding">Switching between Lode Coding and Traditional Coding</h3>

<p>I find that the models, especially Claude Sonnet, are better at UI design/implementation than I am. So I will often work traditionally on back end features and then segue into a Lode Coding session to create/iterate the UI.</p>

<p>After a traditional session I’ve found it useful to update the lodes. This’ll usually involve telling the model I’ve made some changes, and then watching it read the code and the lode and then update the lode automatically.</p>

<h3 id="the-grok-effect">The Grok Effect</h3>

<p>I’ve also found it useful to gather information via grok. Usually relating to more technical aspects of a problem. I’ll have a code-agnostic conversation with grok and then copy the conversation as markdown and drop it into <code class="language-plaintext highlighter-rouge">~/lode/tmp</code> as a resource for a Lode Coding session. I have <a href="https://x.com/fjzeit/status/1960263025430233104">on occassion</a> also brought Grok into an active session to help seed some expertise with minimal effort on my part.</p>

<h3 id="claude-code-commands">Claude Code Commands</h3>

<p>These two commands in my Claude Code global config illustrate how easy it is to kick off and finish a session with a lode update.</p>

<p><code class="language-plaintext highlighter-rouge">~/.claude/commands/lode.md</code></p>

<div class="language-md highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># Seed lode method</span>
Our knowledge management approach is defined in lode/lode-overview.md
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">~/.claude/commands/lupdate.md</code></p>

<div class="language-md highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># Request lode update</span>
remove code comments that provide historical commentary.
update lodes with concise information,
do not leave historical commentary,
the lode is a snapshot for AI agents.
</code></pre></div></div>

<h3 id="examples">Examples</h3>

<p><code class="language-plaintext highlighter-rouge">lode-overview.md</code> provides an example lode overview used for initial project seeding. This gives the model enough information about the approach to enable it to maintain lodes. Bear in mind that the model will update this lode just like any other lode. I place the file in ~/lode/lode-overview.md (<a href="https://gist.github.com/fjzeit/5b50a4dad1973e37764c5b84c2b02141">github gist</a>)</p>

<p>I have recently open-sourced a handful of projects which have included some Lode Coding efforts. These are:</p>

<p><code class="language-plaintext highlighter-rouge">fjleb128</code> is an early project which I wrote by hand. I added the lodes later in the project to help me go from “good enough for me” to “good enough to open source”. One area of the library that was Lode Coded was the span support and associated tests. These lodes are a little more verbose than more current ones but give a decent impression of what the model will produce as an outcome of a session. (<a href="https://github.com/fjzeit/fj-leb128/tree/main/src/.lode">repo</a>)</p>

<p><code class="language-plaintext highlighter-rouge">arcc</code> is a tool that was produced entirely via Lode Coding. I think I might have put in about 30 mins of traditional coding practice into it. Leveraging my long-established Win32 SDK experience, I prompted my way through this one just to get the tool good-enough. If I wanted to extend this tool I’d probably put in more time cleaning up the code and improving separation of concerns. This one is included because it’s as close to Vibe Coding as Lode Coding gets. (<a href="https://github.com/fjzeit/arcc/tree/main/.lode">repo</a>)</p>

<div class="artsoclink">
<a href="https://x.com/fjzeit/status/1914621961852027195"><i class="lni lni-thumbs-up-3"></i></a>
&nbsp;&nbsp;
<a href="https://x.com/fjzeit/status/1914621961852027195"><i class="lni lni-comment-1"></i></a>
&nbsp;&nbsp;
<a href="https://x.com/fjzeit/status/1914621961852027195"><i class="lni lni-x"></i></a>
</div>]]></content><author><name>fj zeit</name></author><summary type="html"><![CDATA[Refining The Disciplined Approach to AI-Assisted Coding]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://fjzeit.github.io/assets/cards/lode-coding-revisited.png" /><media:content medium="image" url="https://fjzeit.github.io/assets/cards/lode-coding-revisited.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">The Impending AI Failure Cascade</title><link href="https://fjzeit.github.io/thoughts/ai-failure-cascade" rel="alternate" type="text/html" title="The Impending AI Failure Cascade" /><published>2025-05-10T00:00:00+00:00</published><updated>2025-05-10T00:00:00+00:00</updated><id>https://fjzeit.github.io/thoughts/ai-failure-cascade</id><content type="html" xml:base="https://fjzeit.github.io/thoughts/ai-failure-cascade"><![CDATA[<blockquote>
  <p>Software development is an ecosystem comprising those who build and those who consume. What happens when the builders start to disappear?</p>
</blockquote>

<p>In the days before open source software, the software development scene was quite straightforward. Companies had two main options for sourcing the underlying tooling to deliver a solution: they could either buy a commercial library licence or hire experienced developers to create custom tooling. This was a time of high demand for skilled developers, with a significant barrier to entry, and work that was both mentally challenging and financially rewarding.</p>

<h2 id="the-open-source-revolution">The Open Source Revolution</h2>

<p>The emergence of open source software changed this landscape dramatically. Developers no longer needed to maintain a vast toolkit of computer science knowledge. Instead, they could leverage open source libraries to handle the heavy lifting, allowing them to focus almost exclusively on solving business problems. Many of those open source solutions were effectively free of charge. This shift democratised software development, but it also created a new ecosystem that would become crucial to the industry’s future.</p>

<p>The open source community thrives on motivated developers who contribute for various reasons. For many, it’s a career accelerator - a way to demonstrate abilities, develop skills, and drive interview conversations. It’s also a powerful platform for showcasing collaboration skills and organisational compliance. Most importantly, it’s all out in the open, visible for anyone to see and evaluate.</p>

<p>This visibility has led to an explosion of open source projects. Almost every library started with a simple problem and solution, evolving into a reusable library as interested parties got involved. The community’s strength lies in this organic growth - developers solving real problems and sharing their solutions with others.</p>

<p>This ecosystem is responsible for almost everything. From the niche office automation tooling created by a disparate community of developers who want to solve one specific problem, right up to the creators of languages, compilers, editors, and core infrastructure.</p>

<h2 id="the-ecosystems-balance">The Ecosystem’s Balance</h2>

<p>The open source ecosystem traditionally balances two primary stakeholders: the contributors and the consumers. While we’ve explored the motivations of contributors, the consumers - particularly for-profit corporations - play an equally crucial role. These companies rely heavily on open source software to make their systems development financially viable. Without open source, many companies would struggle to fund the internal skills they’d need to get things done. And in turn, by being potential employers, they contribute to the motivation for developers to get involved. We all depend on the open source communities, even those of us who primarily produce closed source proprietary solutions.</p>

<h2 id="the-new-players-in-town">The New Players in Town</h2>

<p>But there are new players in this ecosystem: the AI coding agent vendor and their “vibe coding” users. These new stakeholders bring a concerning mentality to software development. They view software development as something that can be automated and commoditised, claiming that AI agents will soon replace developers entirely. Their focus is purely on profit, with little regard for the software development ecosystem that makes the vendors tools viable, and the “vibe coders” dreams feasible.</p>

<blockquote>
  <p>It’s one thing to expect an AI agent to glue together a few libraries that represent thousands of hours of work comprising the opinions and experience of an army of smart minds. It’s an entirely different proposition to expect an AI agent to reproduce that work at an acceptable level of proven quality.</p>
</blockquote>

<h2 id="the-consequences">The Consequences</h2>

<p>So what happens if the AI agent vendors and users get their “developer-less vibe coding” utopia? The consequences could be severe. The demand for software developers would begin to disappear, taking with it the motivation that drives the open source community. Many open source projects would die from neglect, and we would face a generational<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup> loss of skill that might never recover.</p>

<p>Consider these critical questions: How useful would an AI agent be if it couldn’t pull in human-created open source libraries to do the real work? How many people drawn to the “vibe coding” or “prompt-driven development” cycle would be motivated to take over open source software maintenance?</p>

<p>Remember, these are people who were drawn to AI agents because of the simplicity and speed, not because of the underlying technical outcomes. I foresee a desert of creativity, where the motivated minds who once contributed to open source software seek their satisfaction - and income - in other industries. A sad but inevitable outcome of the destruction of the software development discipline.</p>

<h2 id="two-possible-futures">Two Possible Futures</h2>

<p>Assuming that AI agents are going to remain, there are two possible outcomes as I see it: a failure cascade and a total takeover.</p>

<p>The failure cascade is simple: with fewer developers, open source will cease to be a viable source of tooling. The loss of human-created tooling will lead to a failure of AI agents. The industry will have to reboot, having lost a generation of developers.</p>

<p>The total takeover is more concerning. In this scenario, the AI agent vendors progressively fill the gap created by the collapse of open source software. They produce the libraries themselves, employing humans to produce them, and then charge licence fees for their use via their own products. Don’t fool yourself into thinking that the AI agent vendors would open source their work. Why would anybody open source a toolset if the only other consumers are their competitors?</p>

<h2 id="in-closing">In Closing</h2>

<p>The software ecosystem has always relied on a delicate balance between those who build and those who consume. As AI agents edge closer to the centre of development, we risk losing not just the builders, but the motivation and community that have driven open source forward. If we allow the skills and spirit of real developers to fade, we may find ourselves in a world where innovation stalls and the tools we depend on are no longer freely shared, but locked away behind paywalls. The future of software depends on the choices we make now. Do we nurture the ecosystem, or watch it unravel?</p>

<div class="artsoclink">
<a href="https://x.com/fjzeit/status/1921111752495735212"><i class="lni lni-thumbs-up-3"></i></a>
&nbsp;&nbsp;
<a href="https://x.com/fjzeit/status/1921111752495735212"><i class="lni lni-comment-1"></i></a>
&nbsp;&nbsp;
<a href="https://x.com/fjzeit/status/1921111752495735212"><i class="lni lni-x"></i></a>
</div>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>Generational Loss</p>

      <p>As I see it, a developer generation is created over a 5 year period, very often as young people gain unfettered access to computing. A generational loss would take 5-10 years at most. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>fj zeit</name></author><summary type="html"><![CDATA[Software development is an ecosystem comprising those who build and those who consume. What happens when the builders start to disappear?]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://fjzeit.github.io/assets/cards/failure-cascade.png" /><media:content medium="image" url="https://fjzeit.github.io/assets/cards/failure-cascade.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Introducing Lode Coding</title><link href="https://fjzeit.github.io/coding/lode-coding" rel="alternate" type="text/html" title="Introducing Lode Coding" /><published>2025-04-21T00:00:00+00:00</published><updated>2025-04-21T00:00:00+00:00</updated><id>https://fjzeit.github.io/coding/lode-coding</id><content type="html" xml:base="https://fjzeit.github.io/coding/lode-coding"><![CDATA[<p><em><strong>Note: This article has been superseded. Read the <a href="https://fjzeit.github.io/coding/lode-coding-basics">Getting Started</a> article for the latest guide and information. You might still find the discussion presented here helpful.</strong></em></p>

<blockquote>
  <p>A lode is a rich or abundant source of valuable resources.</p>
</blockquote>

<p>AI coding assistants are powerful tools, but their effectiveness depends heavily on context. Without proper guidance, they can generate inconsistent or misaligned solutions. Over the past year, I’ve evolved a systematic approach that solves this problem by maintaining a rich knowledge repository - a lode - that captures the essence of a project.</p>

<p>This approach – dubbed Lode Coding – is a simple, tool-agnostic method that helps me get the most out of AI coding assistants. By building and maintaining a structured collection of project knowledge, I can quickly seed AI sessions with relevant context, leading to more consistent and higher quality outcomes. The approach requires no special configuration and works with any AI coding assistant that supports chat mode, agent mode, and file references.</p>

<p>This article presents a practical guide to Lode Coding. I’ll explore how I create and maintain a knowledge repository, how I use it effectively in coding sessions, and some practical tips that help me maintain control while getting the most out of AI assistance.</p>

<h2 id="terminology">Terminology</h2>

<p>I use a few specific terms throughout this article to describe different aspects of Lode Coding:</p>

<ul>
  <li>
    <p><strong>Chat Mode</strong> - the coding assistant mode where the assistant will not modify your code</p>
  </li>
  <li>
    <p><strong>Agent Mode</strong> - the coding assistant mode where the assistant will offer file changes</p>
  </li>
  <li>
    <p><strong>Seeding</strong> - prompting in <em>chat mode</em> to enrich session context</p>
  </li>
  <li>
    <p><strong>Orchestrating</strong> - prompting in <em>agent mode</em> to achieve a specific outcome from a well-<em>seeded</em> session</p>
  </li>
  <li>
    <p><strong>Lode</strong> - a structured repository of relevant system knowledge</p>
  </li>
  <li>
    <p><strong>Anchoring</strong> - direct intervention to rein in an over-enthusiastic coding assistant</p>
  </li>
</ul>

<h3 id="advantages">Advantages</h3>

<p>Here are the key advantages I’ve found with Lode Coding:</p>

<ul>
  <li>
    <p><strong>Zero configuration</strong>: It’s a philosophy and process, not a technology. I don’t need any special tools or setups.</p>
  </li>
  <li>
    <p><strong>Tool agnostic</strong>: I can use this with any coding assistant that supports chat mode and file operations. No vendor lock-in.</p>
  </li>
  <li>
    <p><strong>Simple approach</strong>: I just maintain markdown files in a structured way. No complex systems or special features needed.</p>
  </li>
  <li>
    <p><strong>Zero Lead Time</strong> - lodes are created iteratively as a by-product of the development process.</p>
  </li>
  <li>
    <p><strong>Fast context seeding</strong>: I can quickly provide high-quality context to get my coding sessions on the right track from the first prompt.</p>
  </li>
  <li>
    <p><strong>Easy context switching</strong>: When I need to fork context or switch tasks, I can do it with minimal overhead by referencing different lode files.</p>
  </li>
  <li>
    <p><strong>Consistent results</strong>: By providing focused context, I get more reliable and aligned output from the coding assistant.</p>
  </li>
  <li>
    <p><strong>Knowledge retention</strong>: I capture and retain systems knowledge that I can use to seed prompts, discuss the system, orchestrate code generation, and write documentation.</p>
  </li>
  <li>
    <p><strong><em>Team friendly</em></strong>: Since the lode lives in the repo, a team can work from, share, and enrich the same knowledge base.</p>
  </li>
</ul>

<h2 id="introducing-the-lode">Introducing the Lode</h2>
<p><strong><em>A lode is a rich or abundant source of valuable resources.</em></strong></p>

<p>Knowledge capture and storage is a fundamental software development skill<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">1</a></sup>. As a professional developer, I spend much of my time discovering and capturing knowledge - in code, tests, documentation, and through discussions with my peers. When working with coding assistants, I’ve found this knowledge to be just as crucial - I need to provide relevant context to get meaningful results.</p>

<p>This realization led me the evolution of Lode Coding. Instead of repeatedly providing context to a coding assistant manually, I maintain a structured repository of knowledge - the lode - that covers all relevant areas of my system. This includes both implemented features and planned developments, alongside higher-level design decisions and patterns.</p>

<p>By maintaining the lode in the same repository as my code, I can easily access, enrich, and reference it during coding sessions. When I start a new task, I simply tag the relevant lode files to seed my session with the right context. As I progress through my goals, I also maintain and update the lode, ensuring it grows alongside my project.</p>

<p>The lode becomes particularly valuable when I’m working on complex features or returning to a project after some time away. Instead of having to rebuild context from scratch, I can quickly provide the coding assistant with the specific knowledge it needs to help me effectively.</p>

<h2 id="creating-the-lode">Creating the Lode</h2>

<p>I usually have a lode directory structure at the root of my repo. The minimum lode looks something like this:</p>

<pre><code class="language-txt">~/lode/
    overview.md
</code></pre>

<p>I also keep a tmp directory for short-term knowledge. When I’m forking a session, I’ll dump relevant parts into a file in <code class="language-plaintext highlighter-rouge">~/lode/tmp/</code> so I can use it – and other lode files – to seed a new session while retaining important context.</p>

<pre><code class="language-txt">~/lode/tmp/
    refactor.md
</code></pre>

<p>I always add <code class="language-plaintext highlighter-rouge">~/lode/tmp</code> to <code class="language-plaintext highlighter-rouge">.gitignore</code>.</p>

<p>I don’t write lode files by hand. Instead, I have the coding assistant create them. I converse with it to build up a session specifically focused on an area and then ask it to create the file. This makes creating and updating lode files low effort. I’ve found that if I tell the assistant it’s writing the file for itself, it creates a more effective lode file anyway.</p>

<p><strong>Creating the lode from an existing project</strong></p>

<p>When I have an existing code base, I start a new session in <em>chat mode</em> and ask the agent to <em>examine the codebase and provide a summary</em>. I review this summary, prompt to clarify any inaccuracies, misunderstandings, or missing context. Then I have the agent re-present the summary and iterate until I’m happy with the outcome. At this point I switch to <em>agent mode</em> and request the summary be saved as a markdown file. I usually place this file in <code class="language-plaintext highlighter-rouge">~/lode/overview.md</code>.</p>

<p><strong>Starting from Scratch</strong></p>

<p>When I’m starting from scratch, I make the effort to begin my project with deliberation. I set up the scaffold to my liking and name things well enough to convey intent. Then I go through the same steps outlined above to create my <code class="language-plaintext highlighter-rouge">~/lode/overview.md</code>. I also enrich this overview in <em>chat mode</em> to provide more context.</p>

<p><strong>Dealing with Complex Projects</strong></p>

<p>For complex projects, especially those with multiple behavioural boundaries – both internal and external – I create a subdirectory for each system behaviour and prompt for a new <code class="language-plaintext highlighter-rouge">overview.md</code> to introduce it. When I need more detail, I create other <code class="language-plaintext highlighter-rouge">.md</code> files in the same folder to keep the knowledge in small reusable units.</p>

<h3 id="example">Example</h3>
<p>Here’s an example lode from one of my current projects - a programming language that compiles to WASM. The language’s syntax is heavily influenced by the Web Assembly Component Model and WASM Interface Type language. While the project is in its early stages, the lode has already proven invaluable. I’ve had many sessions where I’ve achieved a goal in just two shots, producing code that meets my standards and that I’m confident owning.</p>

<pre><code class="language-txt">~/lode/
    milestones.md
    overview.md
    unit-testing.md
    language/
        overview.md
        reference-manual.md
        wit-support.md
    lexer/
        overview.md
    parser/
        overview.md
        read-lex.md
        parse-syntax-tutorial.md
    generator/
        overview.md
        binary-section-tutorial.md
        patterns.md
    examples/
        currying_demo.lang
        data_processor.lang
        graphics_engine.lang
        string_processor.lang
</code></pre>

<p>Each file in this lode contains markdown documents generated by my coding assistant, either from orchestration sessions or focused conversations. These files provide concise descriptions of specific areas of the system, which I use to <em>seed</em> new sessions with relevant context. The tutorial files are particularly valuable - they teach the assistant my preferred patterns and approaches for complex operations like parsing syntax or generating WASM binaries using parts of the system that I wrote by hand.</p>

<h2 id="maintaining-the-lode">Maintaining the Lode</h2>

<p>As the system grows and my design evolves, I make sure to keep the lode up-to-date. I maintain information about system behaviours, milestones, roadmap, standards, patterns used in my code, and the endpoints and interfaces of behavioural boundaries.</p>

<p>Sometimes my coding assistant gets lost or misaligns with my intentions. I’ve found I can fix this by starting a mentoring session. I begin by seeding the session with existing lode files and reference source files, then I provide guidance to help the assistant understand how to code the way I want. Once done, I have it create a new lode file to capture this knowledge.</p>

<p>For example, in my compiler project, <code class="language-plaintext highlighter-rouge">parse-syntax-tutorial.md</code> came from one of these tuition sessions. This file gives the assistant everything it needs to know about querying the lexeme queue, working with token patterns, using existing tokens, and creating new ones. Similarly, <code class="language-plaintext highlighter-rouge">binary-section-tutorial.md</code> provides guidance on generating WASM binaries according to my patterns and preferences.</p>

<p>I also experiment with including mermaid diagrams in the lode documents. I’ll ask the coding assistant to create these diagrams, review them, and add them to the lode. While I’m not yet certain how much the assistant benefits from these diagrams, I include them to explore their potential value.</p>

<p>When I finish implementing a goal, I follow a simple process to update the lode:</p>
<ul>
  <li>Switch to <em>chat mode</em> and ask the assistant to summarize what we’ve achieved</li>
  <li>Review and correct the summary as needed</li>
  <li>Ask which lode files are affected by these changes</li>
  <li>Switch to <em>agent mode</em> to update those files</li>
  <li>Ask for any information that isn’t captured in existing files</li>
  <li>Create new lode files for any significant new patterns or knowledge</li>
</ul>

<p>This systematic approach helps ensure the lode remains a reliable source of context for future sessions.</p>

<h2 id="objectives-and-goals">Objectives and Goals</h2>

<p>I work with two levels of granularity: objectives and goals. An objective is a high-level outcome, something akin to a story or complete feature. A goal is one step in delivering that objective - essentially a task. I keep my goals small and very focused on specific outcomes.</p>

<p>After breaking an objective down into goals – my normal approach when coding – I iterate through a number of goal sessions to deliver the feature.</p>

<h2 id="goal-session-lifecycle">Goal Session Lifecycle</h2>

<p>Here’s how I structure each goal session:</p>

<ul>
  <li>Start a new session</li>
  <li>Seed the session - tag the relevant lode files</li>
  <li>Introduce the assistant to the goal - this is my first prompt</li>
  <li>Iteratively orchestrate the goal - I’ll explain this process in detail shortly</li>
  <li>Final review - I check the code and run tests to make sure everything works</li>
  <li>Update the lode - discuss the changes, review any lode updates, accept them</li>
  <li>Commit the changes</li>
  <li>Close the session</li>
</ul>

<p>When updating the lode, I switch to <em>chat mode</em> and ask my assistant to <em>summarize what we’ve achieved</em>. I review the response and provide any needed corrections. Then I ask <em>which md files in the lode folders are affected by these changes</em> and iterate through the assistant’s response before requesting updates to the lode files.</p>

<p>Before ending the session, I ask the assistant to <em>summarize any information not captured in the existing lode files</em>. After refining this summary, I have the assistant save it in a new lode file. Sometimes the assistant suggests where to put the file, but I can always specify a different location if I prefer.</p>

<p>Once I’m satisfied with both the code and lode updates, I accept all changes, commit them, and close the session.</p>

<h2 id="goal-orchestration">Goal Orchestration</h2>
<p><strong><em>Orchestrate the conversation. Coerce the coding assistant to do your bidding.</em></strong></p>

<p>When I orchestrate, I <em>almost</em> exclusively code by talking to my coding assistant. I don’t edit source files directly - instead, I direct the assistant through conversation.</p>

<p>With my session already seeded with relevant lode files and the goal communicated, I stay in <em>chat mode</em> to discuss what needs to be done. I approach this with the same mental picture I’d have if I were coding by hand. The difference is that I’m going to <em>helicopter</em> over the topic and guide the assistant in writing all the code. I switch between <em>chat</em> and <em>agent</em> modes when I need to <em>direct/clarify</em> and <em>create code</em> respectively.</p>

<p>Here’s what my orchestration process looks like. While I use Cursor in this example, this works with any coding assistant:</p>

<p><strong>Setup</strong></p>
<ul>
  <li>I have Cursor open</li>
  <li>I have my normal IDE open</li>
  <li>Both Cursor and the IDE have the project open</li>
</ul>

<p><strong>Iteration</strong></p>
<ul>
  <li>I walk the coding assistant through the implementation by prompting for specific changes</li>
  <li>I review each suggested outcome:
    <ul>
      <li>Review the code to make sure I’m happy with it, prompt for any changes I want</li>
      <li>Switch to my normal IDE, do a build and – if the build works – test the changes</li>
      <li>If there are any issues I’ll either:
        <ul>
          <li>fix them myself and let the assistant know I’ve changed the code</li>
          <li>or prompt the assistant to fix the issues</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>Then I accept the changes</li>
  <li>I repeat this for every step required to achieve the goal</li>
</ul>

<p>This orchestration approach means I’m fully engaged with every change being made. I’m not passively accepting suggestions - I’m actively directing the implementation, reviewing each piece of code, and understanding every decision. Because I’m thinking through the solution just as I would if coding by hand – with the mechanical work delegated to the assistant – I maintain complete ownership of the architecture and design. When the goal is complete, I’m confident in the code because I’ve shaped it, reviewed it, tested it, and understood it at every step. The resulting implementation is as much mine as if I’d typed every character myself - the assistant is simply helping me work more efficiently.</p>

<hr />

<h2 id="in-summary">In Summary</h2>

<p>Lode Coding is a disciplined approach to working with AI coding assistants that centres around maintaining a knowledge repository (the “lode”). The method involves storing project knowledge in markdown files within a structured directory (<code class="language-plaintext highlighter-rouge">~/lode/</code>), which is used to seed AI coding sessions with relevant context.</p>

<p>Key aspects include:</p>
<ul>
  <li>Maintaining project knowledge in small, focused markdown files</li>
  <li>Using this knowledge to provide context for AI coding sessions</li>
  <li>Switching between chat mode (for discussion) and agent mode (for code changes)</li>
  <li>Breaking work into small, focused goals</li>
  <li>Regularly updating the lode as the project evolves</li>
</ul>

<p>The approach emphasizes taking ownership of AI-generated code, maintaining control of the development process, and creating a reusable knowledge base that grows with the project. It’s tool-agnostic and requires no special configuration, making it easy to adopt with any AI coding assistant that supports chat and file operations.</p>

<p>The method has proven particularly effective for complex projects, reducing mental load while maintaining code quality and consistency with my standards and design intentions.</p>

<hr />

<h2 id="practical-tips">Practical Tips</h2>
<p><strong><em>Know your mode, stay in control, own the outcomes, build something you can own.</em></strong></p>

<p>Here are a few fundamentals that help me get the most out of Lode Coding.</p>

<h3 id="chat-or-agent-mode">Chat or Agent Mode?</h3>
<p><strong><em>Know when you’re conversing and when you’re orchestrating. Choose the right mode.</em></strong></p>

<p>I’ve learned to be deliberate about switching between chat and agent modes. When I just want to discuss or explore ideas, I stay in chat mode - this prevents the assistant from making unwanted changes just because I asked a question. When I’m ready for code changes, I switch to agent mode. Being explicit about these mode switches gives me better control over the session.</p>

<h3 id="anchor-early">Anchor Early</h3>
<p><strong><em>Make sure the coding assistant knows you are in control.</em></strong></p>

<p>While runaway prompts often indicate that my context seeding needs work, sometimes I need to directly tell the assistant to slow down and focus. Anchoring can be as simple as saying “slow down, I’m in charge here,” or I might summarize the session so far and use that summary to seed a fresh session. I’ve found that recognizing when the assistant has gone adrift and correcting early saves me significant time. The lodes make this switch trivial.</p>

<h3 id="take-ownership-of-the-outcome">Take Ownership of the Outcome</h3>
<p><strong><em>Only accept what you are prepared to own. Prompt diligently and iteratively for it.</em></strong></p>

<p>The coding assistant won’t face the consequences of bad code - I will. That’s why I apply my professional judgment to every outcome before accepting it. I ask myself:</p>

<ul>
  <li>Is this solution simple enough?</li>
  <li>Is the solution on or above par with my expectations?</li>
  <li>Am I prepared to accept this as my own?</li>
  <li>Would I offer it for a PR review in my name?</li>
</ul>

<p>Only when I can answer “yes, I’m happy to call this my own” do I accept and move forward.</p>

<h3 id="response-iteration-vs-session-iteration">Response Iteration vs Session Iteration</h3>
<p><strong><em>You will iterate often, sometimes that’s best done in a new session.</em></strong></p>

<p>When I need to iterate on a response, I decide whether to continue in the current session or start fresh. It comes down to how the session context is guiding the assistant. If there’s too much history, the assistant might not be as focused on the remaining problem as I am. Sometimes it’s more effective to accept an almost-good outcome, start a new session, seed it properly, and then fix the remaining issue. This is another form of anchoring that can save time, especially with a rich lode.</p>

<p>I hope you’ve found this guide useful. While every developer’s approach to AI assistance will be different, I’ve shared what works for me in the hope that you’ll find some ideas to help make your own coding sessions more productive and enjoyable. Thank you for reading, and happy coding and please reach out to me on X or drop me a follow.</p>

<p>You might also be interesting in September’s update: <a href="/coding/lode-coding-revisited">Lode Coding Revisited</a></p>

<div class="artsoclink">
<a href="https://x.com/fjzeit/status/1914621961852027195"><i class="lni lni-thumbs-up-3"></i></a>
&nbsp;&nbsp;
<a href="https://x.com/fjzeit/status/1914621961852027195"><i class="lni lni-comment-1"></i></a>
&nbsp;&nbsp;
<a href="https://x.com/fjzeit/status/1914621961852027195"><i class="lni lni-x"></i></a>
</div>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:2" role="doc-endnote">
      <p>The Five Orders of Ignorance</p>

      <p>Viewing software development as knowledge acquisition and ignorance reduction.  <em>Phillip G. Armour</em> (<a href="https://cacm.acm.org/opinion/the-five-orders-of-ignorance/">link</a>) <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>fj zeit</name></author><summary type="html"><![CDATA[A Disciplined Approach to AI-Assisted Coding]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://fjzeit.github.io/assets/cards/lode-coding.png" /><media:content medium="image" url="https://fjzeit.github.io/assets/cards/lode-coding.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>