How do you get production-grade code out of an AI coding assistant, systematically? This guide gives you a complete, reusable workflow.
credit: https://www.youtube.com/watch?v=SS5DYx6mPw8
This guide lays out a reusable, structured process for working with AI coding assistants to produce production-grade code. The examples build a Supabase MCP server in Python, but the methodology applies to any AI-assisted coding scenario.
A few core principles first—the global rules and prompts that follow are all built around them:
Before writing any code, talk things through with the LLM to scope out the project and break down the tasks. Put the high-level plan in PLANNING.md and the concrete tasks in TASK.md. As the project moves forward, have the AI assistant keep both files up to date.
Global rules are the most effective way to make the AI assistant follow the golden rules. Global rules apply to all projects; project rules only affect the current workspace. All the major AI IDEs support both kinds:
Below is a sample rule set (using the Supabase MCP server as the example) that you can grab as a template:
PLANNING.md at the start of every new conversation to understand the project's architecture, goals, code style, and constraints.TASK.md before starting a new task. If the current task isn't recorded there, add it with a brief description and the date.PLANNING.md./tests directory that mirrors the structure of the main codebase.TASK.md immediately after finishing it.TASK.md.Use Python as the primary language.
Follow PEP8, use type hints, and format with black.
Use pydantic for data validation.
Use FastAPI for APIs and SQLAlchemy or SQLModel for the ORM (whichever fits).
Write a docstring for every function, in Google style:
def example():
"""
简要说明。
Args:
param1 (type): 参数描述。
Returns:
type: 返回值描述。
"""
README.md whenever you add a feature, change dependencies, or modify the setup steps.# 原因: inline comment explaining why the code is written this way, not just what it does.TASK.md.MCP lets the AI assistant interact directly with external services, for example:
Looking for more MCP servers? There are curated lists online with a huge number of MCP servers, install instructions included.
MCP configuration docs for each IDE:
Example prompt to use with the Git MCP:
现在代码状态不错,帮我 git commit 保存一下。
The opening prompt matters enormously. No matter how detailed your PLANNING.md is, how well-groomed your TASK.md is, or how thorough your global rules are, that first prompt still needs to be as specific as possible—tell the LLM what you want to build and which docs it can reference.
The specifics depend on your project, but the best thing you can do is give it a similar example to work from. The best-performing prompts in bolt.new, v0, and Archon all come with examples, without exception. If you're using particular tools, frameworks, or APIs, you'll usually need to supply the relevant docs as well.
There are three ways to provide reference material:
@mcp and hitting Tab tells it to search the MCP docs.An opening prompt for building the Supabase MCP server:
参考 @docs:model-context-protocol-docs 和 @docs:supabase-docs,用 Python + FastMCP 写一个与 Supabase 数据库交互的 MCP 服务器。传输方式用 Stdio,需要支持以下操作:
- 读取表中的行
- 创建记录(支持单条和批量)
- 更新记录(支持单条和批量)
- 删除记录(支持单条和批量)
每个工具的描述要写清楚,让 LLM 能准确判断什么时候该用哪个工具。
环境变量需要 Supabase 项目 URL 和 Service Role Key。
先读一下这个 README 了解 Python MCP SDK 的用法:
https://github.com/modelcontextprotocol/python-sdk/tree/main
写完之后更新 README.md 和 TASK.md。
Oh, and remember to start a new conversation once the current one gets long. If you notice the LLM starting to drive you crazy, that's your cue to start over.
For the changes and iterations after the initial prompt, stick to one task per message unless the change is trivial. Dumping a pile of requirements on the LLM at once is tempting, but the more focused the task, the more consistent the output.
A good prompt:
给“列出记录”的函数加一个过滤参数。
A bad prompt:
给列出记录加个过滤功能。另外创建记录那个函数报错说找不到 API Key。还有,README.md 里关于怎么用这个服务器的文档写得太简单了,帮我补充一下。
The key to consistent output is having the LLM change as close to one file at a time as possible.
After each change, don't forget to have the LLM update README.md, PLANNING.md, and TASK.md to match.
You can require the LLM to write tests automatically after implementing each feature via your global rules, or manually follow up with "write me a test for this." Catching bugs early keeps problems from snowballing—this step really matters.
Writing unit tests is admittedly a bit of a chore, and LLM-written tests aren't always perfect, but try to get every feature covered. If you get truly stuck on one test, it's fine to skip it—keep the main flow working first.
A few testing best practices:
tests/ directory.This step is somewhat optional and largely a matter of personal preference, but I want to share my habit anyway. When a project is ready to go live or needs to be shared with others, I usually containerize it with Docker (or Podman).
LLMs are remarkably reliable at anything Docker-related, so this is the most painless packaging approach I've found. On top of that, virtually every cloud platform these days (Render, Railway, Coolify, DigitalOcean, Cloudflare, Netlify…) can run Docker containers. My AI agents, API services, and MCP servers are all deployed as containers.
Example Dockerfile:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 拷贝 MCP 服务器代码
COPY . .
CMD ["python", "server.py"]
Build command:
docker build -t mcp/supabase .
And a prompt to have the LLM generate it for you:
帮这个 MCP 服务器写一个基于 requirements.txt 的 Dockerfile,然后告诉我怎么构建镜像。
Follow this guide to effortlessly set up ESLint and Prettier in VS Code for your Next.js 13 project, ensuring clean and consistent code.
A comprehensive collection of my TypeScript learning notes, from basic concepts to advanced features
Learn to optimize Webflow's Card Slider effortlessly. Enable on mobile, disable on desktop with a seamless, code-free approach.