EngineeringAI & Automation

AI Code Assistant Adoption

Best practices for integrating AI coding tools into day-to-day engineering workflows.

Overview

AI coding assistants have moved from novelty to standard tooling. They accelerate boilerplate, surface patterns, generate first drafts of tests and documentation, and reduce the time spent on routine mechanical work. Used well, they free engineers to spend more attention on the things that require human judgment: architecture, correctness, intent, and trade-offs.

Used poorly, they introduce a subtler problem than the one they solve: code that looks right, compiles, and passes tests — but contains hidden logic errors, security gaps, or missed edge cases that surface later and are harder to trace. The assistant did not think; it predicted. The engineer who committed the output is still responsible for it.

This page covers how we integrate AI coding tools into our workflow, which tools we use, and the standards that keep AI assistance an accelerator rather than a liability.


Why It Matters

Routine tasks have a real time cost. Writing boilerplate, generating type definitions from an API response, scaffolding test files, writing docstrings — these are necessary but low-judgment tasks. An AI assistant completes them in seconds. That time compounds across a team.

Cognitive bandwidth is finite. An engineer who spends three hours writing unit tests for a data transformation layer has three fewer hours for architecture review and design decisions. AI assistance on the mechanical layer preserves bandwidth for the judgment layer.

The quality of code review improves when AI handles the obvious. When an AI assistant catches formatting violations, missing null checks, and obvious type errors before a PR opens, human reviewers can spend their attention on logic, architecture, and intent — the things AI cannot reliably evaluate.

Adoption without standards creates inconsistency. Teams that let every engineer decide independently how and when to use AI assistance get inconsistent code quality, inconsistent security practices, and inconsistent expectations in code review. Standards make the benefit predictable and the risk manageable.


Standards & Best Practices

AI output is a first draft, not a finished commit

Treat AI-generated code the way you treat a junior engineer's code: read it, understand it, test it, and take responsibility for it before committing. "The AI wrote it" is not a defence when a bug reaches production. The engineer who committed the code owns the code.

Apply the same standards to AI-generated code that you apply to hand-written code — same linting, same type-checking, same tests, same code review.

Choose by integration model, not by brand

AI coding tools fall into three integration models. The models are stable; the specific tools filling each model change as the ecosystem evolves. Choose by model first — then pick the current best-fit tool for that model.

Integration modelHow it worksCurrent examplesBest for
CLI / agenticRuns in the terminal alongside your editor; reads and writes files directly; can execute commandsClaude CodeMulti-file refactoring, agentic tasks, terminal-first workflows
IDE-nativeEmbedded in or replaces the editor; delivers inline completions as you typeCursor, GitHub CopilotDaily editing, rapid file-level changes, autocomplete-heavy workflows
Chat / conversationalWeb or desktop interface with no automatic codebase access; context comes from explicit pasteChatGPT, Claude.ai, GeminiDesign exploration, debugging questions, one-off tasks

These models are not competing — they address different moments in a workflow. A team commonly uses an IDE-native tool for daily editing, a CLI/agentic tool for complex multi-file refactors, and a conversational tool for design exploration.

When a new tool launches, ask: which model does this fill? That immediately tells you when to reach for it and what to expect from it.

Never send secrets to an AI tool

API keys, database passwords, session tokens, private keys, and any other credentials must never appear in a prompt or in code you paste into an AI chat. This applies to all three tools — all send your input to external servers.

Before pasting a file or a code block, scan it for secrets. Strip them and replace with placeholders (<REDACTED>) if the surrounding code structure is what you need the AI to reason about.

Understand codebase awareness by integration model

Integration modelCodebase accessHow to provide project context
CLI / agenticReads files on demand; project-level instructions via a config file (e.g. CLAUDE.md, AGENTS.md)Create a project instructions file at the repo root; the tool reads it automatically
IDE-nativeIndexes the full codebase semantically; queries it at edit timeConfigure indexing once; works automatically thereafter
Chat / conversationalNone by default — sees only what you pasteInclude relevant types, function signatures, and dependencies explicitly in every prompt

Context-aware models (CLI and IDE-native) produce higher-quality output because they understand the project structure without you having to explain it. For conversational tools, compensate with explicit context in every prompt — paste the relevant code and constraints alongside your question.

Prompt for specificity, not volume

A clear, constrained prompt produces better output than a long one. Define what "done" looks like before you prompt.

Weak promptStrong prompt
"Write tests for this""Write Jest unit tests for this calculateDiscount function. Cover: zero input, negative price, missing coupon code, and the happy path. Use describe/it blocks. No mocks."
"Refactor this code""Extract the validation logic from this function into a separate validateCheckoutPayload function. Keep the types. Don't change the tests."
"Fix the bug""This function returns undefined when user.address is null. Add a null guard and return an appropriate error value — don't throw."

Specify the output format, the scope, the constraints, and what not to change. Ambiguity produces output you'll have to rewrite.

Review AI output at the logic level, not just the surface

Syntax and type errors are easy to spot. The harder problems in AI-generated code are:

  • Tautological tests — tests that assert what the implementation does rather than what it should do
  • Missing edge cases — AI tends to handle the happy path and obvious error cases, not the subtle ones
  • Incorrect error handling — errors silently swallowed, wrong error types thrown, or recovery logic missing
  • Race conditions — async hazards are a documented weak spot for AI-generated code
  • Over-generalisation — abstractions added that aren't needed, making the code harder to read

Read the logic, not just the shape. A function that compiles and passes its generated tests may still be wrong.

Establish a team norm for AI disclosure in PRs

