top of page
Search

# Copilot Instructions — Intent Driven Engineering (Python)

  • Writer: Mark Kendall
    Mark Kendall
  • 3 days ago
  • 4 min read

# Copilot Instructions — Intent-Driven Engineering (Python)


Save the below as pythonintent.md and paste or have copilot read me and you will be IDE modo Intent Driven Engineering


> **For workshop students:** This file teaches Copilot how *we* engineer.

> Drop it at `.github/copilot-instructions.md` in any repo. Copilot Chat,

> agent mode, and code review will read it automatically.


-----


## The one rule that governs everything


**State intent before generating code.** Implementation is downstream of a

clearly-named goal, a constraint set, and a definition of done. If any of

those three are missing, surface the gap — do not guess.


When asked to write code, your first move is to restate, in one or two

sentences, *what problem this solves and for whom*. If the user’s request

doesn’t make that clear, ask before writing.


-----


## How to respond to a request


Follow this order. Skip steps only when the user explicitly says “just

write it.”


1. **Restate the intent.** One sentence. Plain language. No jargon.

1. **Name the constraints.** What must be true? (perf, compatibility,

style, dependencies allowed, dependencies forbidden)

1. **Name the definition of done.** What test, behavior, or output proves

this works?

1. **Propose the approach.** Two or three sentences. Mention the *shape* of

the solution, not the syntax.

1. **Then write the code.**


If the user pushes back on any of the first four, revise before coding.


-----


## Python conventions for this codebase


- **Python 3.11+.** Use modern syntax: `match` statements, `|` union

types, `Self`, `LiteralString` where appropriate.

- **Type hints are mandatory** on every function signature, including

return types. Use `from __future__ import annotations` at the top of

every module.

- **Prefer pure functions.** Side effects belong at the edges (I/O,

network, DB). Business logic stays pure and testable.

- **Dataclasses or Pydantic for data, not dicts.** A `dict[str, Any]`

flowing through three functions is a missing type.

- **Errors are values when reasonable.** Raise exceptions for *truly

exceptional* conditions; return `Result`-like objects or explicit

`None` for expected failure modes.

- **No bare `except`.** Catch the specific exception or don’t catch.

- **Standard library first.** Reach for a dependency only when stdlib

costs more than it saves. Justify new dependencies in the PR

description.

- **Format with `ruff format`. Lint with `ruff check`.** Both must pass

before the code is “done.”


-----


## Testing — the contract, not an afterthought


- **Every behavior change ships with a test.** No exceptions in this

workshop’s codebase.

- **Use `pytest`.** Parametrize aggressively. One test, many cases.

- **Test names describe behavior, not functions.**

Good: `test_returns_empty_list_when_input_is_blank`.

Bad: `test_parse`.

- **Arrange-Act-Assert, visibly.** Whitespace between the three sections.

- **Mock at boundaries, not internals.** If you’re mocking a function in

the same module, the design is wrong.


-----


## What “done” looks like


A change is done when **all** of these are true:


- [ ] The intent is captured in the commit message or PR description.

- [ ] Types pass `mypy --strict` (or `pyright` in strict mode).

- [ ] `ruff check` and `ruff format --check` pass.

- [ ] New behavior has a test; the test fails without the change.

- [ ] No new dependency was added without a one-line justification.

- [ ] The diff is the *smallest* one that achieves the intent.


-----


## Things to avoid (and what to do instead)


|Avoid |Do instead |

|----------------------------------------|-------------------------------------------------|

|Writing code before stating intent |Restate the goal in one sentence first |

|`dict[str, Any]` as a function parameter|Define a dataclass or Pydantic model |

|Catching `Exception` broadly |Catch the specific class; let others propagate |

|Adding a dependency for one helper |Write the helper; it’s usually 10 lines |

|Comments that restate the code |Comments that explain *why*, not *what* |

|Long functions |Functions named after the single thing they do |

|Cleverness |Boring code that a tired teammate can read at 5pm|


-----


## When the user asks for something ambiguous


Examples of ambiguity and the right response:


- *“Add caching.”* → Ask: cache what, keyed on what, invalidated when,

stored where, with what TTL?

- *“Make it faster.”* → Ask: what’s the current measurement, what’s the

target, and what’s the workload we’re optimizing for?

- *“Fix this bug.”* → Ask: what’s the observed behavior vs. the expected

behavior, and what’s the smallest reproduction?

- *“Refactor this.”* → Ask: what property of the current code is wrong,

and what would ‘better’ let us do that we can’t do now?


A good question is faster than a wrong answer.


-----


## Workshop-specific notes


- This codebase is a **teaching artifact**. Optimize for *legibility over

cleverness*. A student should be able to read any function and explain

it in plain language.

- When you generate an example, **annotate the intent in a docstring**

so students see the practice modeled, not just the output.

- If you’re tempted to suggest something “advanced” (metaclasses,

descriptors, monkey-patching), pause and propose the boring version

first. Show the advanced version only if the user asks why.


-----


*This file is the contract. If you find yourself wanting to violate it,

say so out loud and explain why — that conversation is the work.*

 
 
 

Recent Posts

See All

Comments

Rated 0 out of 5 stars.
No ratings yet

Add a rating
Post: Blog2_Post

Subscribe Form

Thanks for submitting!

©2020 by LearnTeachMaster DevOps. Proudly created with Wix.com

bottom of page