Building with AI Coding Agents: Best Practices for Agent Workflows

Building with AI Coding Agents: Best Practices for Agent Workflows
Page content

Over the past year, I’ve been working extensively with AI coding agents — intelligent assistants that go far beyond code autocompletion. These agents can plan, execute, and iterate on entire development tasks. They function like tireless pair programmers who never lose focus or context, dramatically increasing productivity when guided correctly.

However, without clear direction, agents often produce inconsistent or overly complex outputs. After several messy repositories and unfinished code snippets, I learned that the difference between chaos and clarity lies in how you direct your agent, not just what you ask it to do.

In this post, I’ll share the best practices that have consistently helped me when working with coding agents.

What Are AI Coding Agents?

AI coding agents are autonomous systems that use large language models to perform software development tasks. Unlike simple code completion tools, agents can:

  • Plan: Break down complex tasks into actionable steps
  • Execute: Run commands, edit files, and interact with development environments
  • Observe: Read outputs, check test results, and analyze errors
  • Iterate: Adjust approach based on feedback and continue working

Agent vs. Assistant: Key Differences

Feature AI Assistant AI Agent
Autonomy Waits for prompts Works independently
Memory Session-limited Persistent context
Tools Code suggestions Full IDE/CLI access
Feedback loop Single turn Multi-step iteration
Goal Help you code Code for you

Golden Rules for AI-Assisted Development

After extensive experimentation, I’ve distilled these core principles that consistently lead to better outcomes:

  1. Use markdown files to manage the project — Maintain README.md, PLANNING.md, and TASK.md files for project documentation and task tracking.

  2. Keep files under 500 lines — Split into modules when files approach this limit to maintain readability and maintainability.

  3. Start fresh conversations often — Long chat threads degrade response quality. Restart when conversations get lengthy.

  4. Don’t overload the model — One task per message yields more consistent results than bundling multiple requests.

  5. Test early, test often — Every new function should have unit tests. Catch bugs early to prevent compounding problems.

  6. Be specific in your requests — The more context and examples you provide, the better the output.

  7. Write docs and comments as you go — Don’t delay documentation. Update README.md and code comments during development.

  8. Implement environment variables yourself — Never trust the LLM with API keys or sensitive credentials.

Planning and Task Management

Before writing any code, have a conversation with the AI to plan the initial scope and tasks for the project. This upfront investment pays dividends throughout development.

PLANNING.md

The PLANNING.md file captures high-level vision, architecture decisions, constraints, tech stack, and tools.

Purpose:

  • Document architectural decisions
  • Define tech stack and tools
  • Record project constraints and requirements
  • Establish coding conventions and patterns

Prompt to AI: “Use the structure and decisions outlined in PLANNING.md.”

Have the AI reference this file at the beginning of any new conversation to maintain context consistency.

TASK.md

The TASK.md file tracks current tasks, backlog items, and sub-tasks throughout the project lifecycle.

Purpose:

  • Track active work items
  • Record completed milestones
  • Capture discoveries made during development
  • Maintain a prioritized backlog

Prompt to AI: “Update TASK.md to mark XYZ as done and add ABC as a new task.”

Configure your AI assistant to automatically update TASK.md as it completes work through global rules.

Setting Up Global Rules for AI IDEs

Global rules (or project-level rules) are the most effective way to enforce consistent behavior from AI coding assistants. All major AI IDEs support both global and project-specific rules:

AI IDE Documentation
Cursor Rules docs.cursor.com/context/rules-for-ai
Windsurf Rules docs.codeium.com/windsurf/memories#windsurfrules
Cline Rules docs.cline.bot/improving-your-prompting-skills/prompting
Roo Code Rules Works the same as Cline

Here’s a comprehensive example of global rules you can adapt for your projects:

### 🔄 Project Awareness & Context
- **Always read `PLANNING.md`** at the start of a new conversation to understand 
  the project's architecture, goals, style, and constraints.
- **Check `TASK.md`** before starting a new task. If the task isn't listed, add 
  it with a brief description and today's date.
- **Use consistent naming conventions, file structure, and architecture patterns** 
  as described in `PLANNING.md`.

### 🧱 Code Structure & Modularity
- **Never create a file longer than 500 lines of code.** If a file approaches this 
  limit, refactor by splitting it into modules or helper files.
- **Organize code into clearly separated modules**, grouped by feature or responsibility.
- **Use clear, consistent imports** (prefer relative imports within packages).

### 🧪 Testing & Reliability
- **Always create unit tests for new features** (functions, classes, routes, etc).
- **After updating any logic**, check whether existing unit tests need to be updated. 
  If so, do it.
- **Tests should live in a `/tests` folder** mirroring the main app structure.
  - Include at least:
    - 1 test for expected use
    - 1 edge case
    - 1 failure case

### ✅ Task Completion
- **Mark completed tasks in `TASK.md`** immediately after finishing them.
- Add new sub-tasks or TODOs discovered during development to `TASK.md` under a 
  "Discovered During Work" section.

### 📎 Style & Conventions
- **Follow language-specific best practices** (PEP8 for Python, etc.)
- **Use type hints** where applicable.
- **Use appropriate frameworks** for data validation and APIs.
- Write **docstrings for every function** using a consistent style.

### 📚 Documentation & Explainability
- **Update `README.md`** when new features are added, dependencies change, or 
  setup steps are modified.
- **Comment non-obvious code** and ensure everything is understandable to a 
  mid-level developer.
- When writing complex logic, **add an inline `# Reason:` comment** explaining 
  the why, not just the what.

### 🧠 AI Behavior Rules
- **Never assume missing context. Ask questions if uncertain.**
- **Never hallucinate libraries or functions** – only use known, verified packages.
- **Always confirm file paths and module names** exist before referencing them 
  in code or tests.
