Prompt-Style Comments to Steer Copilot
TL;DR — Copilot’s suggestion quality is driven by surrounding context. Write 1-3 line comments before functions describing what they do, inputs, constraints. Reference style: “small Stripe-like API wrapper.” Mention the framework version. Naming hints matter.
After where Copilot’s good, tactically improving suggestion quality. Copilot reads 20-30 lines of context above your cursor. Make those lines work for you.
The before / after
Before (bad context):
func getUser(id string) {
// Copilot suggests a generic stub
}
After (good context):
// getUser fetches a User by ID from Postgres.
// Returns ErrUserNotFound if no row matches.
// Caller MUST have an authenticated session.
func getUser(ctx context.Context, db *pgxpool.Pool, id uuid.UUID) (*User, error) {
// Copilot now suggests a SELECT with proper error handling
}
The comment plus the signature give Copilot enough to write the right query, error mapping, and return. Five seconds of comment writing → ~30 seconds of code generated correctly.
Patterns that work
1. State the operation in plain English.
// Refund a paid order. If already refunded, return ErrAlreadyRefunded.
// Reduces inventory. Emits OrderRefunded event.
func (s *OrderService) Refund(ctx context.Context, orderID uuid.UUID) error {
//
}
The comment is half the docs. Copilot uses it as a spec.
2. Reference the framework / version when ambiguous.
// React 18 component. Uses concurrent features.
// Uses useTransition for the filter input.
function SearchableList({ items }: { items: Item[] }) {
//
}
Without the version note, Copilot might suggest patterns from React 16. With it, more likely concurrent-aware.
3. Mention conventions explicitly.
# Repository pattern: return domain.User or raise UserNotFound
# Do NOT raise for empty result sets — use Optional.
def get_user_by_email(db: Session, email: str) -> Optional[User]:
#
Codifies your team’s idioms; Copilot follows.
4. Reference similar functions.
// Like ProcessRefund, but for partial amounts.
// Validates amount > 0 and amount < order total.
func ProcessPartialRefund(...) {
//
}
If ProcessRefund is in the file or recently in scope, Copilot patterns after it.
5. Naming hints in variable declarations.
// User's outstanding subscription balance, in cents (USD).
let balanceCents: number = 0;
// Now Copilot won't randomly suggest balance / 100 transforms.
Type hints + comment = unambiguous.
What NOT to put in prompts
Vague intent.
// Do the thing with the user
function foo(u: User) {
//
}
Copilot will pattern-match against random “do something with user” patterns. Unhelpful.
Aspirational complexity.
// Build a distributed fault-tolerant event-sourced microservice that...
class App {
//
}
Copilot can’t generate a whole app from a comment. Scope to one function or operation.
Marketing language.
// Lightning-fast, blazing-fast, ultra-modern API
function api() {
//
}
Copilot doesn’t care about adjectives. Plain English.
File-level context
The top of the file matters more than people realize. A header comment that establishes context applies to every function below:
// Package billing implements subscription and invoice management.
// Uses Postgres via pgxpool. Emits events to Kafka (topic: billing.events.v1).
// All money values are in cents (USD).
// Time values are timestamptz; never local time.
package billing
Subsequent functions inherit this context. Copilot stops suggesting time.Local or floating-point money.
Inline anchors for choice points
When there are multiple ways to do something:
# Using SQLAlchemy 1.4 style (not 2.0). Use .execute(text("..."))
def list_orders(db: Session, user_id: int):
#
Without the anchor, Copilot picks one randomly. With it, you get what you asked for.
When prompting fails
Sometimes adding more context doesn’t help; Copilot keeps generating wrong code. Signs:
- Suggestion contradicts the surrounding code
- Suggestion contradicts the comment you just wrote
- Suggestion is too generic for the project
In those cases, just write it yourself. The cost of fighting Copilot exceeds the cost of typing.
My pre-function template
For non-trivial functions, I write:
// <name> <verb> <object>. <one sentence about behavior or contract>.
// Returns <return value description>.
// <Critical constraint or invariant>.
func <name>(<params>) <returns> {
Three lines + signature = enough context for ~70% accept rate on the implementation.
Not for every function. For one-line getters or trivial helpers, the comment is overhead.
Common Pitfalls
Long-winded comments. 5+ lines becomes noise. Two crisp lines beat ten verbose ones.
Comments that say what code does, not what it should do. Useless for Copilot AND for human readers.
Out-of-date comments after refactoring. Worse than no comment.
Putting Copilot prompts at file top, then defining many unrelated functions below. Context dilutes; suggestions drift.
Expecting Copilot to write business logic from one line. Decompose: write skeleton, comment each branch, let Copilot fill blanks.
Wrapping Up
Comments are prompts. Treat them as such. 30 seconds of context = better completions for the next 5 minutes. Friday: reviewing AI-suggested code.