Skip to content
Agentic Levels
  • New to AI?
  • Assessment
  • Levels
  • Lessons
  • Tracks
  • Resources
  • Reference
  • What's New
  • What's Next
  • More
    Tool SetupCompareAboutThanksFAQPricingPreferences
  • New to AI?
  • Assessment
  • Levels
  • Lessons
  • Tracks
  • Resources
  • Reference
  • Tool Setup
  • Compare
  • What's New
  • About
  • Thanks
  • FAQ
  • What's Next
  • Pricing

© 2026 Fuentes Studio·Privacy·Terms

yourCouncil
Ready to help
✦

What do you want to understand?

Ask anything about what you're learning.

L2Lesson 1Free

Write Stubs the Model Can Finish

After this, you'll be able to write function stubs that reliably produce useful inline completions, instead of vague or wrong ones.

Before you start

Before diving in, complete Set Up Your Persistent Workspace so the model already knows your project context before you write your first stub.

The idea

Inline completions are pattern-matching engines. They predict what comes next based on what you've already written. The quality of the prediction is almost entirely a function of how much information you packed into the stub.

Here is the before and after: Two stubs for the same function. First: `function processOrders() {`. The model has no idea what Orders look like, what processing means, or what you expect to get back. It will hallucinate a plausible-looking body. Second: `function processOrders(orders: Order[]): { fulfilled: Order[]; failed: Order[] } {`. Now the model knows the input shape, the output shape, and the return structure. The completion it generates will use your actual types, respect the `fulfilled`/`failed` split, and almost certainly be usable.

Three things that make stubs completable. Typed parameters (the model sees exactly what it is working with). A descriptive name that signals intent, not just what (not `process` but `validateAndCharge`). A return type or a comment that describes the expected output. You do not need all three every time. Even one of them lifts the completion noticeably.

Try it (12 min)

Watch out for

  • Accepting the first completion without reading it. The model completes confidently regardless of whether it is correct.
  • Writing function names like `handle`, `process`, or `doStuff`. These give the model almost nothing to work with.
  • Skipping the return type in TypeScript or Python. It is the single highest-value addition to a stub.
  • Expecting the model to know your domain types without seeing them. Open the file that defines your types before you start completing call sites.
  • Treating a bad completion as a tool failure. Nine times out of ten it is a stub problem, not a model problem.

Paste this into Claude:

I want to practice skeleton-driven completions. Here is a function stub I wrote that got a bad or vague completion: [paste your stub here, e.g. a plain `function doThing() {` with no types or detail]. Help me rewrite it as a completable stub: (1) Add typed parameters that describe the input shape. (2) Add a return type or an inline comment describing what the function produces. (3) If the name is vague, suggest a more intent-revealing name. Then explain why each change makes the completion more predictable. I will test the new stub in my editor and report whether the completion improved.

What good looks like:

  • You rewrote at least one stub from a blank/untyped version to a typed version with a return type
  • The completion your editor produced for the new stub was noticeably more specific and usable
  • You can name the three elements that make a stub completable: typed parameters, descriptive name, return type or comment
  • You did not have to edit the generated completion more than one or two lines to make it correct
  • You can describe in one sentence why typed stubs produce better completions than blank ones

What a good response looks like:

Here is the rewritten stub for your `processOrders` function:

Before: `function processOrders() {`

After:
```typescript
/**
 * Validates each order against inventory and marks it fulfilled or failed.
 * Does not mutate the input array.
 */
function processOrders(orders: Order[]): { fulfilled: Order[]; failed: Order[] } {
```

Three changes and why each one matters. First, typed parameter `orders: Order[]`: the completion engine now knows the exact shape of what it is iterating over, including every field on your `Order` type. Second, return type `{ fulfilled: Order[]; failed: Order[] }`: the model knows it needs to split into two arrays, not return a boolean or a count. Third, the JSDoc comment: 'validates against inventory' and 'does not mutate' tells the model the business logic without requiring it to guess. When you trigger the completion now, you should see the body use your actual `Order` fields (like `order.id`, `order.quantity`) instead of invented ones. If it still invents fields, open your `Order` type definition file in another tab before completing.

Go deeper (15 min)

Paste this into Claude:

Take a function you already wrote with AI completion. Strip it back to just the stub: signature, types, and a short comment. Delete the body. Ask your editor to complete it again from the stub only. Compare the two versions: the original completion and this one. Paste both here and tell me: which version is closer to what you actually needed, and why? If the second one is worse, what is missing from your stub that the first session had as surrounding context?

What good looks like:

  • You deliberately regenerated a completion from a clean stub rather than accepting the first one you got
  • You compared the two completions and identified what made one better or worse
  • You adjusted the stub based on what you learned and got a third completion that was at least as good as the original
  • You can explain one specific element of surrounding context that influenced the original completion

What a good response looks like:

Here is the comparison you asked for:

Original completion (from full session with surrounding context): The body used `this.inventoryService.check(order.sku)` and correctly referenced `order.customerId` for logging. It matched your actual service dependencies.

Regenerated from clean stub only: The body invented `checkStock(item)` and used `order.itemId` instead of `order.sku`. Both wrong. The model did not have your `InventoryService` import or your `Order` type visible, so it guessed.

What the original session had that the clean stub did not: your `InventoryService` import at the top of the file and 3 other functions in the same file that used `order.sku` as the identifier. The model pattern-matched from those. When you stripped the file to just the stub, that surrounding context disappeared.

Fix for round 3: Add a one-line comment to the stub: `// Uses this.inventoryService.check(sku: string)` and a typed parameter `order: Order`. That gives the regeneration enough signal to get `order.sku` right without needing the full file context.

When this breaks

  • Breaks when the function has no clear input or output contract, because the model has nothing to pattern-match against and will invent shapes that look plausible but do not exist in your codebase.
  • Breaks in domains the model has weak training coverage on, because typed stubs help but cannot fully compensate for missing knowledge of your specific framework or internal conventions.

Claude can do it for you

Paste a vague stub into a chat with Claude and say: 'Rewrite this as a completable stub. Add typed parameters, a return type, and rename it if the name is vague. Explain each change.' You will get a template you can paste back into your editor before completing.

You can now

Rewrite a vague untyped stub into one with typed parameters, an intent-revealing name, and a return type or comment, and demonstrate that the resulting completion needs at most one or two lines of editing.

Key takeaways

The completion is only as good as the stub. Type your parameters, name your intent, declare your return shape. Then hit Tab.

  • The completion is only as good as the stub you give it
  • Typed parameters, intent-revealing names, and return types are the three signals that lift suggestions
  • Even one of the three lifts the completion noticeably; you do not need all three every time
  • Bad completions are almost always a stub problem, not a model problem

Go deeper

  • Cursor Docs: Getting Started
  • Claude Code Quickstart
  • GitHub Copilot Overview