A Chat Assistant vs a Coding Agent: Why Pasting the Error Stopped Being the Workflow

Dmitri Voronov

Dmitri Voronov

September 30, 2026

A Chat Assistant vs a Coding Agent: Why Pasting the Error Stopped Being the Workflow

The worst Tuesday of my freelance year started with a red CI badge on a client’s Django project and ended, six hours later, with me realising I had spent most of the day as a clipboard. Copy the traceback. Paste it into a chat window. Read a confident explanation. Copy the suggested fix. Paste it into the editor. Push. Wait four minutes for CI. Copy the new traceback. Repeat.

Every answer the chat assistant gave me was plausible. Several were things I might have tried myself. None of them fixed the build, because the problem was in a file I had never pasted: a settings/ci.py override that a previous contractor had added, which swapped the database backend for SQLite during tests. The migration that failed used a Postgres-only index type. The assistant could not see that file. I did not think to show it, because I did not know it existed.

The next morning I opened the same repository in a coding agent, gave it the failing command, and asked it to find out why the migration broke in CI but not locally. It ran the test command, read the settings module chain, found the override, and told me in about three minutes. That was the day pasting the error stopped being my workflow.

A chat assistant only knows what you choose to show it

This sounds obvious, and it is the whole story. A chat assistant, whether that is ChatGPT in a browser tab or a chat panel that does not read your workspace, reasons about the text you give it. When you paste a traceback, you are also making an editorial decision about which context matters. You pick the file. You pick the error. You pick how much of the log to include before the chat box starts feeling silly.

When you know roughly where the bug is, that works. You paste the function, you paste the error, and the assistant is a very well-read colleague looking over your shoulder. When you do not know where the bug is, your selection is the bug. You keep showing it the part of the system you suspect, and it keeps giving you excellent advice about the part of the system that is fine.

What made the Tuesday so expensive was not bad answers. It was that each answer looked like progress. The assistant would say something like “this error typically occurs when the migration depends on an extension that is not installed,” and I would go check the extension, and it would be installed, and I would paste the next error. Each loop cost me ten minutes of CI and context switching, and each one felt productive.

An agent can go and look

A coding agent differs in one mechanical way that changes everything: it can read files and run commands in your project without you ferrying the output back and forth. When I asked it why the migration failed in CI, it did roughly what a careful human would do on their first day with the codebase:

  • Opened the CI config to see which command and which settings module CI actually used.
  • Followed DJANGO_SETTINGS_MODULE to settings/ci.py.
  • Noticed the DATABASES override to SQLite.
  • Opened the failing migration and saw a GinIndex.
  • Ran the test suite locally with the CI settings to confirm the same failure.

That last step is the part a chat assistant cannot do. It did not guess that the environment was different. It reproduced the difference. Then it offered two fixes: run CI against Postgres in a service container, or guard the index behind a vendor check. I chose the service container, because testing against a different database than production was the real bug, and the migration was just where it surfaced.

Overhead view of a cluttered desk with a laptop, printed pages covered in handwritten notes, a red pen and crumpled paper

The paste loop has costs nobody puts on the invoice

I bill by the day for most clients, so I track where time goes more carefully than I would like to. Looking back over a month of notes from before and after I switched most debugging to an agent, the paste loop had three hidden costs.

Selection bias. I already covered the big one: I showed the assistant what I thought was relevant, which meant it inherited my wrong assumptions. When I was right about where the bug lived, chat was great. When I was wrong, chat made me wrong faster and with better grammar.

Version drift. Chat answers are often correct for some version of the library. Twice in that month I applied a fix that used an API from a newer Django release than the client ran. The assistant could not see requirements.txt unless I pasted it, and I never pasted it, because who pastes the requirements file to ask about a migration? An agent reads the pinned versions as a matter of course, because it is already in the repo.

Transcription errors. Moving code between a browser and an editor is where small damage happens. An indentation level lost in Python. A truncated log line. A fix applied to the wrong one of two similar functions because I pasted the suggestion under the wrong definition. None of these are dramatic, and all of them cost a CI round trip.

