Your cloud setup shouldn't take longer than your actual build. Instant VMs, built-in HTTPS, persistent disks - zero config drama. Spin up, SSH in, ship it. That's exe.dev.
π Get started today

Your cloud setup shouldn't take longer than your actual build. Instant VMs, built-in HTTPS, persistent disks - zero config drama. Spin up, SSH in, ship it. That's exe.dev.
π Get started today
Every CI debug session ends the same way: 10 commits called fix: ci, fix: ci again, fix: asdf. You push a guess, wait 10 minutes for a 15-step pipeline to fail at step 14, look at logs, push another guess. It's such a waste of time. Stop guessing!
Depot CI lets you run real CI against your local uncommitted changes. Edit a workflow, run it, get an answer. No commit, no push, no polluted git history. If logs aren't enough, stop the run after the expensive setup step and SSH straight into the runner. You can pw, ls, and check what's actually on the machine instead of inventing it in your head.
The loop is three commands:
bashdepot ci run --workflow .depot/workflows/ci.yml depot ci run --workflow .depot/workflows/ci.yml --ssh-after-step 3 depot ci ssh <run-id>
Migration is one command: depot ci migrate picks up your existing GitHub Actions workflows and copies them over. Your .github/ folder stays intact, so you can run both in parallel until you're ready to cut over.
In modern software development, there are two common paths:
Neither of these paths is great.
I want to tell you something about AI-assisted development in 2026.
If you don't understand your programming language deeply, your main web framework, HTTP, databases, concurrency fundamentals, Architecture Patterns, tradeoffs... You can't tell when the code generated by Claude or Copilot is subtly wrong - and it will be, often enough to matter in production.
AI amplifies what you already know.
The stronger your fundamentals, the better your judgment on what Architecture Decisions to make, what to keep, what to fix, and what to throw away entirely. And going forward, developers with deep knowledge who operate AI, will be the most valued.
Over the past year, I built a 10-step workflow that I use to ship quality software much quicker with AI. This workflow is designed to create well-architected, production-ready software with solid architecture, proper validation, error handling, security, and clean code.
You should treat AI as your personal assistant who helps you in each phase of design and development. You guide it through a structured process where each step builds on the output of the previous one.
In this post, I will share the complete workflow with detailed prompts you can adapt for your own projects.
In this post, we will explore:
Let's dive in.
The most common way developers use AI for coding is what I call "vibe coding." You open a chat, type "build me a REST API for managing orders," and get back something that compiles.
The generated code typically has:
This happens because the AI has no context about your project. It does not know your architecture decisions, your team's coding conventions, your error handling patterns, or your deployment constraints. It gives you a generic answer to a generic question.
And even with the best AI models, like Claude Opus, with such generic prompts, you cannot guarantee that the output will be production-ready.
Production-ready code means something specific:
To achieve this, we need a better process. When you give AI structured requirements, architecture decisions, and code examples to follow, the output quality increases dramatically.
The workflow I share in this post mirrors how experienced developers already think:
AI accelerates each step, but the human remains the architect and decision-maker. I always said that the creative and decision-making part should always be on us, humans.
I have created and refined this workflow over time to ship production-quality software with AI.
The workflow has 5 phases and 10 steps:
Phase 1: Requirements and Planning
Phase 2: Architecture and Specification
Phase 3: Backend Implementation
Phase 4: Frontend Implementation
Phase 5: Deployment
Each phase produces artifacts that feed into the next phase.
Let's walk through each step in detail.
Every project starts with requirements (regardless of whether you use AI). Skip this step, and you will spend more time fixing misunderstandings than writing code.
A Business Requirements Document (BRD) describes what the system should do from the user's perspective. It covers user roles, core features, workflows, business rules, and edge cases.
If you already have a BRD, upload it to Claude Code, switch to Opus 4.7 model and use Plan Mode. Opus can handle 1M tokens in a single prompt, which is enough for documents with 500 pages (I haven't tested it with larger documents).
Plan Mode tells Claude to analyze and reason through the problem before generating anything. This is critical. Without it, Claude will jump straight to code.
Here is the prompt I use for analyzing business requirements:
markdownYou are a Senior Business Analyst reviewing a Business Requirements Document. Read the attached BRD and analyze it thoroughly. For each feature, identify and document: 1. All user roles and their permissions 2. Core entities and their relationships 3. Complete user workflows (step by step) 4. Business rules and validation constraints 5. Edge cases and error scenarios 6. Any ambiguities or missing requirements Present your analysis as a structured document. Flag every ambiguity with a [CLARIFICATION NEEDED] tag so we can resolve it before moving to architecture.
If you do not have a BRD, you can create one interactively. Describe your project idea, and ask Claude to generate a BRD by asking you clarifying questions:
markdownI want to build [describe your project in 2-3 sentences]. Help me create a Business Requirements Document by asking me clarifying questions about: - User roles and permissions - Core features and workflows - Business rules and constraints - Integration requirements Ask questions one section at a time. After I answer, I summarize my answers and move to the next section.
The goal of this step is to eliminate ambiguity. Every unclear requirement will become a bug or a rework cycle later.
P.S. To speed up the process, I use the Wispr Flow app to dictate rather than type. It costs me $12/month, and it's absolutely worth it, as it saves so much time for typing. If you want to try it, you can use my referral link to get 1 month for free.
Most developers skip non-functional requirements and pay for them later during production incidents.
Non-functional requirements (NFRs) define the quality attributes of your system:
These constraints directly affect architecture decisions in the next step.
Here is the prompt I use:
markdownBased on the business requirements we defined, help me define non-functional requirements for this project. For each category below, extract from the document, and if missing, suggest specific, measurable targets: 1. Availability: Uptime SLA, acceptable downtime per month 2. Performance: API response time targets (p50, p95, p99), page load time targets 3. Scalability: Expected concurrent users, data growth rate, peak load scenarios 4. Security: Authentication method, authorization model, data encryption requirements, compliance needs 5. Cost: Infrastructure budget constraints, hosting preferences (cloud provider, self-hosted) Present each requirement with a measurable target and the reasoning behind it.
This is just an example; your task as an Architect is to define the NFRs for your project. There are way more than I have mentioned. See the full list here.
After Claude suggests targets, challenge them. Are they realistic for your project size? Do you really need 99.95% uptime for your project?
Overengineering starts with inflated non-functional requirements. The output of this step is a short document (usually one page) that will guide every architecture decision that follows.
This is where many developers make their biggest mistake with AI: they accept the first architecture suggestion without questioning it.
I use Claude as an Architecture Consultant, not as an authority. I present the requirements and NFRs, ask for options with trade-offs, and then I make the decision myself.
Here is the prompt:
markdownYou are a Solution Architect. I need help designing the architecture for the project described in the attached requirements. Based on the business requirements and non-functional requirements, propose 2-3 architecture options. For each option, provide: 1. Architecture style (Modular Monolith, Microservices, Serverless) 2. Project structure and module/service boundaries 3. Database choice and schema approach 4. API design approach (REST, GraphQL, gRPC, Events) 5. Authentication and authorization strategy 6. Deployment model For each option, clearly state: - Pros and cons - Which NFRs does it satisfy, and which ones does it trade off - Team size and expertise requirements - Estimated complexity Recommend one option and explain your reasoning.
For most projects, I use a Modular Monolith with Vertical Slice Architecture right from the start. This gives you clean module boundaries without the operational complexity of microservices. You can always extract modules into separate services later if needed. Read more about architecture trade-offs in my other post.
After choosing the architecture, I use an interactive conversation to define the details:
The key is to challenge every proposal. Ask "Why this approach over X?" and "What happens when Y fails?"
The output of this step is an architecture document that describes the system structure, technology choices, and the reasoning behind them.
A backend specification is a detailed Markdown file that describes every aspect of the implementation. It is so detailed that a developer could implement the entire backend without asking many questions.
When you feed Claude a specification file, the generated code is consistent, follows your patterns, and requires minimal rework.
Before generating any specification or code, set up a CLAUDE.md file in the root of your project.
This is the single most impactful thing you can do.
CLAUDE.md is a Markdown file that Claude Code automatically loads into context when you open a project.
It tells Claude your tech stack, architecture, coding conventions, and patterns, so every generated file is consistent from the start.
What to include in CLAUDE.md:
What NOT to include:
.editorconfig for that)@ instead)Here is the CLAUDE.md template I use for my .NET backend projects:
markdownundefined
[Project name] - Modular Monolith Web API
**How to reference other files from CLAUDE.md.** For large projects, keep CLAUDE.md under 100 lines and split detailed rules into separate files using the `@` import syntax: ```markdown @.claude/rules/architecture.md @.claude/rules/testing.md @.claude/rules/api-conventions.md
You can also create module-specific rules that only apply to certain paths. Place them in .claude/rules/ with a YAML frontmatter:
markdown--- paths: - src/Modules.Users/** ---
With CLAUDE.md in place, your specification prompt becomes much shorter. Claude already knows your project structure, file naming, patterns, and conventions. The prompt only needs to describe the business-specific content: entities, endpoints, and business rules. Here is the prompt I use: ```markdown Based on the architecture we designed, create a detailed Backend Implementation Specification as a Markdown file. The specification must include: 1. Entity Definitions - All entities as C# classes with property types - Value objects and enums - Entity relationships 2. Database - EF Core mapping configuration for each entity - EF Core Migrations - Seeding strategy with sample data using Bogus 3. API Endpoints - For each endpoint: HTTP method, route, request body, response body with C# record definitions - Business rules and validation rules per endpoint - Error scenarios and expected error responses 4. Authentication and Authorization - Which endpoints require authentication - Which endpoints require specific policies or roles
There is no need to describe file naming, handler patterns, DI registration, or project structure. Claude already knows all of that from CLAUDE.md.
I iterate on this specification until it covers every feature. Every hour spent on the specification saves 3-5x as many hours of rework, rewriting and debugging generated code.
This is the core implementation step. With CLAUDE.md and the specification already in place, the implementation prompt is short. Claude already knows your architecture, patterns, file naming, and conventions.
It has the specification with all entities, endpoints, and business rules. The prompt just needs to connect the two.
Here is the prompt I use:
markdownYou are a Principal Developer producing code of exceptional quality, following Clean Code principles. Your code is a pleasure to read, maintain and work with. Read the Backend Specification file and implement all features. Follow existing code patterns - see @file:CreateShipment.Endpoint.cs, @file:CreateShipment.Handler.cs, and @file:CreateShipment.Validator.cs as reference examples.
That is it. Three sentences plus a few @file references.
This works because Claude combines context from multiple sources:
The @file references are the most powerful technique in the entire workflow.
Instead of describing your patterns in words, you point to actual code files.
Claude reads them and follows the same style. If you want AI to generate high-quality code, you must provide high-quality code examples for it to follow.
After generating the backend code and all the tests pass, review it.
I want a fresh look at the code while reviewing. That's why I opened a new session in Claude to reset the context. I use a three-pass review approach. Each pass focuses on a different aspect:
markdownReview the generated code with three passes: Pass 1 - Code Quality: - Are naming conventions consistent across all files? - Are all handlers following the same pattern? - Are there any unused imports or dead code? - Is the code DRY without being over-abstracted? Pass 2 - Performance: - Are there any N+1 query issues in EF Core calls? - Are there any unnecessary database round-trips? - Are all async methods properly awaited? - Are CancellationTokens passed through the entire call chain? Pass 3 - Security: - Are all endpoints properly authorized? - Are all user inputs validated before processing? - Are there any SQL injection or XSS vulnerabilities? - Are sensitive data fields excluded from responses? - Are sensitive data fields excluded from logging? For each issue found, show the file, the problem, and the fix.
Claude can find its own mistakes when you ask specific questions. The key is being specific. "Review this code" produces generic feedback. "Check for N+1 queries in EF Core" produces actionable findings.
After fixing issues, I also run architecture tests to verify that the generated code follows the intended architecture. I have a set of architecture test examples, and I use them as a reference to quickly write them with AI for my project.
I also ask AI to create HTTP request files in my IDE (supported by Visual Studio, Visual Studio Code and JetBrains Rider) for each endpoint.
You should never fully trust any AI-generated code. Run the application, test the endpoints manually, and verify the database queries.
AI catches patterns, but humans catch business logic errors.
The frontend needs its own specification, separate from the backend.
I call this a Product Document Requirement (PDR). The PDR references the backend API and includes everything a frontend developer needs to build the UI.
Here is the prompt I use to generate the PDR:
markdownBased on the implemented backend, create a Frontend Product Document Requirement (PDR) as a Markdown file. The PDR must include: 1. Authentication Flow - Login page: POST /api/users/login request/response - Store JWT token, call GetMe after login - Refresh token flow: intercept 401 responses, call POST /api/users/refresh, retry original request - Logout: clear tokens and redirect to login 2. For Each Page - API endpoints it calls with an exact JSON request and response examples - UI layout: which fields to display, form inputs, table columns - Actions: create, update, delete buttons with their API calls - Validation rules matching backend validators - Error handling: how to display API errors to the user 3. Conditional Rendering - Read authorization policies from @file:UserPolicyConstants.cs - Show/hide action buttons based on HATEOAS links in API responses - Show/hide pages in navigation based on user claims 4. Paging - How to call paginated endpoints - Request parameters (page, pageSize) - Response shape (items, totalCount, totalPages) - UI: page controls, page size selector Include complete JSON examples for every request and response so the frontend implementation requires zero guessing about the API contract.
Notice the @file:UserPolicyConstants.cs reference.
This tells Claude to read the actual backend policy constants and use the exact claim names in the PDR.
The generated PDR should be so good that a real front-end developer can implement UI without any additional questions. And the same goes with Claude code.
The PDR bridges backend and frontend by including the exact JSON shapes for every endpoint.
Create a separate CLAUDE.md for the frontend.
Here is a concise frontend CLAUDE.md example:
markdownundefined
This is enough for Claude to generate a consistent frontend structure. The PDR provides the implementation details; the CLAUDE.md provides the conventions.
Just like the backend, the frontend prompt is short when CLAUDE.md and the PDR are already in place.
Claude knows your tech stack and conventions from CLAUDE.md. It knows every page, endpoint, and JSON shape from the PDR. The prompt just connects them.
Here is the prompt:
markdownYou are a Principal Developer producing code of exceptional quality, following Clean Code principles. Your code is a pleasure to read, maintain and work with. Read the PDR file and implement a professional, production-ready UI. Follow the frontend CLAUDE.md for tech stack and conventions. UI requirements: - Clean, professional design with ###### as accent color - Rounded borders on all interactive elements - Responsive layout for desktop, tablet, mobile - Loading states for all API calls - Error messages displayed inline near the relevant fields - Follow the attached screenshots for UI mockups
The prompt focuses only on what CLAUDE.md and the PDR do not cover: visual design preferences. Everything else - pages to build, API calls to make, conditional rendering rules, paging behavior - is already in the PDR.
For an existing project with established UI components, make the prompt even shorter and add @file references to existing pages:
markdownRead the PDR file and implement the remaining features. Follow the patterns in @file:UsersPage.tsx and @file:LoginPage.tsx.
This is the power of the specification-first approach: each step builds on the previous one. By the time you reach the frontend implementation, most decisions are already made and documented.
P.S. If you use Claude, you can connect a Figma MCP and let your AI talk to Figma and generate the UI code with better quality.
With the backend and frontend working, the next step is to automate deployment.
Here is the prompt I use for generating CI/CD pipelines:
markdownCreate a GitHub Actions CI/CD pipeline for this project. The pipeline should: 1. Trigger on push to main and pull requests 2. Backend (.NET): - Restore, build, and run all the tests - Build Docker image - Push to private GitHub container registry 3. Frontend (React): - Install dependencies - Run linter and tests - Build production bundle 4. Deploy to [your target environment] Use separate jobs for backend and frontend so they run in parallel. Cache NuGet packages and npm modules for faster builds. Use environment variables for secrets (never hard-code them).
Adjust the deployment target to match your infrastructure. Whether it is Azure App Service, AWS ECS, a Kubernetes cluster, or a simple VPS with Docker Compose, the prompt should specify the exact target.
This final step is entirely human.
Run the application end to end. Test every user flow manually. Click through the UI. Call every API endpoint. Verify that error messages make sense. Check that authorization works correctly for different user roles.
Review the generated code yourself. Read through the handlers, validators, and endpoints. Look for business logic errors that the AI might have missed. AI is excellent at following patterns, but it does not understand your business domain as well as you do.
Test edge cases. What happens when you submit an empty form? What happens when two users edit the same record simultaneously? What happens when the database is down?
When you find issues, go back to Claude with specific feedback. Reference the actual file and line:
markdownIn CreateOrder.Handler.cs, the handler does not check if the customer exists before creating the order. Add a check that returns Error.NotFound if the customer ID is invalid.
Specific feedback produces specific fixes. "The order creation is broken" produces confusion.
P.S.: You can also use AI to help you create test cases for automated and manual testing. Often, AI creates a more detailed set of tests than a human. But it can't reason the same way as a human, and doesn't know all the nuances and details. Always review the AI-generated tests, add and refine them as needed.
After using this workflow on multiple projects, I distilled the following principles:
1. Specificity beats cleverness. A 30-line prompt with explicit instructions produces better code than a 3-line prompt with a clever framing. Tell Claude exactly what files to create, what patterns to follow, and what conventions to use.
2. Reference existing code with @file. This is the single most impactful technique. Instead of describing your patterns in words, point to actual code files. Claude reads them and follows the same style.
3. Separate planning from coding. Never ask Claude to design the architecture and write the code in the same prompt. The planning steps (1-4) produce specification documents. The coding steps (5, 8) consume those documents. This separation keeps each step focused.
4. Use specifications as contracts. The Markdown specification file is a contract between you and Claude. If the generated code does not match the spec, that is a specific, fixable problem. Without a spec, you have no way to evaluate whether the output is correct.
5. Review in phases. When reviewing generated code, focus on one aspect at a time: first code quality, then performance, then security. Each phase reveals issues the others miss.
6. The human is the architect. Claude proposes, you decide. Never accept an architecture recommendation without understanding why it was suggested and whether it fits your constraints. Challenge every proposal.
7. Iterate, do not rewrite. When Claude generates code with issues, fix the issues. Do not throw everything away and start over. The generated code usually has the right structure. The problems are in the details.
The biggest mistake I made when I started this workflow was asking Claude to plan and code in a single prompt. The output was mediocre because Claude was trying to make too many decisions at once. Splitting into separate steps, each building on the previous one, was the change that made everything click.
This workflow is, in principle, tool-agnostic, but I use Claude Code with Opus 4.7 for a reason.
Code quality. Opus produces clean, well-structured code that follows conventions consistently. It understands the relationships between the backend and the frontend, so complex refactorings do not break dependencies across layers.
Deep reasoning. Through Extended Thinking and Plan Mode, Opus reasons through trade-offs and edge cases before writing code. This matters most during architecture design (Step 3) and specification generation (Step 4), where bad decisions are expensive to fix later.
Large context window. With 1M tokens of context, Opus can hold your entire CLAUDE.MD, specification file, and hundreds of file references at once. It sees the full picture instead of working with fragments.
I use Claude Opus for planning, main implementation, code reviews, creating test cases, and generating specifications. I use Claude Sonnet for smaller iterations, writing tests, and quick fixes where deep reasoning is not required.
Claude Code plans (April, 2026):
Alternative: Codex Agent. OpenAI's Coding Agent that works with OpenAI models. It follows a similar pattern of reading your codebase and generating code. If you are already invested in the OpenAI ecosystem, Codex CLI is worth exploring.
Based on my experience, Claude produces code with much higher quality than Codex. Claude is a bit faster, with better reasoning and a bigger context window.
The workflow I described in this post applies regardless of which tool you choose. The principles - specifications before code, @file references, structured prompts - work with any AI coding assistant.
This workflow works because it mirrors how experienced developers already think. AI does not change the process. It accelerates every step within it.
P.S.: Before starting a new project, read this article on how to start a new .NET project with a proper base from day one.
Did you like this article on using AI? Would you like me to write more or less content on AI topics? Respond to this email with your thoughts. I read every response.
Hope you find this newsletter useful. See you next time.
Whenever you're ready, here's how I can help you:
The .NET Senior Playbook β 800+ real-world interview questions with expert answers across 50 chapters. You try to answer each question first, then reveal the full solution β and a test after every chapter proves it actually stuck. Finish, and you earn a verifiable certificate for your LinkedIn.

Join my community of 25,000+ developers and architects.
Each week you will get 1 practical tip with best practices and real-world examples.
Learn how to craft better software with source code available for my newsletter.