best practices for prompt engineering

Prompt Engineering: What It Is and 10 Best Practices

By Zest | Updated | 11 min read

Related guide: Claude Code skills: reusable prompts in a SKILL.md

A laptop on a desk with the words Prompt Engineering over code on its screen

Prompt engineering is writing instructions an AI model can act on: the task, the context it needs, the rules the answer must follow and the format you want back. For developers, it is the difference between a generic snippet you rewrite and code that fits your repository the first time. The ten practices below work in a chat assistant and in coding agents like Claude Code, Codex and Cursor.

Zest shows which skills, models and coding agents your team uses, and links each session to the pull request it led to. Start free

With coding agents, the prompts you would otherwise repeat move into files. Project rules go in CLAUDE.md or AGENTS.md, which the agent reads at the start of every session, and reusable task prompts become skills.

The core prompting techniques

Five techniques cover most prompts. The best prompts often combine them, such as a persona with a few-shot example.

Technique What you do Use it for
Zero-shot Ask directly, with no examples Common tasks with one obvious answer
One-shot and few-shot Show one example, or two to five, of the input and the output you want Formats and conventions that are hard to describe
Chain-of-thought Ask the model to reason step by step before it answers Multi-step logic, debugging, planning
Prompt chaining Split a task into prompts, each building on the last one’s output Features and refactors too big for one answer
Persona Give the model a role: “Act as a security reviewer” Focusing an answer on one concern

Few-shot prompting became practical with GPT-3, introduced in the May 2020 paper Language Models are Few-Shot Learners: a handful of examples in the prompt replaced fine-tuning for many tasks. Chain-of-thought prompting comes from a 2022 Google paper.

1. Be specific and give context

The model knows nothing about your project except what you put in the prompt, or what the agent reads from the repository. Name the stack, paste the relevant code or error, and say what “done” looks like.

A laptop with code on its screen, a closed book, an open book, and eyeglasses on a wooden desk.

  • Vague prompt: create a button component
  • Specific prompt: Create a reusable React button component in TypeScript with Tailwind CSS. It takes an onClick handler and a boolean disabled prop. Match our design system: primary color #3B82F6, white text, rounded-md corners, px-4 py-2.

The second prompt sets the stack, the props and the styling rules, so the code fits without a round of edits.

  • Name your stack: the language, framework and key libraries.
  • Paste the code: the function, class or full error message you’re working on.
  • Point at a pattern: “Follow the structure of components/Input.tsx.”
  • Save what works: keep a prompt that works where the team can reuse it, such as a project rules file or a Claude Code skill.

2. Define the output format

Say what you want back and in what shape. Without it, you get explanation, code and filler mixed together, and you pick the useful parts out by hand.

Clean and minimalist desk setup with an iMac showing 'Clear Format', books, coffee cup, and phone.

  • Vague prompt: Write a React hook for fetching data.

  • Specific prompt: Write a React hook for fetching data. Return three code blocks: the imports, the hook with TypeScript types, and a component that uses it.

  • Be explicit: start with Format your response as: or Return only:.

  • Give a template: Return a JSON object with keys "functionName", "description" and "code".

  • Cut the prose: Return only the function, with no explanation.

This works the same in every assistant; see how to code with ChatGPT, Claude, Gemini and Copilot.

3. Iterate on prompts that miss

When the output misses, find what the prompt left out and add it. Change one thing at a time so you learn which instruction made the difference.

  • First try: Create a button

  • Second: Create a React button

  • Third: Create a React button with a hover state using Tailwind CSS

  • Final: Create a reusable React button component in TypeScript with Tailwind CSS. On hover the background darkens by 10%. It accepts onClick and disabled props. A disabled button has 50% opacity and ignores clicks.

  • Analyze the gap: did the model pick the wrong library, misread the logic or miss an edge case?

  • Refine one step at a time: add one piece of missing information per attempt.

  • Keep the final version: save the prompt that worked, with a note on what changed, so the next person starts there.

