The Symbolic Noise Problem of Coding Agents

How an unnoticed behaviour of AI models could be creating unnecessary cognitive load.

The responses generated by coding agents are typically a mixture of regular prose and symbolic content like filenames, code, various identifiers and other artifacts. The problem is that current AI models structure them in a way that imposes unnecessary cognitive load. This is an issue that has largely gone unnoticed and its importance is increasing as we transition to an era where most of the code is generated by AI.

Take a look at the following example of a typical AI-generated response. It's deliberately simplified to demonstrate the issue at hand, but I'm sure the overall structure will look very familiar if you've used AI for coding:

AGENT:

The issue is likely in TodoDetailView.swift:14, where the todo is stored as local state:

@State private var todo: Todo

EditTodoView.save() updates the repository in TodoRepository.swift:52, but TodoDetailView keeps rendering its original copy.

Pass the todo ID instead and read the latest value from the repository:

struct TodoDetailView: View {
    let todoID: Todo.ID

    @Environment(TodoRepository.self)
    private var repository

    var todo: Todo? {
        repository.todo(id: todoID)
    }
}

Also remove the reloadTodo() workaround in TodoDetailView.swift:68. The underlying problem is that the view owns a stale snapshot instead of observing the source of truth.


At first, this might seem like an acceptable response, but if you take a second look, you will notice that it contains information that is unnecessary when it comes to giving you a high-level understanding of the issue and the suggested solution. You don't really need to know the exact filenames and line numbers (TodoDetailView.swift:14, TodoRepository.swift:52) to understand the issue. Moreover, that line of code that represents the local state, @State private var todo: Todo, could be described in prose without having to mentally force you into code-interpretation mode.

Now consider the following version of the response above that is restructured to prioritize a higher-level description:

Restructured agent response:

The detail screen likely shows stale data after an edit because it keeps its own copy of the todo. Saving updates the repository, but the screen continues rendering the original snapshot.

Keep the repository as the source of truth. Pass the todo’s ID to the detail view and read its current value from the repository:

struct TodoDetailView: View {
    let todoID: Todo.ID

    @Environment(TodoRepository.self)
    private var repository

    var todo: Todo? {
        repository.todo(id: todoID)
    }
}

This replaces the local @State property in TodoDetailView.swift:14. Provided the lookup reads observable repository state, edits can update the detail screen without manually reloading it; the reloadTodo() workaround can then be removed.


The second response prioritizes the high-level understanding of the issue, removing any symbolic content that is either irrelevant or positioned in a way that could cause unnecessary mental switching to code-reading mode, what I call symbolic noise. This restructuring still includes code and other symbolic content, but it's positioned toward the end of the conversation at a point where mentally you are more prepared to read it if necessary.

To put it differently, the agent is structuring the response in a behaviour-first vs. the implementation-first approach that it tends to follow by default. This pushes any code or other symbolic content, even if it's not noise, further down the response, essentially making it optional to consume. I have often found that reading the first part of the response describing the high-level behaviour is more than enough to ensure that the model is on the right path or if it has already made a mistake, without reading the code.

When symbolic noise becomes a problem

Scale matters. The cognitive load imposed by any symbolic noise is negligible for trivial coding tasks or short coding sessions. For longer coding sessions, harder problems or when you are working on multiple different projects, that's not the case. Apart from slowing you down, it's also increasing the chances you'll make mistakes.

For throw-away prototypes or trivial coding side-tasks, reading any agent output, including code, is usually skipped, so any symbolic noise is negligible simply because careful reading of the output is not required. However, if you are working on production code and you want to understand the code generated or the way the AI has approached its implementation on a higher level, reading these AI-generated responses is inevitable. This is when symbolic noise hurts the most.

Putting the problem into perspective

Reducing symbolic noise should not be treated as an absolute goal. There will always be cases where the best response will require various inclusions of symbolic content anywhere in the response and that's fine. The goal should be to minimize the symbolic noise, not any symbolic content, and this can be achieved through careful content engineering.

It's worth considering another perspective: The interaction model of coding agents is fundamentally conversational, and that's not a coincidence. Conversations are fundamental information exchange structures in the pursuit of achieving a common goal that involves collaboration with other intelligent entities. Our brains have been optimised for this type of interaction for thousands of years. In that regard, it is sensible to evaluate the quality of a conversation with coding agents on its similarity to a hypothetical conversation that would take place with one or more human counterparts, asking questions like: How close are the coding agent's replies to the ones a human would produce? That's not to say that human-generated responses should be the benchmark for the ones generated by AI, but we should examine what makes a human-level conversation more efficient for us humans, and use that information as a way to further optimise what the AI models produce.

It's also a matter of trust. The addition of references to lower-level artifacts, filenames, code references and snippets can act as an extra layer of assurance of the model's accuracy and understanding of the task at hand. However, in practice, this ends up being a thin veneer of trustworthiness at the cost of additional symbolic noise. I've seen AI models admit, on several occasions, that the inclusion of various code references, variable names or filenames and other symbolic content served that purpose. Earlier, less-capable models would hallucinate much more, so perhaps, the symbolic noise is artifact of how older models have been trained mixed with some well-intented convenience features like using the filenames and numbers as links to quickly access the code.

A skill that can provide better guidance

One way to reduce symbolic noise is careful context engineering. Current coding agents do offer various ways to configure the agent's output that could partly address the symbolic noise issue, but I'm switching between various models and agents so I needed a solution that worked across models and harnesses. This is why I developed an agent skill for this purpose. So far, it has worked incredibly well with versions of Fable, Opus and Astra at any effort level or output setting. It's currently the most used skill across both coding and (surprisingly) design sessions as well. I've used it mostly on web and mobile-related projects of various sizes ranging from small experimental prototypes to production-level coding tasks.

The version I'm sharing is the result of several rounds of adaptations and adjustments I've made based on daily usage on these projects and I tried to make it as short and open-ended as possible. Current frontier models like Fable and Astra require much less guidance and I wanted the skill to be usable on any coding project, not just the ones that I'm using.

Another aspect of this skill's design is to encourage the model to aim beyond better textual output: AI models can now produce visual artifacts like diagrams, interactive widgets and images so the model should be given more opportunities to choose the most efficient output structure to convey the information requested.

You can find the skill on my repo.

If you happen to use it, I would love to hear your feedback.

Is that all?

As AI models and harnesses get better and more reliable, understanding what the model does remains essential but it's no longer based on reading the code generated. Directing the model to effectively communicate its work and the reduction of symbolic noise is now perhaps the topmost issue to address.

It's not the only inefficiency, though. I tend to view Symbolic noise as just one of the symptoms of a bias known as Curse of Knowledge that affects human-to-human communication as well.

Either way, we're barely scratching the surface of what's possible and how to best use these incredibly powerful tools at our disposal. And this is exactly why we should always retain an open mind and a critical stance towards this evolving technology to ensure that the signal remains strong.