Build code with agents while keeping a working understanding
Peter Naur in 1985 wrote that programming is the act of building a working theory of the system in our minds, and this often takes form as tacit knowledge in the head of programmers. Task: Peter Naur in 1985 wrote that programming is the act of building a working theory of the system in our minds, and this often takes form as tacit knowledge in the head of programmers. Even if you handed the complete codebase and perfect documentation to a completely new team, they would often need to go back to the old team and ask questions.And before agents, we often built this working theory of the system by writing the code by hand. It helps us figure out the "grain" of the codebase so we have a better idea of how to extend it.So what happens when agents are writing the code? The main avenue with which we built the working theory of the system in our mind is now taken away, and we're left feeling like our understanding of the system is blinded.I ended up more or less changing my entire workflow. Four main principles:1. Interrogation/interview-based design and specification2. Make the decisions that matter and leave the rest to the agent.3. Use agent to generate explainers, quizzes, and simulations.4. Use verifiers and guardrails in the coding loop.Interview-based design and specWhen I tell the agent what I want to build or extend, there's naturally ambiguity. But the agent knows what is ambiguous to it, so it can ask me. /grill-me is one way to do this. You'd think this would be commonplace now, but it's actually not. Some people are still wondering why they're getting bad results. It's because they're not resolving the ambiguity.Making the decisions that matterNot every decision matters in a product. Agents are fast at writing code and pretty good at some of the nitty gritty details, so I let it make those decisions. Also, if a particular subsystem is commonplace and undifferentiating, such as login, then I also let it make architectural decisions for that subsystem.For decisions that are product differentiators, where that differentiation is supported by technology, I make decisions on the stack, the architecture, and the approach. This is the design phase. Because agents tend to make the mainstream decisions, they almost always take a midwit approach which doesn't leverage the technology in a way that makes a difference for the customer.Some try to build this understanding from code reviews. I personally don't think it's the way to go, because it's not motivating. I find that I'm more motivated to learn how the system works today, because I want to change how it works tomorrow--and it sticks in my head better too (no different than pre-agents).Generating explainers, quizzes, and simulationsAs I'm doing design for an improvement and I don't know how a part of the system works, I can ask questions of the agent in chat. If I still don't get it, I can ask for diagrams (either ASCII or mermaid). But if it's an entire subsystem, I have a skill in which I can ask for visual and interactive explainers. It'll generate a markdown page (or html) that has these interactive components that help demonstrate a concept.To help make the concept stick, there are quizzes after each section and at the end.With the computational simulations, I generate a throwaway tool in which I can explore the state space. This doesn't happen as often, as I try to keep state spaces small, and for those explainers tend to work well.With the design simulations, a same-model agent and a cross-model agent and I will talk about an explainer, and we'll name things that we understand or notice about the design and the intended direction we want to extend it. Then, we'll use subagents to generate options and then discuss the pros and cons. I find this is a good way for me to understand the dead-ends of a design.Using Verifiers and GuardrailsI define guardrails as mechanistic checks that doesn't change with the feature. such as linters, typecheckers, and pre-commit hooks are all guardrails. Verifiers are mechanistic checks that will be different with each feature, such as unit/integration tests.For more complicated states or concurrent parts, I'll ask the agent to use formal methods to write a proof. Then use the proof to generate a trace (a series of steps that demonstrate a happy or unhappy path). Then I run that trace in unit tests (kinda like property-based testing--so I guess this can be called trace-based testing), and the code has to adhere to the trace.I also wrote a design verifier, where the requirements in the spec can be converted into a series of mechanically checkable rules.; tools: custom-built or unnamed agent. Human role: The original post does not say how a person stayed involved.; limitations: This approach requires a custom agent setup capable of generating interactive HTML/Markdown explainers and running formal verification tools. It assumes the agent can reliably identify ambiguities and generate valid proofs for complex states. Integration with existing CI/CD pipelines for 'trace-based testing' may require significant engineering effort. The method relies on the author's specific definition of 'product differentiators' which may not apply to all projects..
Tools
custom-built or unnamed agent
Published on Agent Work Atlas:
Overview
Peter Naur in 1985 wrote that programming is the act of building a working theory of the system in our minds, and this often takes form as tacit knowledge in the head of programmers.
Workflow
Peter Naur in 1985 wrote that programming is the act of building a working theory of the system in our minds, and this often takes form as tacit knowledge in the head of programmers. Even if you handed the complete codebase and perfect documentation to a completely new team, they would often need to go back to the old team and ask questions.And before agents, we often built this working theory of the system by writing the code by hand. It helps us figure out the "grain" of the codebase so we have a better idea of how to extend it.So what happens when agents are writing the code? The main avenue with which we built the working theory of the system in our mind is now taken away, and we're left feeling like our understanding of the system is blinded.I ended up more or less changing my entire workflow. Four main principles:1. Interrogation/interview-based design and specification2. Make the decisions that matter and leave the rest to the agent.3. Use agent to generate explainers, quizzes, and simulations.4. Use verifiers and guardrails in the coding loop.Interview-based design and specWhen I tell the agent what I want to build or extend, there's naturally ambiguity. But the agent knows what is ambiguous to it, so it can ask me. /grill-me is one way to do this. You'd think this would be commonplace now, but it's actually not. Some people are still wondering why they're getting bad results. It's because they're not resolving the ambiguity.Making the decisions that matterNot every decision matters in a product. Agents are fast at writing code and pretty good at some of the nitty gritty details, so I let it make those decisions. Also, if a particular subsystem is commonplace and undifferentiating, such as login, then I also let it make architectural decisions for that subsystem.For decisions that are product differentiators, where that differentiation is supported by technology, I make decisions on the stack, the architecture, and the approach. This is the design phase. Because agents tend to make the mainstream decisions, they almost always take a midwit approach which doesn't leverage the technology in a way that makes a difference for the customer.Some try to build this understanding from code reviews. I personally don't think it's the way to go, because it's not motivating. I find that I'm more motivated to learn how the system works today, because I want to change how it works tomorrow--and it sticks in my head better too (no different than pre-agents).Generating explainers, quizzes, and simulationsAs I'm doing design for an improvement and I don't know how a part of the system works, I can ask questions of the agent in chat. If I still don't get it, I can ask for diagrams (either ASCII or mermaid). But if it's an entire subsystem, I have a skill in which I can ask for visual and interactive explainers. It'll generate a markdown page (or html) that has these interactive components that help demonstrate a concept.To help make the concept stick, there are quizzes after each section and at the end.With the computational simulations, I generate a throwaway tool in which I can explore the state space. This doesn't happen as often, as I try to keep state spaces small, and for those explainers tend to work well.With the design simulations, a same-model agent and a cross-model agent and I will talk about an explainer, and we'll name things that we understand or notice about the design and the intended direction we want to extend it. Then, we'll use subagents to generate options and then discuss the pros and cons. I find this is a good way for me to understand the dead-ends of a design.Using Verifiers and GuardrailsI define guardrails as mechanistic checks that doesn't change with the feature. such as linters, typecheckers, and pre-commit hooks are all guardrails. Verifiers are mechanistic checks that will be different with each feature, such as unit/integration tests.For more complicated states or concurrent parts, I'll ask the agent to use formal methods to write a proof. Then use the proof to generate a trace (a series of steps that demonstrate a happy or unhappy path). Then I run that trace in unit tests (kinda like property-based testing--so I guess this can be called trace-based testing), and the code has to adhere to the trace.I also wrote a design verifier, where the requirements in the spec can be converted into a series of mechanically checkable rules.
Reported result
The source does not report measured outcomes, efficiency gains, or specific failures. It describes a subjective shift in workflow where the author feels they can stay out of the immediate coding loop while maintaining a 'working theory' of the system. No quantitative data on time saved or bug reduction is provided.
Human role
The original post does not say how a person stayed involved.
Limitations
This approach requires a custom agent setup capable of generating interactive HTML/Markdown explainers and running formal verification tools. It assumes the agent can reliably identify ambiguities and generate valid proofs for complex states. Integration with existing CI/CD pipelines for 'trace-based testing' may require significant engineering effort. The method relies on the author's specific definition of 'product differentiators' which may not apply to all projects.
Try it
Act as a senior software architect using an AI coding agent. I am building [replaceable: specific feature or subsystem] in [replaceable: tech stack]. 1. **Specification**: Do not write code yet. Ask me clarifying questions about ambiguous requirements until we have a clear spec. Use a 'grill-me' style interview. 2. **Design Decisions**: Identify which parts are product differentiators. I will decide the architecture for those. You decide the implementation details for standard components (e.g., auth, logging). 3. **Explainers**: Generate an interactive HTML/Markdown explainer for the core logic of the differentiator. Include quizzes to test my understanding. 4. **Verification**: Write unit tests and a 'design verifier' script that checks if the implementation matches the spec's mechanical rules. First, perform a dry run on a small sample module. Show me the spec questions, the design decision rationale, and the explainer output. Wait for my confirmation before generating the full codebase. Ensure no code is committed until I approve the verification results.
Source reports are not independently verified. Publication date is the catalog publication date, not the original article date.