Josh Ashton

Teaching developers to work with AI properly

Once we started putting Claude into the hands of more developers, one problem appeared almost immediately.

A developer would open Claude Code, point it at a ticket and essentially say:

Fix this.

Claude, being Claude, would happily oblige.

In one case it made changes across roughly fifteen files before the developer properly stopped to look at what it was doing. The result initially looked convincing, but once they started reviewing it, they realised they were spending longer understanding and untangling the changes than the ticket would probably have taken to implement manually.

That was useful.

Not the fifteen-file mess specifically. We could probably have lived without that.

The useful part was that it exposed the wrong mental model very early.

Claude wasn’t something you handed a requirement to and then waited for software to fall out of the other end.

The developer still needed to understand the problem, decide how it should be approached and remain accountable for whatever eventually ended up in the repository.

So one of the first rules I introduced was simple:

Plan first.

Investigate, plan, then code

During the early rollout, I enforced Claude Code’s Plan Mode fairly strongly for meaningful changes.

Before Claude was allowed to start changing code, I wanted it to investigate the problem, inspect the existing implementation, find similar patterns and produce a plan.

Then the developer had to review that plan.

  1. Investigate the problem
  2. Inspect the existing implementation
  3. Find similar patterns
  4. Produce a plan
  5. Developer reviews the plan
Before any code changes

This did two things.

It improved Claude’s output because the model had more context before implementation began.

More importantly, it moved the developer’s judgement to the start of the process.

In Part 1, I described a senior developer’s week-long ticket reaching a reviewable state in roughly a day and a half. The speed was interesting, but the more important part was that the senior developer had challenged Claude’s plan before any code existed.

That meant they could ask questions while changing direction was still cheap.

  • Why are you introducing another service?
  • Why does this need a database change?
  • We already solve something similar elsewhere. Why aren’t you following that pattern?
  • Are you assuming something about the domain that isn’t actually true?

The plan wasn’t there so we could ceremonially approve whatever Claude suggested.

It was there to make the approach inspectable before implementation started.

We initially used this on relatively small, bounded tasks while people learned the workflow, then gradually allowed Claude to tackle larger features as developers became more comfortable directing and reviewing it.

Giving an agent an entire epic and disappearing for lunch is technically an AI development strategy.

It just wasn’t ours.

Ask what could go wrong

Another habit that improved the quality of the interaction was challenging the plan rather than immediately accepting it.

Some of the most useful questions were surprisingly simple:

  • What assumptions are you making?
  • What are the main risks with this change?
  • What edge cases should we consider?
  • What other parts of the system could this affect?
  • What alternative approaches are available?
  • Why are you recommending this one?

I particularly liked asking for alternatives.

AI has a tendency to present its first suggestion as though it had been carved into stone tablets.

Ask for three possible approaches and suddenly you have something much more useful: a design discussion.

Perhaps the existing service can be extended.

Perhaps a new component makes more sense.

Perhaps the database schema needs changing.

Perhaps touching the database for this particular feature would be complete madness.

The point wasn’t that Claude always found the right answer.

It was that the developer was now comparing options rather than accepting one.

We had already seen smaller examples of why questioning assumptions mattered. In Part 1, Claude spotted a .Single() call that could throw because the collection wasn’t guaranteed to contain exactly one element.

The important lesson wasn’t that Claude knew how LINQ worked.

It was the question behind it:

What assumption does this code make, and what happens if that assumption is wrong?

That is a useful question whether the code came from Claude or a developer.

Context is part of the workflow

As people started using Claude on larger tasks, another problem became obvious.

Context needs managing.

The natural instinct is to keep using the same conversation because Claude already knows what you’ve been working on.

That works for a while.

Then the session accumulates old decisions, abandoned approaches, irrelevant files and assumptions from three tasks ago.

Performance can start degrading because the useful context is mixed in with an increasingly large amount of noise.

So I encouraged developers to treat a new bounded piece of work as a natural point to start fresh.

In practice, that often meant a new session for each issue or PR.

It wasn’t an absolute technical rule, but it was a useful default.

If a session became large but still contained useful state, Claude Code’s /compact command allowed us to compress the conversation and carry the important context forward.

If Claude had gone properly down the wrong path, though, I preferred starting again.

There is a point where another twenty prompts attempting to rescue a bad assumption costs more than opening a fresh session and explaining the problem properly.

Sometimes the best prompt is a new session.

Claude wasn’t just there to write code

I also wanted developers to stop thinking about Claude solely as a machine for producing implementation code.

Some of the most useful things we did with it involved relatively little production code at all.

We used it to debug issues and trace exceptions through unfamiliar parts of the application. We used it to generate and improve tests, review pull requests, explain existing implementations and investigate code developers hadn’t worked with before.

We also used it heavily for documentation.

When features changed, Claude could help identify affected areas of the user manuals, draft updated documentation and build out test plans around the new behaviour.

That saved more time than I initially expected.

Documentation has always occupied a strange place in software development where everyone agrees it is incredibly important right up until somebody actually has to update it.

Claude was remarkably enthusiastic about volunteering.

More importantly, this changed how developers thought about AI-assisted development.

The job isn’t just writing code.

It is understanding problems, investigating systems, designing solutions, testing them, documenting them and reviewing what other people have built.

AI could help with all of those things.

The developer still owned the result

As people became more comfortable using Claude, the larger risk shifted from mistrust to complacency.

Generated code can be dangerous precisely because it often looks reasonable. It compiles, the naming looks sensible, tests may pass, and Claude can give you a very convincing explanation for why everything is correct.

That makes it remarkably easy to stop looking quite as closely.