- **Never delete or overwrite existing code** unless explicitly instructed or 
  part of a task from `TASK.md`.

Configuring MCP (Model Context Protocol)

MCP enables your AI assistant to interact with external services, dramatically expanding its capabilities:

Essential MCP Servers:

Server Purpose Repository
Crawl4AI RAG Crawl and leverage external documentation github.com/coleam00/mcp-crawl4ai-rag
Supabase MCP Manage databases, tables, and queries github.com/supabase-community/supabase-mcp
Brave Search Search the web for documentation github.com/modelcontextprotocol/servers/tree/main/src/brave-search

Additional Useful Servers:

Server Purpose Repository
Filesystem Read/write, refactor, multi-file edits github.com/modelcontextprotocol/servers/tree/main/src/filesystem
Git Branching, diffing, committing github.com/modelcontextprotocol/servers/tree/main/src/git
Claude Task Master Advanced task management github.com/eyaltoledano/claude-task-master

MCP Configuration Guides:

AI IDE Documentation
Cursor MCP docs.cursor.com/context/model-context-protocol
Windsurf MCP docs.codeium.com/windsurf/mcp
Cline MCP docs.cline.bot/mcp-servers/mcp
Roo Code MCP docs.roocode.com/features/mcp/using-mcp-in-roo

For a comprehensive list of available MCP servers with installation instructions, visit the Model Context Protocol servers repository.

Crafting the Initial Project Prompt

The first prompt to begin a project is the most critical. Even with comprehensive PLANNING.md, clear tasks in TASK.md, and well-configured global rules, you must provide detailed context about what you want the AI to create.

Three Ways to Provide Examples and Documentation:

  1. Use built-in documentation features — Many AI IDEs support referencing documentation directly. For example, typing “@docs” in Windsurf and hitting tab tells the AI to search specific documentation sources.

  2. Have the AI use MCP servers — Instruct the AI to search the web using MCP servers like Brave Search: “Search the web to find other Python MCP server implementations.”

  3. Manually provide examples — Include code snippets, URLs, or reference materials directly in your prompt.

Example Initial Prompt:

Use @docs:model-context-protocol-docs and @docs:supabase-docs to create an MCP 
server written in Python (using FastMCP) to interact with a Supabase database. 
The server should use the Stdio transport and have the following tools:

- Read rows in a table
- Create a record (or multiple) in a table
- Update a record (or multiple) in a table
- Delete a record (or multiple) in a table

Be sure to give comprehensive descriptions for each tool so the MCP server can 
effectively communicate to the LLM when and how to use each capability.

The environment variables for this MCP server need to be the Supabase project 
URL and service role key.

Read this GitHub README to understand best how to create MCP servers with Python:
https://github.com/modelcontextprotocol/python-sdk/tree/main

After creating the MCP server with FastMCP, update README.md and TASK.md since 
you now have the initial implementation for the server.

Important: Restart conversations when they get lengthy. You’ll know it’s time when the AI’s responses start frustrating you or losing coherence.

Modular Prompting for Follow-up Tasks

After the initial project setup, handle follow-up fixes and changes one task at a time. It’s tempting to bundle multiple requests, but focused prompts yield consistently better results.

Good Example:

“Now update the list records function to add a parameter for filtering the records.”

Bad Example:

“Update list records to add filtering. Then I’m getting an error for the create row function that says API key not found. Plus I need to add better documentation to the main function and in README.md for how to use this server.”

The key principle: Have the AI focus on updating a single file whenever possible.

Always instruct the AI to update README.md, PLANNING.md, and TASK.md after making changes to keep documentation synchronized with code.

Testing Strategy

Catching bugs early prevents compounding problems. Either configure global rules to mandate unit tests after each feature, or explicitly request tests as a follow-up task.

Best Practices for AI-Generated Tests:

  • Create tests in a /tests directory mirroring your main application structure
  • Mock external service calls — Never make real database or API calls in tests
  • Test three scenarios per function:
    • One successful/expected use case
    • One intentional failure (to verify error handling)
    • One edge case

If the AI gets stuck on complex test scenarios and you need to move forward, you can explicitly instruct it to bypass test writing for that specific feature and revisit later.

Containerization and Deployment

When ready to deploy or share your project, containerization with Docker provides the most consistent packaging method. AI assistants excel at Docker configurations, making this an ideal task to delegate.

Benefits of Containerization:

  • Consistent deployment across environments
  • Supported by virtually all cloud platforms (Render, Railway, Coolify, DigitalOcean, Cloudflare, Netlify)
  • Simplifies dependency management
  • Easy to version and roll back

Example Dockerfile:

FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy the application files
COPY . .

CMD ["python", "server.py"]

Build Command:

docker build -t myapp:latest .

Example Prompt:

Write a Dockerfile for this application using requirements.txt. Give me the 
commands to build and run the container.

I containerize all AI agents, API endpoints, and MCP servers as Docker containers—it’s the most reliable deployment method I’ve found.

Conclusion

Working effectively with AI coding agents is a skill that improves with practice. The key takeaways from my experience:

  1. Invest in setup — Time spent on PLANNING.md, TASK.md, and global rules pays exponential dividends.
  2. Communicate clearly — Specific, focused prompts with examples produce superior results.
  3. Test continuously — Catch bugs early before they compound.
  4. Document as you go — Keep README.md and code comments synchronized with changes.
  5. Know when to restart — Fresh conversations beat struggling with context-degraded threads.

AI coding agents are powerful tools that can dramatically accelerate development when guided properly. They’re not replacements for developer judgment—they’re force multipliers that amplify your productivity when directed with clear intent and structured workflows.