4. Show examples (few-shot prompting)

Showing beats describing. One example, or a few, of the input and output you want teaches the model your conventions faster than a list of rules.

Stack of white cards on a wooden table, one showing 'Show Examples' text, in an office setting.

Instead of Write a Go function to fetch user data by ID. Add error handling., show the pattern to copy:

Here is our standard error handling in Go:

func GetProduct(id string) (*Product, error) {
  if id == "" {
    return nil, errors.New("product_id_empty")
  }
  // database logic...
  return &product, nil
}

Write GetUser(id string) that fetches a user profile.
Follow the same error handling pattern for an empty ID.

For data transformations, show before-and-after pairs and leave the last one open:

Convert the user feedback into a JSON object with "type", "component" and "summary" keys.

Feedback: "The login button is broken on the dashboard."
JSON: {"type": "bug", "component": "authentication", "summary": "Login button not working on dashboard"}

Feedback: "We should add a dark mode to the settings page."
JSON: {"type": "feature", "component": "UI", "summary": "Add dark mode to settings"}

Feedback: "The user profile picture is loading slowly."
JSON:

Start with one example (one-shot) and add more only if the output still drifts. Keep your best examples in a shared rules file or skill, so everyone’s generated code follows the same patterns.

5. Break big tasks into a chain of prompts

Split a large task into steps and prompt one step at a time, checking each result before the next. This is prompt chaining: each prompt builds on the output of the one before. It is often mislabeled chain-of-thought, which means asking the model to reason step by step inside a single answer.

  • Vague prompt: Build me an e-commerce checkout flow.
  • Chained prompts:
    1. Create a React component for a shopping cart summary that displays items, quantities and a total price.
    2. Next, build a shipping address form with validation for name, address, city and zip code.
    3. Now write the function that integrates Stripe Elements for payment.
    4. Finally, create an order confirmation page that summarizes the completed purchase.

Each step is a checkpoint where you test the output before building on it.

  • Plan first: ask the agent for a plan, review it, then let it build one step at a time.
  • Use the session’s memory: refer to earlier output instead of pasting it again.
  • Save recurring sequences: “add an API endpoint” or “add a marketing page” can become a skill.
  • Refactor in stages: analyze the code, list the changes, then apply them one at a time.

6. Ask for reasoning and trade-offs

Ask for trade-offs with the code. A short explanation of why this approach, and what it costs, surfaces logic flaws and edge cases before code review does.

  • Vague prompt: Write a Python function to find the shortest path in a weighted graph.
  • Better prompt: Write a Python function that implements Dijkstra's algorithm on a weighted graph stored as an adjacency list. After the code, explain why Dijkstra's fits this problem, its time complexity, and one pitfall to watch for, such as negative edge weights.

Asking a model to “think step by step” before answering is chain-of-thought prompting. Reasoning models now do that on their own: OpenAI’s guide to prompting its reasoning models says such instructions are unnecessary. What still helps is asking for the reasoning you want to read.

  • Ask for alternatives: “Give three ways to solve this and recommend one.”
  • Ask for the gotchas: before you implement, ask what edge cases or common mistakes come with the pattern.

7. Set constraints and guardrails

Say what the model must not do: no new dependencies, no API changes, a size or performance budget. Constraints stop code that is correct in general from being wrong for your project.

  • Vague prompt: Refactor this component to be more efficient.

  • Constrained prompt: Refactor this Vue component for better performance. Constraints: keep the existing public API, stay under 100 lines, add no third-party dependencies, and meet WCAG 2.2 AA, especially for keyboard navigation.

  • Use a constraints section: list the rules under a Constraints: heading in the prompt.

  • Link your standards: point to your style guide or architecture notes.

  • Make standing rules permanent: put “no new dependencies” or “every change needs tests” in CLAUDE.md or AGENTS.md, so every session applies them.

8. Use precise technical terms