We wanted one principle to remain very clear:

The developer was accountable for whatever they committed.

It didn’t matter whether they had typed every character themselves, copied something from Stack Overflow, generated it with Claude or discovered it mysteriously written on a USB stick in the car park.

If your name is attached to the change, you need to understand it.

This also tied back to the junior developers from Part 1.

Claude could be an incredible learning accelerator, but only if developers used it to increase their understanding.

If they asked why something worked, experimented with alternatives and challenged the result, they could learn incredibly quickly.

If they gave Claude the ticket, accepted the diff and moved the issue to Done, they could increase their apparent output while learning almost nothing.

That wasn’t something I wanted us accidentally optimising for.

A minimum evidence trail

As adoption grew, we wanted AI-assisted changes to leave enough evidence that another developer could understand what had happened without needing access to somebody’s Claude session.

The process we settled on looked like this:

EvidenceWhat it meantWhere it lived
Stated goalWhat are we changing and why?Issue or PR description
Inspectable planWhat approach are we proposing before implementation?PR description, issue comment or artefact
Bounded change setThe scope is understood and the work is isolatedBranch and commits
Automated evidenceWhat evidence shows the implementation behaves correctly?Builds, tests, scans and CI artefacts
Human judgementWho reviewed the implementation and accepted it?PR review and approval
Clear outcomeWhat ultimately happened to the change?Merge, revert or escalation

The word bounded was important.

The problem with the fifteen-file incident wasn’t that Claude had changed fifteen files.

There are perfectly legitimate features that require far more than that.

The problem was that nobody had consciously agreed that fifteen files should change.

If the approved plan describes modifications to three components and Claude suddenly starts changing twelve unrelated ones, something has changed.

At that point the answer shouldn’t be:

Well, Claude probably knows what it’s doing.

Keeping governance inside normal development

I didn’t want AI adoption to create a parallel development process that developers had to maintain alongside the real one.

We already had issues, branches, commits, pull requests, CI and code review.

So those became the audit trail.

We weren’t storing enormous Claude transcripts or pretending we could preserve some complete record of the model’s internal reasoning.

What mattered was the decision trail: what were we trying to achieve, what approach had been agreed, what changed, how was it validated, who reviewed it and what happened to it?

Most of the enforcement initially came through review culture rather than a giant automated compliance system.

Because we introduced Claude team by team, the workshops allowed us to establish the expectations as developers came onboard. Reviewers knew that meaningful AI-assisted changes should have an inspectable plan. Existing branches and commits recorded execution, CI captured much of the validation evidence, and approval remained a human decision.

There was some friction, particularly around planning.

If somebody believes Claude can implement something in ten minutes, asking them to spend five of those minutes reviewing a plan can feel like unnecessary ceremony.

The fifteen-file experiment was quite a good advertisement for why it wasn’t.

Five minutes reviewing a plan is cheap.

An hour trying to understand why your coding agent has enthusiastically redesigned half the application is less so.

Some of these ideas also map closely to principles now formalised in the GitHub Certified: Agentic AI Developer material for GH-600: Developing in Agentic AI Systems, including separating planning from execution, validating plans and making agent activity inspectable through normal development tooling.

The terminology may have become more formal, but the underlying principle is fairly simple:

AI-assisted development should still be auditable software development.

Match the controls to the risk

I enforced planning quite aggressively during the rollout because developers were learning a new workflow.

I wouldn’t enforce exactly the same ceremony forever.

Correcting a spelling mistake does not need a security review, three approvers and an architectural decision record just because Claude happened to type it.

The controls should match the risk.

ChangeControls
A small documentation changeNormal review
A feature touching normal application logicAutomated tests, integration testing and another developer reviewing it
Authentication, permissions, sensitive data or important domain logicConsiderably more scrutiny

The key point is that AI shouldn’t automatically create more bureaucracy.

But it definitely shouldn’t create less accountability.

Changing the post-mortem question

The evidence trail also changed the way we talked about problems.

The tempting question after an AI-assisted change goes wrong is:

Why did Claude do that?

I don’t think that is particularly useful.

Claude will make mistakes.

Developers make mistakes too.

The more useful questions became:

  • Was there a visible plan?
  • Did the implementation still match it?
  • Did the right people review the change?
  • Did the validation match the risk?
  • Could another developer reconstruct what happened from the issue, commits, CI results and PR?

That shifts the discussion away from blaming the model and towards something the team can actually improve.

Did the agent fail?

Maybe.

But did our development process give that failure an easy route into production?

That is usually the more interesting question.

The real skill isn’t prompting

Good prompting obviously matters.

Asking about risks, requesting alternatives and actively managing context all improved the quality of our results.

But after watching a development team adopt Claude, I don’t think the most important skill is memorising clever prompts.

It is engineering judgement.

  • Knowing when a plan looks wrong.
  • Knowing when a change has grown too large.
  • Knowing what needs testing.
  • Knowing what context matters.
  • Knowing when Claude is confidently talking nonsense.
  • And knowing when to stop it instead of spending another twenty prompts trying to make a bad approach work.

The developers who got the most value from Claude weren’t necessarily the people with the fanciest prompts.

They were the people who learned how to direct it without surrendering responsibility to it.

Once we had that working reasonably well, though, we found the next problem.

Every developer was still teaching Claude how they wanted code written.

Architectural conventions were repeated in prompts. Testing expectations varied between sessions. Things senior developers considered obvious weren’t obvious to the model at all.

So we started turning those conventions into reusable skills.

That’s where Part 3 starts.

Next in this series: turning engineering standards into shared AI skills.