The Agent Skill Model for Python Teams
An AI coding assistant already knows how to write a FastAPI route, add type hints, or wire up a Celery task in general - that knowledge came from its training, not from your team.
Search across all documentation pages
An AI coding assistant already knows how to write a FastAPI route, add type hints, or wire up a Celery task in general - that knowledge came from its training, not from your team.
What it doesn't know by default is which Python version your services actually run, whether your team standardizes on Pydantic v2 patterns or still carries v1 code, which logging fields are mandatory, or which shortcut a past incident taught everyone never to take again. An Agent Skill is how a team encodes that gap - the specific, local, version-pinned decisions - into something an assistant can be handed at the exact moment it needs them, instead of hoping a prompt happens to mention all of it.
This page is the model underneath the individual skill pages in this section - FastAPI Expert Skill, pytest / Testing Skill, Type-Hinting Skill, Packaging & Publishing Skill, and the rest each look like separate skills, but they're all built from the same three parts described here.
SKILL.md file - that scopes an AI assistant's default behavior to one team's specific conventions for one recurring Python task.A decision domain is the scope a single skill owns - "scaffold a FastAPI service," "review a PR for type-hint coverage," "package a library for PyPI," "build a data pipeline" - and the first rule of the model is that one skill covers exactly one domain. A skill that tries to cover everything stops being a specific contract and becomes a vague, general-purpose prompt with extra formatting, which defeats the point.
A skill is invoked at a trigger - a moment in the work where its specific guidance applies, rather than sitting passively as background reading the way a wiki page does. "New microservice in the monorepo," "we're standardizing type hints before a mypy rollout," "this PR touches the training pipeline" are all triggers; the skill exists specifically to be reached for at that moment, not browsed ahead of time.
A useful analogy is a lab protocol handed to a new research assistant on their first day. It doesn't re-teach them how Python or statistics work, they already know that. It tells them exactly which conventions apply here: which random seed to fix, which validation split to use, which shortcut a past experiment proved was a mistake. That's the difference between a skill and a tutorial - a tutorial builds general knowledge; a skill applies specific, local knowledge at the exact moment it's needed.
Every skill is built from three parts, and a SKILL.md file missing any one of them is closer to a doc than a skill:
pyproject.toml, router modules, a test suite). This is what makes a skill's output checkable rather than just plausible-sounding. trigger recognized ──▶ skill loaded ──▶ guardrails applied ──▶ output produced
│ │ │ │
"new FastAPI stack pin + "Pydantic v2 only, pyproject.toml,
service needed" decision tree never sync DB in routers, tests,
for this domain an async route" verification cmds
The stack pin - the exact Python, framework, and library versions a skill assumes - exists because an assistant's training data spans years of API history, and without an explicit pin it has no reliable way to know which era of guidance is current for your codebase right now. FastAPI Expert Skill states its pin (Python 3.14, FastAPI 0.115+, Pydantic 2) in its header for exactly this reason; a skill without one is implicitly trusting the model to guess correctly, which it often won't.
The output side of the contract matters as much as the input side: skill outputs in this section are required to end in verifiable commands - uv run pytest, ruff check, mypy or pyright, a curl against a health route - specifically so a human isn't left evaluating an assistant's prose confidence, but can run something objective and see whether it actually passes.
A skill's guardrails narrow the space of likely mistakes, but they are not a substitute for review - the model producing output under a skill's guidance is still the same underlying model, applying the same reasoning process, just with better local context to reason from. Treating skill output as pre-approved because it followed a contract is a mistake; the contract exists to make output checkable, not to make checking optional.
Skills also age, the same way any version-pinned artifact does. A skill written against Pydantic v1 and Python 3.10 becomes actively misleading once a codebase moves to Pydantic v2 and Python 3.14, not neutral, actively wrong, because it will confidently apply outdated patterns (.dict() instead of model_dump(), no structural pattern matching) to a newer stack.
There's a real security dimension specific to skills that scaffold code: a guardrail like "never commit real secrets, .env.example placeholders only" is only valuable if it's explicit, because a generic assistant asked to "add config for a database connection" has no way to know your org's convention is a secret manager rather than a literal connection string in a file.
Python's split between application engineering and data/ML work adds a domain-specific wrinkle other ecosystems handle less often: a skill scoped to "build a data pipeline" or "train a PyTorch model" often needs guardrails around reproducibility (fixed seeds, pinned dataset versions, logged hyperparameters) that a web-service skill has no equivalent for, which is why this section keeps those as clearly separate decision domains rather than one generic "write Python" skill.
Skills are deliberately positioned as a layer on top of existing human documentation, not a replacement for it - each skill page in this section states directly that the corresponding human cookbook pages (fastapi/, pytest/, packaging-publishing/) remain authoritative, and a skill's job is to route an assistant to the right convention at the right moment, not to become the new source of truth itself.
| Approach | Strength | Weakness | Best Fit |
|---|---|---|---|
| Raw prompting, no skill | Fast to start, no maintenance overhead | Drifts to generic training defaults; conventions repeated (or forgotten) every time | One-off, low-stakes tasks with no house convention to violate |
| Agent Skill (this model) | Encodes specific, version-pinned conventions; reusable across the team | Needs authoring and upkeep as the stack evolves | Recurring, decision-domain-scoped tasks with a real cost to getting defaults wrong |
| Full agent autonomy, no human review | Fastest iteration loop, no human bottleneck | No objective check on output; guardrails alone don't catch everything | Rarely appropriate for production Python changes, even skill-guided output benefits from review |
A structured SKILL.md contract - triggers, inputs/outputs, guardrails, and a stack pin - that scopes an AI assistant's behavior to one team's specific conventions for one recurring Python task.
Documentation is written for a human to read and internalize over time; a skill is written to be invoked at a specific trigger and to produce a checkable output. A skill without triggers, an input/output contract, and guardrails is functionally just a doc with extra formatting.
You can, but it doesn't scale - conventions get forgotten, phrased inconsistently, or omitted under time pressure, and the assistant quietly falls back to its generic training defaults whenever a specific instruction is missing. A skill exists precisely so that context doesn't depend on someone remembering to type it correctly every time.
Triggers (when to invoke it), an input/output contract (what it needs and what it produces), and guardrails (explicit boundaries on what it should never do). A SKILL.md missing any of the three is closer to a passive doc than an invocable skill.
Because an assistant's training data spans multiple years of Python and framework history, and without an explicit pin it has no reliable way to know which era of guidance currently applies to your codebase, the pin removes that ambiguity outright.
It's the specific scope a skill owns, scaffolding, testing, packaging, data pipelines. Limiting a skill to one domain keeps its triggers and guardrails specific and checkable; a skill that tries to cover everything degrades into a vague general-purpose prompt.
No, a skill's guardrails reduce the likelihood of a wrong default, but the output still needs to pass the same objective checks (pytest, ruff, mypy) and the same human review any other change would. Skill outputs are explicitly required to end in verifiable commands for this reason.
Yes, a pipeline or model-training skill typically guards reproducibility (fixed seeds, pinned dataset versions, logged hyperparameters), while a web-service skill guards things like async correctness and secret handling. Keeping these as separate decision domains is deliberate.
An AI coding assistant, at the moment its trigger condition is recognized, either because a human explicitly invokes it or because the assistant's tooling matches the current task to a known skill's trigger.
Yes, and arguably faster, because a stale skill doesn't just become outdated, it actively and confidently applies old guardrails and version pins to a newer stack, which is worse than no guidance at all.
It shouldn't by design, skills are meant to route to and reinforce the authoritative human documentation, not diverge from it. A skill that drifts out of sync with its referenced cookbook pages is a sign the skill itself needs updating.
No, a guardrail is an instruction shaping what the assistant should avoid doing while producing output; a test is an objective, automated check run against the output afterward. Guardrails reduce how often a test needs to catch something in the first place, but they don't replace running it.
A one-off task with no repeated convention to encode and no real cost if the assistant's generic default is used, writing a skill for something that will only ever come up once is pure overhead with no return.
Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Pydantic 2, and ruff 0.9+.
Reviewed by Chris St. John·Last updated Jul 15, 2026