Prompting Coding Assistants

This content was generated with the assistance of AI and should be verified against the official documentation of each tool and framework before being relied on in production.

This section’s bibliography lists the reference material consulted while preparing these pages.

Examples on this page use the current GitHub Copilot Chat extension for VS Code and the current Claude Code CLI, both checked against their official documentation as of 2026-09-28. The running example throughout is DocsAssistant API, a small Spring Boot + Python sample: the controller lives at src/main/java/com/example/docsassistant/DocsController.java, its tests at src/test/java/com/example/docsassistant/DocsControllerTest.java, and its embeddings are built by a Python script at ingest/build_index.py. This page assumes Prompt Engineering Fundamentals and does not repeat it: roles, the prompt anatomy figure, delimiters and few-shot prompting apply to a coding assistant exactly as described there. What follows is that anatomy applied specifically to code — what "context" and "acceptance criteria" mean when the input is a codebase and the output is a diff.

Applying the prompt anatomy to code

A coding assistant’s "input" is rarely a self-contained question — it is a change to make inside an existing codebase, so the context and instructions parts of the anatomy carry more weight than they do for a general chat prompt. Four habits consistently separate a prompt that lands the first time from one that needs several rounds of correction.

The specificity checklist for code

Before sending a coding prompt, check it against four things a vague request tends to leave unstated:

Specify Vague Specific

Language / version

"Add an endpoint that returns related pages."

"Add the endpoint in Java 21, matching the Spring Boot 3 style already used in this file."

Files

"Add an endpoint that returns related pages."

"Add it to src/main/java/com/example/docsassistant/DocsController.java, next to the existing getPage handler; the embeddings it reads come from ingest/build_index.py."

Constraints

"Add an endpoint that returns related pages."

"Don’t add a new Maven dependency; query the index ingest/build_index.py builds through the existing EmbeddingIndex service rather than reading the FAISS files from Java, and keep the response shape [{"pageId": string, "score": number}]."

Acceptance criteria

"Add an endpoint that returns related pages."

"Done means: mvn test passes, an unknown page id returns 404, and a page with no embedding yet returns an empty list rather than a 500."

The four rows compose into a single prompt rather than four separate ones — the "coding" example under SDLC phase examples below shows them combined. See GitHub Copilot — Prompt engineering.

Pasting interfaces and types

Rather than describing a data shape in prose and hoping the assistant infers the right field names, paste the actual interface, record or DTO the new code has to match. This removes an entire class of the "inconsistent examples" anti-pattern from Prompt Engineering Fundamentals: the model cannot invent a field name that conflicts with a type it can already see.

Here is the record this endpoint must return:

public record RelatedPage(String pageId, double score) {}

Implement GET /api/pages/{id}/related in DocsController.java so it returns a
List<RelatedPage>, sorted by descending score, using the existing EmbeddingIndex service.

Leading words