Teams that are transparent about AI-assisted code review it more carefully — which is the right instinct. A simple convention in the PR description (e.g., "AI-assisted: test scaffolding generated with Cursor, reviewed and modified") keeps reviewers calibrated without creating overhead.


How to Implement

Step 1 — Choose your primary tool and configure it

Pick one primary tool per engineer based on their workflow. Configuration matters more than tool choice.

Claude Code:

# Install via npm
npm install -g @anthropic-ai/claude-code

# Or via Homebrew (macOS)
brew install claude-code

Add a CLAUDE.md at the project root with team standards. Claude reads this at the start of every session:

# Project Standards

## Language & framework

- TypeScript, Next.js 15, React 19
- Use pnpm, not npm or yarn

## Code style

- No comments unless the WHY is non-obvious
- Prefer `const` + arrow functions for utilities
- All new components must have a corresponding test file

## What to avoid

- Do not use `any` without a type comment explaining why
- Do not add error handling for scenarios that can't happen

Cursor: Add .cursor/rules files to set context for specific directories. Cursor reads these when editing files in that directory:

# .cursor/rules (project root)
This project uses TypeScript strict mode. Always provide explicit return types.
Prefer server components for data fetching. Use 'use client' only when browser APIs are needed.

OpenAI Codex: No project-level config. Establish a team prompt library — a shared document of reusable prompt patterns for common tasks (test generation, refactoring, documentation).

Step 2 — Define which tasks AI assistance is appropriate for

Write a brief team agreement on where AI assistance is expected vs. where it should be flagged:

Task categoryAI assistanceNotes
Boilerplate, scaffoldingEncouragedAlways review before committing
Unit test generationEncouragedVerify tests are meaningful, not tautological
Documentation / docstringsEncouragedReview for accuracy
Complex business logicWith cautionAI output needs close review; consider writing by hand
Security-sensitive codeRequires reviewAuth, cryptography, permissions — human sign-off required
Architecture decisionsNot appropriateAI can explain trade-offs; decisions must be human-made

Step 3 — Adopt a standard review checklist for AI-generated code

Before committing any AI-generated or AI-assisted code:

  • I have read and understood every line
  • The logic is correct, not just syntactically valid
  • Edge cases and error conditions are handled
  • No secrets, credentials, or environment-specific values are present
  • The code passes the team's standard linting and type-checks
  • If tests were AI-generated: I have verified they would fail if the implementation were broken

Step 4 — Set up linting and type-checking as a backstop

AI tools respect your linting config if they can see it. With Claude Code and Cursor, the config is read automatically. With Codex, include relevant rules in the prompt.

CI lint and typecheck jobs catch issues that slip through. They are not a substitute for review, but they are a reliable baseline:

# Runs on every PR — catches AI-generated code that doesn't meet standards
- name: Lint
  run: pnpm lint

- name: Type-check
  run: pnpm typecheck

Step 5 — Run a team retrospective after the first 30 days

After adopting AI tooling, hold a 30-minute retrospective:

  • Where did AI assistance save real time?
  • Where did it produce output that needed significant rework?
  • Did any AI-generated code reach review in a state that wasted reviewer time?
  • Are there tasks the team wants to standardise prompts for?

Use the findings to refine the team agreement from Step 2.


Tools & Templates

Integration model capability comparison

CapabilityCLI / agenticIDE-nativeChat / conversational
Codebase accessFull repo (reads files on demand)Full repo (semantic index)Manual paste only
File editingDirect edits with git integrationInline edits within editorCopy/paste only
Terminal accessFull CLI, command executionNoneNone
CompletionsOn requestReal-time inlineOn request
Agentic / multi-step tasksYes — multi-file, multi-stepLimited background agentsNone
Typical entry costSubscriptionFree tier availableFree tier available
Current examplesClaude CodeCursor, GitHub CopilotChatGPT, Claude.ai, Gemini

Reusable prompt patterns

Generate unit tests:

Write Jest unit tests for the `[function name]` function below.
Cover: [list specific cases].
Use describe/it blocks. Do not mock unless I/O is involved.
A test should fail if the implementation is wrong — verify this.

[paste function]

Extract a function:

Extract the [describe logic] into a separate function called `[name]`.
Keep the existing types. Do not change the calling code or the tests.
Return only the new function and the updated call site.

Explain unfamiliar code:

Explain what this code does, step by step.
Identify any edge cases or assumptions that are not obviously handled.
Note anything that looks like it might be a bug.

[paste code]

Common Pitfalls

Committing AI output without reading it. Speed is the temptation; correctness is the requirement. Code that looks plausible and compiles may still be logically wrong. Read every line before committing.

Sending secrets in prompts. Environment variables, API keys, and connection strings pasted into a chat window have left your control. Strip all secrets before sharing any code with an AI tool.

Trusting AI-generated tests as proof of correctness. A test generated by the same system that wrote the implementation is likely to encode the same assumptions. Verify that generated tests would actually fail if the implementation had a bug in it.

Using AI for architecture decisions. AI assistants can describe trade-offs fluently. They cannot weigh your team's specific constraints, organisational context, or long-term maintenance burden. Use AI to explore options; make decisions as a team.

Picking a tool based on hype, not workflow fit. AI tools serve different integration models — CLI/agentic, IDE-native, and chat/conversational. Evaluate based on which model fits how your team actually works, not benchmarks measured in controlled conditions.

No team norms leading to inconsistent practices. If some engineers review AI output carefully and others commit it directly, the team has no shared standard and code review becomes unpredictable. Agree on norms explicitly; don't assume shared intuition.