AI tools for software work: where each kind actually helps
Completion, chat, agentic coding, review and test generation are different tools with different failure modes. Which helps with what, and where the productivity claims break down.
On this page
Five distinct kinds of tool get grouped together as AI for software work, and they help with different things. Inline completion, conversational assistance, agentic coding, review, and test generation each have a shape of problem they suit and a characteristic way of being unhelpful.
Knowing which is which matters more than picking a vendor, because the common disappointment is using one category for a job that belonged to another.
What we'll cover
Five categories, five failure modes
Inline completion predicts the next few lines as you type. Fails by being confidently plausible.
Conversational assistance answers questions and produces snippets. Fails by lacking context about your actual codebase.
Agentic coding takes a task and makes changes across files. Fails by doing a great deal of work in a direction you did not want.
Review reads a change and comments. Fails by volume — plausible observations that are not worth acting on.
Test generation writes tests for existing code. Fails by testing what the code does rather than what it should do.
Each of those failure modes is specific and each has a mitigation. The general complaint that "AI coding tools do not work" usually resolves into one of these five, used somewhere it does not fit.
Inline completion
The most widely adopted and the least demanding to use.
Where it genuinely helps: boilerplate, repetitive structures, the obvious next line, filling in a pattern you have already established twice. It is very good at noticing what you are doing and continuing it.
Where it does not: anything requiring a decision. Completion optimizes for plausibility, and plausible is not the same as correct. The characteristic failure is a suggestion that looks exactly right, compiles, and uses an API parameter that does not exist or handles an edge case incorrectly.
The habit that makes it safe: read the suggestion before accepting it, every time. This sounds obvious and the whole design of the tool works against it, because accepting is one keystroke and reading takes three seconds.
The measurable risk: accepting completions in unfamiliar code. When you know the domain, you catch the wrong ones. When you do not, you are accepting suggestions on trust, which is exactly the situation where you are least able to.
Conversational assistance
Asking a question in a chat interface and getting an explanation or a snippet.
Where it genuinely helps: explaining unfamiliar code, generating something self-contained from a clear description, translating between languages, remembering the syntax for something you use twice a year, and rubber-ducking a design problem.
Where it does not: anything depending on your specific codebase that it cannot see. Without your conventions, your types, and your existing helpers, the answer is generic, and adapting generic code to a real codebase sometimes costs more than writing it.
The thing that moves the needle: context. Tools that can read your repository give substantially better answers than ones you paste into. That is the main axis on which these products now differ.
The failure to watch for: confident answers about libraries and APIs that do not exist or have changed. Verify anything it tells you about an external interface, because this is where models are most confidently wrong.
Agentic coding
The category that has changed most, and the one with the widest gap between a good day and a bad one.
What it does: takes a described task, explores the codebase, makes changes across several files, runs tests, and iterates.
Where it genuinely helps: well-specified, mechanical changes with a clear definition of done. Renaming a concept across a codebase, adding a parameter through several layers, writing a migration, implementing something that follows an established pattern already present in the repository.
Where it does not: anything under-specified. Given a vague task it will produce a confident, substantial change in some direction, and evaluating a large diff you did not write is slower than writing a small one you did.
The practices that separate useful from frustrating:
Give it a way to check its own work. A task with tests it can run is a task it can verify; one without is a task it will declare finished based on its own judgement.
Keep the scope small enough to review properly. The value disappears at the point where reviewing the change costs more than making it.
Expect to review as carefully as you would a colleague's work, and more carefully in unfamiliar areas.
Review and static analysis
Models reading a change and commenting on it.
Where it genuinely helps: catching the things humans skip. Inconsistent error handling, a missing null check, a resource not closed, a test that does not assert anything, documentation that no longer matches the code.
Where it does not: architectural judgement, whether this is the right approach, whether this fits the team's direction. Those need context a diff does not contain.
The failure mode that kills adoption: volume. A reviewer producing twenty comments per change, of which three matter, trains the team to skim. Tuning toward fewer, higher-confidence findings is what determines whether it gets used in month three.
Where it is unambiguously valuable: as a first pass before human review, catching the mechanical issues so the human review is about design. That sequencing is what makes it worth having.
Test generation
The most oversold and still useful within limits.
The fundamental problem: generating tests from existing code produces tests that assert what the code currently does. If the code has a bug, you now have a test asserting the bug. That is worse than no test, because it makes the bug look deliberate.
Where it genuinely helps: generating the cases you would not have thought of. Empty inputs, boundary values, unusual types, the combination you did not consider. That is a real contribution and it is different from writing your test suite.
Where it helps most: test data and fixtures, which are tedious, voluminous, and where being slightly wrong is inexpensive.
The discipline required: read every generated assertion and ask whether it describes intended behaviour or observed behaviour. That is the whole difference, and skipping it produces a suite that locks in whatever the code happened to do on the day it was generated.
Where the productivity claims break down
Worth being direct, because the numbers published in this area are mostly not measurements of anything durable.
Code written is not the metric. These tools reliably increase the volume of code produced. Whether that is good depends entirely on whether the code was needed, whether it is correct, and what it costs to maintain.
The time saved moves rather than disappearing. Less time writing, more time reviewing. For mechanical work that is a good trade. For work requiring judgement, reviewing a change you did not write can be slower than writing it.
The gains concentrate in familiar territory. They are largest where you can immediately evaluate the output, which is your own domain. They are smallest, and the risk highest, in unfamiliar code where you are least able to spot a wrong suggestion.
Maintenance is not usually counted. Code accepted quickly, understood shallowly, and maintained for years has a cost that does not appear in any study of how fast a task was completed.
The honest summary: these tools are genuinely useful for mechanical work, genuinely risky in unfamiliar territory, and roughly neutral on work that is mostly thinking. That is a real benefit and it is not the transformation the marketing describes.
There is also a category of work adjacent to this that is frequently automated badly: the operational plumbing around development. Deployment notifications, ticket updates, release notes assembled from merged changes, reminders about stale branches. That is ordinary business automation rather than coding, and describing it is faster than scripting it. On CodeWords you describe what should happen in plain language and Cody, the automation builder, builds it, connects it to your repository and chat tools, and deploys it. Automations connect to more than 3,000 integrations. The free plan covers light use, with Pro at $39 per month and Business at $100 per month as usage grows; details are on the pricing page.
Adopting these on a team
Individual adoption is easy and team adoption has a few decisions worth making deliberately.
Agree what gets reviewed. The main risk is not bad generated code but code accepted quickly and understood shallowly. A team norm that generated changes are reviewed exactly as carefully as written ones, and more carefully in unfamiliar areas, is the single most useful agreement available.
Decide on the licensing position once. Whether you filter suggestions matching public code, and what your obligations are. Having a stated position beats each developer making their own quietly.
Keep prompts and configurations in the repository where they affect shared behaviour. Anything influencing how the team's tools behave should be reviewable rather than living in individual settings.
Be wary of measuring the wrong thing. Lines produced, suggestions accepted, and time-to-first-commit all go up and none of them tells you whether the software got better. If you measure anything, measure defect rates and the time spent on review, because those are where the costs land.
Expect uneven benefit. These tools help most on mechanical work in familiar territory and least on the design-heavy work senior people spend their time on. A team seeing wildly different value across its members is seeing exactly what the tools do, rather than a problem that needs solving or a sign that somebody is using them wrong.
Frequently asked questions
Which category should I start with?
Inline completion, because the adoption cost is nearly zero and the benefit on boilerplate is immediate. Conversational assistance second, particularly a tool that can read your repository. Agentic coding once you have a sense of how carefully you need to review its output.
Do these tools work for learning to program?
They help and they carry a specific risk: accepting working code you do not understand teaches you nothing and feels like progress. Using them to explain rather than to produce is the version that helps, and it requires deliberately choosing the harder path.
Is generated code safe to use?
It needs the same review as any code, and more in unfamiliar areas. The specific risks are outdated library patterns, confidently invented APIs, and security issues from patterns that were common years ago. None of that is unique to generated code; what is different is how fast it arrives and how plausible it looks.
Should AI-generated tests count toward coverage?
Only after somebody has read the assertions. Tests generated from existing code assert what the code does, so coverage from unreviewed generated tests measures how much code is pinned in place rather than how much is verified correct.
How do I stop an AI reviewer being ignored?
Tune for fewer findings. A reviewer producing three findings that matter is read; one producing twenty of which three matter is skimmed within a fortnight. Volume is the thing that kills adoption, not accuracy.
What about code the model was trained on?
Licensing and provenance are live questions and worth having a position on rather than discovering one. Some tools offer filtering for suggestions matching public code. Whether that satisfies your obligations is a question for whoever advises you on licensing.
Does any of this replace understanding the codebase?
No, and it raises the value of understanding it, because the main skill these tools demand is evaluating output quickly. That is exactly the skill that depends on knowing the system, which is why the benefits concentrate where you already know what good looks like.