Use the exact term for what you want. “Make it faster” makes the model guess; “add a B-tree index” doesn’t.

  • Vague prompt: speed up the database query

  • Precise prompt: For our PostgreSQL database, add a B-tree index on the user_id column of the orders table to reduce SELECT latency for per-user lookups.

  • Name the versions you run: take them from your lockfile, not from memory, so the model doesn’t write code for an older API.

  • Use measurable targets: “keep the bundle under 50 KB” instead of “make it smaller”.

  • Paste exact errors: the full message and code give the model a starting point.

  • Keep a glossary: define internal terms once in your project rules file.

9. Validate and test generated code

Don’t merge generated code you haven’t run. Ask for tests in the same prompt, then run them along with your existing suite.

A laptop on a wooden desk displays code validation checks, next to a coffee cup and books.

  • Vague prompt: Write a Python function to upload a file to S3.
  • Test-inclusive prompt: Write a Python function using boto3 to upload a user-provided file to an S3 bucket. Handle file-not-found and access-denied errors. Then write three pytest tests: a successful upload, a missing local file, and invalid credentials.

On our own team, agents test as they go: 93% of the 221 agent-written bug-fix pull requests we merged between August 12 and October 4, 2026 changed a test file (what 866 agent-written pull requests show). That is one small team, and “changed” doesn’t mean the test was new.

  • Run the existing suite: it catches regressions the new tests won’t.
  • Ask for edge cases: have the model list and test them.
  • Keep a checklist: static analysis, no hardcoded secrets, types pass. Put it in your project rules.

For a debugging workflow, see AI-assisted code debugging.

10. Measure what works for your team

Judge prompting practices by what ships, not by how a session felt. Pick a change, roll it out, and compare merged pull requests, review rounds and time to merge with the period before.

  • Vague approach: Let's all try chained prompts for complex tasks.

  • Measured approach: For the next month, every bug fix starts with a written plan. We'll compare review rounds and time to merge with last month.

  • Set a baseline first: you can’t compare without one.

  • See who uses what: Zest shows which coding agents, models, skills and MCP tools each engineer uses, joined to the pull requests their sessions led to.

  • Review weekly: talk about what worked. Zest’s Friday Team Standup lists the skills and practices that spread across the team that week.

  • Standardize what’s proven: turn it into a skill or a project rule, and share the evidence with it.

Where to start

  1. Write a short project rules file. Your stack, the commands to build and test, and the rules every change must follow, in CLAUDE.md or AGENTS.md.
  2. Turn your most repeated prompt into a skill. Writing tests, opening a pull request and adding an endpoint are common first ones.
  3. Compare prompts as a team. Take one small problem, have everyone solve it with an assistant, and compare what each person asked.

Frequently asked questions

What is prompt engineering?

Prompt engineering is writing instructions an AI model can act on: the task, the context, the constraints and the output format. Good prompts get usable answers on the first try instead of the third. For coding agents, much of it lives in project rules files and reusable skills.

What is the difference between chain-of-thought and prompt chaining?

Chain-of-thought asks the model to reason step by step inside a single answer. Prompt chaining splits a task into several prompts, each building on the output of the last. Chaining keeps big tasks checkable, and reasoning models do step-by-step reasoning without being asked.

Is prompt engineering still worth learning?

Yes, as a basic skill rather than a job title. Stating the task, giving context and setting constraints is how you get usable output from any model. With coding agents, the skill shifts to writing good project rules and skills.

Do I need a data-science background?

No. Prompt engineering is clear writing and precise technical language, not machine learning. Knowing your codebase matters more than knowing how the model was trained.

How do I know if my prompts are working?

Check how much you edit the output, whether the same prompt gives a good result twice, and whether the code gets merged without extra review rounds. For a team, compare merged pull requests and review rework before and after a change in how you prompt.


Zest records each engineer’s coding-agent sessions (Claude Code, Codex, Cursor, Copilot Chat) and links them to the pull requests they led to.