A single call to a code-generation model and a firmware workflow automation system can produce the exact same first draft of a driver. The difference doesn’t show up in that first draft. It shows up in what happens to it next, and specifically in three mechanisms a plain code-generation call doesn’t have: persistent state across attempts, a channel that turns hardware feedback into a decision, and a repair loop that is grounded in what the board actually reported.
A Generation Call Has No Memory of the Board
A code-generation API call is stateless by design. Prompt in, code out. If that code fails to build, or builds but doesn’t run correctly on the target, the model has no built-in way to know that. The failure happened downstream, in a stage the call never touches: build, flash, execution.
Ask a code-generation tool to “try again,” and it can only work from the prompt and whatever context was pasted into it. It cannot reference what the board specifically returned, because it was never connected to the board in the first place.
What Has to Persist Across a Build-Flash-Debug Cycle
A workflow automation system has to carry more than a prompt from one attempt to the next:
- Which parts of the datasheet, SDK, and errata sheet were already checked for this specific register or peripheral, so the same lookup isn’t repeated blind
- What the board actually returned on the last run: a compile error, a flash failure, a missing device on the bus, a specific log line
- Which fixes have already been tried, so the next attempt doesn’t repeat a change that already failed
This is closer to a running log than a single prompt. Every step, what document was referenced, what decision followed from it, the compile result, the flash result, has to stay attached to the task, not disappear once that step finishes.
Turning a Log Line Into a Decision
The harder mechanism isn’t storing the log. It’s using it. A missing device over SSH and a UART log showing a register write that never took are different failure signatures that call for different next steps: one might mean a driver didn’t load, the other might point straight at an errata entry that was missed the first time.
A code-generation tool has no mechanism for this at all, because it isn’t watching the board. It can be told a test failed, in a sentence typed by a person, but it cannot read the board’s own output and decide what that output implies about which stage broke.
Where “Try Again” Means Something Different
For a code-generation tool, retrying usually means regenerating from a similar prompt, with no reference to what specifically failed on hardware the first time. For a workflow automation system, repair means something narrower and more grounded: the fix is scoped to the actual failure that came back from the board, then re-verified the same way, build, flash, execute, check, not considered finished until that check passes on the physical target rather than in a compiler.
This is the same principle behind FWAuto’s log design: every step it takes, referenced documents, decisions, compile results, flash results, is recorded and visible, so an engineer can see exactly what triggered a given repair rather than treating it as a black box. A run isn’t marked done because the code compiled. It’s marked done when the board confirms it, and if that confirmation doesn’t come, the loop continues with the specific failure as its input.
Why the Distinction Matters When Evaluating a Tool
For firmware specifically, the useful question about any AI tool isn’t how good the code it writes looks in an editor. It’s what the tool does after that code leaves the editor: whether it has anywhere to store what the hardware reported, whether it can turn that report into a specific next action, and whether “try again” means something more precise than starting over.
A model can be excellent at generating a first draft and still have none of these three mechanisms, because they aren’t properties of the model. They’re properties of the system built around it, the one connected to the toolchain and the board, that a plain code-generation call was never designed to be part of.
