background-shape
Prompt-Style Comments to Steer Copilot
December 7, 2022 · 4 min read · by Muhammad Amal ai

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.