A leading word is the opening token of the code you want — def, SELECT, public — placed at the end of the prompt (or, for ghost-text completion, literally typed into the editor) so the assistant continues from there instead of deciding the shape of the answer itself. This is the same next-token mechanics Sampling & Decoding describes, applied on purpose: the model is far more likely to produce a matching, compilable continuation of public List<RelatedPage> findRelated( than to produce an equivalent method from a bare description.

In GitHub Copilot (VS Code)
public List<RelatedPage> findRelated(String pageId) {
    // Copilot ghost-text continues from here as you type
In Claude Code
$ claude "Complete this method in DocsController.java so it calls the existing
EmbeddingIndex service and returns the 5 nearest pages:
public List<RelatedPage> findRelated(String pageId) {"

Copilot’s own guidance covers this as starting from a partial signature or a SQL keyword and letting completion finish it; see GitHub Copilot — Prompt engineering.

Modular asks

A single prompt that asks for the endpoint, its tests, its Javadoc and a refactor of the surrounding class in one turn tends to under-deliver on at least one of those four things, for the same reason the "overloaded" anti-pattern does in the general case. Ask for one deliverable per turn instead, in dependency order: the implementation, then its tests, then its docs — exactly the phase-by-phase breakdown under SDLC phase examples below. Both tools document this directly: Copilot’s guidance is to "break complex tasks into simpler tasks" (GitHub Copilot — Prompt engineering), and Claude Code’s is to explore, then plan, then implement as separate steps — covered in depth on Plan-First Workflows — (Claude Code — Best practices).

Anti-patterns for code prompts

The general anti-patterns table in Prompt Engineering Fundamentals covers vague, overloaded and under-delimited prompts in general. The five rows below start with the two of those that bite hardest in code, Vague ask and Overloaded ask, restated on DocsAssistant API, and then add three failure shapes specific to coding prompts:

Anti-pattern What it looks like on DocsAssistant API Why it fails

Vague ask

"Make the related-pages thing better."

No file, no current behavior and no target behavior: the assistant cannot tell whether "better" means faster, more accurate, better-tested or better-documented, and has to guess which axis to work on.

Overloaded ask

"Add the related-pages endpoint, write its tests, document it, and refactor DocsController to use records everywhere while you’re at it."

Four unrelated deliverables compete for one turn’s attention; a shallow or skipped sub-task is common, and a single diff mixing a new feature with an unrelated refactor is hard for a human to review afterward.

No acceptance criteria

"Add GET /api/pages/{id}/related."

With no stated "done" condition — which status code an unknown id returns, whether mvn test must pass, what an empty-embedding page should return — the assistant will pick its own definition of finished, which may not match what the reviewer expects.

"The above code"

"Fix the bug in the code above." after three code blocks have appeared earlier in the session, or after none have.

The prompt refers to something by position in a conversation the model may not still hold in full, especially once context has been compacted; the fix is to paste or @-reference the actual file, as Context Windows & Memory covers for truncation and compaction generally.

Ignoring clarifying questions

The assistant asks "should an id with no embedding yet return 404 or an empty list?" and the reply is "just make it work."

A clarifying question exists because the prompt was genuinely ambiguous on a decision the assistant cannot make on its own; answering it directly costs one short reply, while "just make it work" forces a guess that then has to be caught and corrected in review instead.

A prompt per SDLC phase

Every prompt below is a before/after pair on the same DocsAssistant API feature — adding GET /api/pages/{id}/related, which returns the pages most semantically similar to a given page id, using the existing EmbeddingIndex service over the index ingest/build_index.py builds — so a single feature can be followed from planning through to its pull request description.

Planning / PRD

Before, the ask has no scope, no files and no decisions to interview about:

We should let people find pages similar to the one they're looking at.

After applies the specificity checklist and asks the assistant to interview before writing anything, the spec-first pattern Plan-First Workflows covers in depth:

$ claude "I want to add a 'related pages' feature to DocsAssistant API: given a page
id, return the pages most semantically similar to it, reusing the existing
EmbeddingIndex service over the index ingest/build_index.py builds. Interview me
about the response shape, the unknown-id case, the no-embedding-yet case, and how it
should be tested. Keep asking until we've covered everything, then write the result to SPEC.md."

Coding

Before gives a goal with no file, constraints or acceptance criteria:

Add an endpoint for related pages.

After combines the four rows of the specificity checklist into one request, shown in both tools:

In GitHub Copilot (VS Code)
Add GET /api/pages/{id}/related to DocsController.java, next to getPage. Get the 5
nearest pages from the existing EmbeddingIndex service, which queries the index
ingest/build_index.py builds, and return them as [{"pageId": string, "score": number}],
sorted by descending score. Return 404 when id is unknown. Use Java 21, match the
existing @RestController style in this file, and don't add a new Maven dependency.
Run the tests after and fix any failures.
In Claude Code
$ claude "Add GET /api/pages/{id}/related to
@src/main/java/com/example/docsassistant/DocsController.java, next to getPage. Get
the 5 nearest pages from the existing EmbeddingIndex service, which queries the index
ingest/build_index.py builds, and return them as [{\"pageId\": string, \"score\":
number}], sorted by descending score. Return 404 when id is unknown. Use Java 21,
match the existing @RestController style in this file, and don't add a new Maven
dependency. Run mvn test after and fix any failures."

Tests

Before names no file, no cases and no conventions to follow:

Write tests for the related endpoint.

After scopes the file, lists the specific cases, and points at the existing test conventions to match:

Write JUnit 5 tests in src/test/java/com/example/docsassistant/DocsControllerTest.java
for GET /api/pages/{id}/related: a known page id returns 5 results ordered by
descending score; an unknown id returns 404; a page with no embedding yet returns an
empty list rather than an error. Use the existing @SpringBootTest setup already in
this file and don't add a mocking library that isn't already a dependency.

Debugging

Before restates the symptom with no location and no reproduction:

The related endpoint test is failing, fix it.

After follows the test-driven debugging pattern Testing & Debugging with AI covers: name the failing test, paste the actual error, and ask for the root cause rather than a workaround:

$ claude "DocsControllerTest#relatedPages_unknownId_returns404 is failing with a 500
instead of a 404:
[paste the stack trace here]
Find where DocsController.related handles a missing embedding and fix the root cause,
not by catching the exception at the controller layer. Re-run
mvn test -Dtest=DocsControllerTest and confirm it passes."

Docs

Before leaves "add docs" to mean anything from a code comment to a new page:

Add docs for the new endpoint.

After names the two places documentation actually needs to change and the style to match, the pattern Refactoring & Documentation covers for docstring and README generation generally:

Add Javadoc to DocsController.related describing the request, the response shape and
the 404 case, matching the Javadoc style already on the getPage method above it. Then
add a short "## API" section to this repo's README.md documenting
GET /api/pages/{id}/related with one example curl call.

PR description

Before asks for a summary with no diff scoped and no length or content target:

Write a PR description.

After scopes the changed files and states the shape a reviewer needs, the same convention Reviewing AI-Generated Code assumes on the receiving end:

$ claude "Write a PR description for the diff adding GET /api/pages/{id}/related.
Summarize what changed in DocsController.java, DocsControllerTest.java and
ingest/build_index.py, call out the 404 behavior for an unknown id and the empty-list
behavior for a missing embedding, and add a short manual test plan a reviewer can run.
Keep it under 200 words."