None of this is the chat tool’s fault. It is what happens when a human becomes the transport layer between a reasoning system and the thing it is reasoning about.

What I still take to a chat window

I did not stop using chat. I stopped using it as a debugger for code it cannot see. These days a chat window gets three kinds of questions from me.

Conceptual questions. “What is the difference between a GIN and a GiST index for full-text search?” “When would I choose a queue over a cron job for this?” These do not depend on my repository. A chat assistant is excellent at them, and running an agent over the codebase to answer them would be wasteful.

Design discussion before there is code. When a client describes a feature over a call, I often talk it through in chat first, sketching data models and trade-offs. There is nothing yet for an agent to read. The conversation is the work.

Code I cannot give an agent. Some of my clients have contracts that forbid sending their source to third-party tools beyond what they have approved. For those, I will sometimes write a minimal reproduction in a scratch project and discuss that instead. It is slower, and it forces me to isolate the bug, which is occasionally the fastest way to find it anyway.

What the agent is worse at

It would be dishonest to write this as a conversion story with no downside. The agent’s ability to go and look has its own failure modes.

It can go and look at too much. On a Laravel project, I asked it to explain a failing queue job and watched it open thirty files, run the whole test suite twice, and produce a long explanation of the queue system before getting to the actual problem, which was a missing environment variable. A chat assistant, given the error and one sentence of context, would have said “check that QUEUE_CONNECTION is set” in one line.

It can also act when I only wanted an explanation. Early on, I would ask “why is this failing?” and come back to find it had also “fixed” the failure, sometimes by changing a test. Now I phrase diagnostic requests explicitly: find the cause, explain it, do not edit files. Most agents respect that. The default in many tools leans towards doing, and doing is not always what you want at the diagnosis stage.

And it reads everything it can reach. That includes a .env file if one exists in the workspace, and any credentials a lazy past contractor committed. With a chat assistant, the only secrets that leak are the ones you paste. With an agent, you need to think about what is sitting in the working directory before you start, and use ignore files for anything it should never open.

A developer leaning back in an office chair watching a laptop screen in an empty co-working space in the evening

How my debugging session looks now

The shape of a typical bug hunt changed more than I expected. It used to be: read error, form hypothesis, paste into chat, apply suggestion, test. Now it is closer to this:

  1. I write one or two sentences describing the symptom and where I saw it. “The test_invoice_export test fails in CI with an IntegrityError, passes locally.”
  2. I give the agent the exact command that reproduces it, or ask it to find that command from the CI config.
  3. I ask for diagnosis only. Find the cause, show me the evidence, propose a fix, do not apply it yet.
  4. I read the evidence, not just the conclusion. Which files did it open, what did it run, what output did it see?
  5. If I agree with the diagnosis, I let it apply the fix on a branch and run the tests again.

Step four is where I earn my rate. The agent’s conclusion is sometimes wrong in an interesting way, and the evidence trail shows you where it went sideways. A chat assistant gives you a conclusion with no trail, because there is no trail. It never touched anything.

The real change is who holds the context

The biggest shift was not speed. It was that I stopped being the person responsible for deciding what the tool gets to see. With chat, every answer is bounded by my guess about what matters. With an agent, the boundary is the repository and whatever commands I allow, which is a much larger and much less biased window.

That is also why the agent needs more supervision in some ways. When I controlled the context, I controlled the risk. Handing over the context means handing over some judgment about where to look and what to touch. For diagnosis, that trade has been overwhelmingly worth it. For changes, I still want to review before anything lands.

The Django client’s CI now runs against a real Postgres container. The settings/ci.py override is gone, with a comment in the commit explaining why testing against a different database was a trap. I think about that Tuesday whenever I catch myself reaching for the copy shortcut on a traceback. If the tool could just go and look, pasting the error is me volunteering to be the slowest part of the system.

More articles for you