Best practices for AI usage
General AI coding assistant practices
Start with a clear intent, then constrain the task
How to do it
State goal, constraints, definition of done, and the exact files or interfaces involved.
Prefer short iterative prompts that build on the current diff.
Example
“Add optimistic updates to IssueList.tsx using React Query. Keep existing typing. Update useIssues.ts to invalidate the issues key only on success. Provide a minimal diff and a 3-item test plan.”
Why
Specific context reduces ambiguity and improves suggestion quality. GitHub’s prompt engineering guidance stresses being explicit about functions, files, and context.
GitHub Docs
Always review, test, and secure
How to do it
Ask the assistant to write unit tests first for risky changes, then code to make them pass.
Run linters, code scanning, secret scanning, and CI before merge.
Copilot prompt example
“Generate Jest unit tests for calculateDiscount.ts that cover 0, boundary, and invalid inputs. Do not stub business rules. Next, propose code changes to make all tests pass.”
Why
GitHub recommends combining Copilot with tests and automated scanning, and shows step-by-step test generation flows. This ties usage to shipped quality instead of raw acceptance.
Security checklist to apply during review
Validate inputs on the server, never trust user input.
Do not log secrets or tokens.
Guard auth, authorization, and output encoding paths.
Reference OWASP quick checks for input validation.
Make metrics reflect shipped quality
How to do it
Pair activity metrics with outcomes like merged PRs, test pass trends, rework, and defects.
Read acceptance together with language or area, not in isolation. Your Copilot and Cursor pages encourage acceptance and language breakdowns. Use them with outcome signals to avoid vanity measures.
Keep developers accountable
How to do it
Require a human LGTM for AI-assisted diffs.
Keep architecture and security decisions in team's hands.
GitHub’s secure use guidance and enterprise docs reinforce human review and policy controls.
Document decisions inside the PR
How to do it
Ask the tool to draft the PR description and test plan, then add your rationale, edge cases, and rollout plan.
Example PR note template
“Intent: add optimistic updates for issues. Constraints: preserve cache keys and typing. Tests: 5 unit, 1 E2E. Risk: stale cache on error. Rollback: feature flag optimisticIssues.”
Copilot’s cheat sheet includes commands for explaining code and creating tests that help populate this PR template.
Protect data and IP
How to do it
Do not paste secrets or proprietary payloads unless your enterprise configuration explicitly allows it.
Use approved enterprise settings for logging and data boundaries.
Build a learning loop
How to do it
When output is off, reply with why and ask for a corrected version that follows your examples.
Maintain a small internal “prompt cookbook” of patterns that work for your stack. GitHub’s official tips emphasize setting context, making asks specific, and iterating.
The GitHub Blog - a fun and useful read with more examples and tips.
GitHub Copilot - usage best practices with examples
Pick the right Copilot surface
When to use inline
Completing a function, adding parameters, small refactors.
When to use Copilot Chat
Explaining unfamiliar code, writing tests, multi-file changes, or generating a migration plan. The docs show test generation and E2E examples directly from Chat.
Chat prompts you can copy
“Explain how
useRetryingFetchworks and list failure modes.”“Generate table-driven Jest tests for
parseDateRangeincluding invalid ranges.”“Propose a minimal diff to replace legacy crypto with
subtle.cryptoand update tests.”
Review acceptance with intent
Practice
Review the first two or three alternative suggestions. Accept the smallest correct diff. Reject verbose or speculative code.
Inline example
“Show two simpler alternatives with fewer allocations and explain tradeoffs.” Why: GitHub encourages scanning alternatives and giving acceptance feedback to shape future suggestions.
Test first for risky changes
Scenario You are adding rate limiting to an API. Chat sequence
“Write Jest tests for
rateLimiter.tsthat cover normal, burst, and blocked user scenarios.”“Generate implementation changes that pass the tests. Keep public API unchanged.”
“Add an E2E Playwright test for the 429 response path.”
Use Copilot in code review without skipping human judgment
Ask: “Summarize this diff. Flag potential N+1 queries and missing input validation.”
Keep your checklist items for secrets, validation, and authorization. GitHub’s secure practice pages advocate combining Copilot with automated scanning and human review.
Keep Copilot scoped
Provide only the files needed and the exact function signatures.
Never include secrets. Use masked env values in examples.
Interpret Copilot metrics with care
Track suggestions accepted by language and area of code, then correlate with merged PRs, test pass rate, rework, and defects.
If acceptance is high but rework rises, slow down and tighten review. This mirrors your “expanded metrics” emphasis on segmentation and context.
Cursor - usage best practices with examples
Seed Cursor with rules
Keep it focused and composable, under 500 lines.
Include language patterns, error handling rules, test frameworks, and things to avoid. Cursor’s docs spell out how to write effective rules.
Keep in mind, you can go ahead with setting up
.cursorrules, but it will be deprecated soon.
Work in small, reviewable steps
Scenario
You need to add a debounce to a search box.
Composer prompt
“Update SearchBox.tsx to debounce input by 300 ms using useCallback and setTimeout. Show a minimal diff. Add a test for rapid keystrokes.”
Follow-up
“Explain the diff and provide one simpler alternative.”
Why: Cursor guidance and community tips encourage iterative edits and minimal diffs.
Make Cursor refactor your own diffs
Scenario
You wrote a pagination helper.
Chat prompt
“Review paginate.ts. Reduce allocations and avoid off-by-one errors. Propose a smaller version with identical behavior and add tests for edge pages.”
Use context intentionally
Practice
Reference only files that are required for the change.
For multi-module edits, ask Cursor to first list affected files and functions before it edits. This reduces irrelevant changes.
Interpret Cursor metrics with care
Practice
Read AI vs manual lines and acceptance rates next to merged PRs and rework.
Sample AI-assisted PRs weekly for maintainability and security. Your Cursor docs mention capture limits, so qualitative review stays important.
Close the loop in the PR
Prompt “Draft a PR description summarizing intent, constraints, test plan, and risk. Keep it under 120 words.” Then you add links to tickets and any rollout notes.
Claude Code Best Practices for Developers
(Focused on improving output quality)
Claude Code can produce highly reliable, idiomatic code when given the right structure, context, and feedback. This guide focuses on how developers can systematically improve Claude’s outputs and make them more consistent, testable, and production-ready.
Set strong context
Claude works best when it understands your project, conventions, and constraints clearly.
Maintain a CLAUDE.md (or similar) at the repo root that includes:
Project overview, architecture sketch, and main data models.
Coding standards (style guides, naming, error handling, logging).
How to run tests, linters, formatters, and local environment.
Always reference concrete files and paths:
Paste or attach the specific files Claude should consider (e.g.,
src/api/user.ts,tests/user.test.ts).Tell Claude explicitly which files it is allowed to edit and which are read-only.
Provide realistic examples:
Show a “good” existing function or module and say: “Match this style and patterns.”
Include an example request/response or input/output for APIs and CLIs.
Write precise, structured prompts
The single biggest lever on output quality is the prompt structure.
Use a consistent prompt template, for example:
Context: What the project/module does and any relevant standards.
Goal: One clear task, e.g., “Implement X”, “Refactor Y”, “Add logging.”
Constraints: Performance, security, libraries, patterns to use/avoid.
Tests: Existing tests, desired new tests, or explicit acceptance criteria.
Output format: “Return only updated code for file A and B” or “Reply with a unified diff.”
Avoid fuzzy asks:
Replace “Improve this code” with “Refactor to reduce duplication, keep behavior identical, and ensure all tests in
tests/user.test.tsstill pass.”Avoid mixing multiple unrelated tasks in a single prompt; split them.
Make hidden expectations explicit:
Mention error handling strategy, logging format, null-handling, and type-checking rules.
Clarify which external APIs or internal services are authoritative.
Use tests and examples as the “truth”
Claude becomes much more reliable when tests and examples define correctness.
Lead with tests whenever possible:
Provide failing test cases first and ask Claude to “make these tests pass without breaking existing tests.”
If no tests exist, ask Claude to generate tests before or alongside the implementation.
Give table-driven or example-based specs:
For business rules, supply a table or list of input → expected output scenarios.
Ask Claude to restate these in its own words before coding to surface misunderstandings.
Keep tests close to the code:
Always show the relevant test file next to the implementation file in your prompt.
After code generation, ask Claude to adjust tests if behavior intentionally changes, and to explain the change.
Iterate in small, focused steps
Short, focused loops produce more accurate and maintainable code than one-shot “big bang” prompts.
Limit scope per iteration:
Aim for a single function, class, or endpoint change per prompt.
For large refactors, ask for a step-by-step plan first, then implement step 1, then step 2, etc.
Use a “plan → code → review” pattern:
Ask: “Propose a detailed plan to implement X in this codebase without writing code yet.”
Once the plan looks right, ask Claude to implement only the next step.
Always follow up with critique:
After generation, respond with specific feedback: “You missed case A; the logger format is wrong; and this must not block the main thread.”
Ask Claude to revise just those points, not to rewrite everything.
Enforce your standards in the prompt
Claude will usually conform to whatever rules you clearly and consistently enforce.
Embed standards in every relevant prompt:
Language version, style guide (e.g., PEP 8, Airbnb), type system usage, and project-specific idioms.
Error handling policies (e.g., domain-specific error classes, never return raw exceptions).
Require lint- and type-clean output:
Say: “Write code that passes
npm run lintandnpm run testwith zero warnings.”If your toolchain is known, mention it explicitly (e.g., ESLint, mypy, pylint, detekt).
Standardize logging, metrics, and tracing:
Provide an example of a well-instrumented function and ask Claude to follow that pattern.
Explicitly forbid printing directly to stdout/stderr if your logging infra expects structured logs.
Make Claude explain and self-check
Getting Claude to reason about its own output catches many issues early.
Ask for reasoning after the code:
“After writing the code, briefly explain how it works and why it satisfies the requirements.”
“List potential edge cases this implementation might still miss.”
Use an explicit self-review step:
“Now review your code against the acceptance criteria and tests and describe any mismatches. Fix them if found.”
“Compare your changes against the project’s error-handling rules in CLAUDE.md and adjust.”
Encourage alternative designs:
“Propose one alternative implementation with different trade-offs (performance vs. readability), but mark clearly which one you recommend.”
Control file edits and diffs
Tightly controlling how Claude edits files reduces merge pain and accidental regressions.
Be explicit about allowed changes:
“Only modify the
createOrderfunction inorder_service.py. Do not change any other functions.”“Add new code at the bottom of the file under the ‘// Feature flags’ section only.”
Prefer diff-style outputs for larger changes:
Ask for unified diffs (
diff -u) so you can review and apply changes safely.Instruct: “Do not regenerate the whole file; produce minimal edits needed.”
Avoid hidden behavior changes:
Tell Claude to keep public signatures and observable behavior unchanged unless explicitly told otherwise.
If behavior must change, ask for a short changelog bullet list.
Use Claude for refactoring and understanding
Claude is strong at explaining and reshaping existing code when guided properly.
Clarify your refactoring goals:
“Reduce duplication between A and B by extracting a shared helper.”
“Improve readability and add comments, but do not change runtime behavior.”
Ask for high-level summaries:
“Summarize what this module does, its key responsibilities, and any code smells you see.”
Use the summary to confirm shared understanding before deeper changes.
Have Claude propose better structures:
“Suggest a more modular design for this code, then implement only the new interfaces and stubs first.”
“Identify functions that should be moved to a different module and explain why.”
Guide performance, security, and edge cases
You can push Claude to consider non-happy-path concerns explicitly.
Performance:
Clearly state constraints (“Input can be up to 1M items”, “This runs in a hot path”).
Ask for complexity analysis and possible bottlenecks after code is generated.
Security:
Call out relevant risks: injection, XSS, CSRF, authentication, authorization, secrets handling.
Ask: “Review your code for security issues in this context and fix any problems you see.”
Robustness:
Request explicit handling of nulls, timeouts, retries, and external failure modes.
Provide a list of edge cases and ask Claude to point to where each is handled.
Example prompt template
You can adapt this template as a standard for your team.
Context
“You are helping with a codebase described in CLAUDE.md below. This project is a [brief description]. We use [language, framework, style guide].”
Files
“Here is the current content of
path/to/fileand relevant tests: [paste code].”
Goal
“Task: [single, clear task]. Maintain existing behavior unless explicitly told otherwise.”
Constraints
“Constraints:
Follow [style guide/tools].
Code must pass [tests/commands].
Do not modify [list of files/functions].”
Tests/spec
“Here are the test cases / acceptance criteria / examples that must hold: [paste or describe].”
Output format
“Output: Provide only the updated code for [file(s)], as a unified diff. Then explain in 3–5 sentences how it satisfies the requirements and which edge cases it handles.”
Using a structure like this consistently can dramatically improve Claude’s code quality, reduce rework, and make outputs more predictable.
Safeguards for Responsible AI Use
Require tests for AI-assisted changes above a size threshold Example GitHub Action: block merge if diff touches more than N lines across M files and the PR has zero new or updated tests. Copilot docs recommend automated checks and testing around AI output.
Block merges on security failures Example: run secret scan, SAST rules, and dependency checks on every PR. Reject if any high severity issue appears. Use OWASP input validation reminders in review. owasp.org
Count only code that lands and passes CI when discussing “AI impact” Tie assistant usage to merged PRs and green pipelines rather than raw suggestion counts. This aligns with your metrics pages that caution against surface-only numbers.
Weekly sampling of AI-assisted PRs Have tech leads sample two AI-assisted PRs per team each week for security, clarity, and maintainability. Record findings and feed them back into rules or the prompt cookbook. Cursor rules are designed to evolve with feedback.
Last updated
Was this helpful?
