AI-Assisted Greenfield Software Development, Part 4: Architecture Prompts and Instructions

by John Miller | First published: February 2, 2026 - Last Updated: February 11, 2026

This is the fourth post in the series on AI-assisted greenfield software development. If you're joining mid-stream, you may want to begin with Part 1: Business Requirements, where I established the foundation for an AI‑driven development workflow. Part 2 and Part 3 expanded that foundation with scaffolding, project‑level instructions, and Git workflow guidance.

In this post, I'll shift from project-level instructions to architecture-level instructions. This is where I'll define the structural rules that guide AI agents as they generate code—ensuring consistency, correctness, and architectural integrity across the entire solution.

Why Architecture Instruction Files Matter

When humans build software, architecture is often implicit; shared understanding, tribal knowledge, and experience fill in the gaps. AI doesn't have that luxury. Without explicit architectural rules, AI agents tend to optimize for convenience rather than coherence.

Architecture instruction files solve this by providing:

  • A clear architectural pattern
  • Implementation rules and constraints
  • Folder and feature structure
  • Cross‑cutting concerns
  • Anti‑patterns to avoid
  • Testing expectations
  • Success criteria for generated code

These files become the “rails” that keep AI‑generated code aligned with the intended system design.

To begin, I'll focus on one of the most widely used architectural patterns in modern back-end systems: CQRS. I've chosen CQRS because it is not a trivial architecture and is a good test of AI's ability to create architectural instructions and implement them in accordance with those instructions.

What Is CQRS?

The CQRS (Command Query Responsibility Segregation) architectural pattern separates read operations (queries) from write operations (commands). Instead of a single model handling everything, CQRS splits responsibilities so each side can be optimized independently.

Core Principle

Traditional CRUD applications use a single model to handle both read and write operations. CQRS separates these concerns by introducing two distinct models: one dedicated to commands (writes) and another focused on queries (reads).

  • Commands - A command is responsible for modifying the system's state and carrying out the necessary business logic to make that change meaningful. Its job ends there—it does not return any domain-level data, only an acknowledgment that the operation completed. Command examples are CreateOrderCommand and ChangePasswordCommand.

  • Queries - A query's sole responsibility is to retrieve information from the system. It provides data back to the caller but never alters the application state or triggers any side effects.

Key Benefits

CQRS makes it possible to scale the read and write sides of the system independently, allowing each to grow according to its own demands. Because the two responsibilities are separated, each side can use models tailored to its specific purpose, with the read side often taking advantage of denormalized structures to maximize performance. This separation also creates cleaner security boundaries, making it easier to control who can read or modify data. Since the two sides operate independently, each can use the storage technology best suited to its workload, which gives the architecture far more flexibility.

Common Implementation Pattern

Write operations trigger events that update read models. This creates an eventually consistent system—an intentional tradeoff that unlocks performance and scalability.

When CQRS Is a Good Fit

CQRS is especially effective in environments where read operations vastly outnumber writes, allowing the system to optimize each side independently. It also shines in domains with intricate business rules, where separating commands and queries helps keep complexity manageable. Architectures built around event sourcing benefit naturally from CQRS, as do multi‑tenant applications that must serve diverse read patterns. And in systems where auditability is essential, the clear separation of responsibilities makes tracking and verifying changes far more straightforward.

When to Avoid It

If your application is simple CRUD, CQRS adds complexity without meaningful benefit.

Creating the Architecture Prompt File

Prior to creating CQRS instructions, I created a prompt file to guide the creation of the instructions. By asking Copilot to create a prompt file, you give Copilot a chance to add relevant context, which improves the prompt, which in turn will improve the instructions generated by the prompt.

When generating GitHub AI guidance, I used the custom prompt-engineer.chatmode.md chat mode, introduced in Part 2, which focuses Copilot on the skills needed to generate effective prompts.

When working with GitHub AI guidance, there is always a chicken-and-egg problem. For Copilot to generate an artifact, you need a prompt. In this case, we want Copilot to generate a prompt file. We could create a prompt file that would generate the prompt file we need to generate the instruction file. This is a recursive process with diminishing returns. At some point, we'd need to manually prompt Copilot to bootstrap the artifact generation.

Here is the manual prompt I used to generate the prompt file: Create a prompt file that generates instruction files for a CQRS architecture. The prompt file should target AI agents and be optimized to reduce token consumption.

By asking Copilot to generate a prompt file, Copilot will use the ai-assisted-output.instructions.md and the prompt-file-generation.instructions.md to guide the generation of the prompt file. This ensures the prompt file conforms to the AI output instructions and the instructions for generating prompts.

All of this meta guidance (prompts that generate prompts which create instructions that govern the generation of code) can get confusing. Take a close look at the files I've referenced in this post and have Copilot explain anything you don't quite understand.

Understanding the generate-cqrs-eventsourcing-instructions.prompt.md Prompt File

The generate-cqrs-eventsourcing-instructions.prompt.md prompt file instructs an AI agent to generate a complete instruction file for implementing CQRS with event-sourcing patterns in a specific programming language and technology stack. The agent takes four parameters, the programming language, mediator framework, event store implementation, and projection strategy, and produces a comprehensive .instructions.md file that will guide future AI-assisted code generation.

The instruction file content follows a rigid 15-section structure. The agent begins with a brief overview, then creates a reference table that defines core concepts such as events, aggregates, event stores, projections, and snapshots. It documents three main implementation patterns: command handling with event-sourced aggregates, event store operations for writing and reading event streams, and query handling using projections rather than direct event store access.

For each pattern, the agent provides structure tables showing components, their purposes, and file locations, followed by implementation rules written as imperative directives. It includes minimal code templates demonstrating aggregate event application, command handlers that append events with optimistic concurrency, and projection subscribers that update read models. The agent specifies snapshot strategies for performance optimization when aggregates accumulate many events, and documents the chosen projection approach (inline, background worker, or separate service).

Additional sections cover event schema design with versioning strategies, aggregate reconstruction patterns, idempotency handling, anti-patterns to avoid, event schema evolution techniques using upcasters, and testing approaches. The agent concludes with a validation checklist ensuring all critical patterns are documented.

Creating the Architecture Instruction File

With the prompt file in place, I generated a concrete instruction file. Using the prompt:

Submit the prompt generate-cqrs-eventsourcing-instructions.prompt.md in the C# language, the MediatR framework, the EventStoreDB event_store and inline projections.

This generates an instruction that directs an AI agent executing the prompt to generate C# code that strictly separates command-handling from query-handling, using MediatR for mediation and EventStoreDB for persistence. When creating commands, agents must structure them so handlers validate inputs, load aggregates by replaying events, execute domain logic that returns new events without mutating state, and append those events using optimistic concurrency checks. Agents are instructed to never allow aggregates to directly modify their internal state; instead, all state changes must flow through Apply() methods that process events.

For queries, agents must create handlers that read exclusively from denormalized read models stored in a separate database schema, never directly accessing the event store. The file mandates inline projections that update read models synchronously within the same transaction as event appends, ensuring immediate consistency. Agents must implement projection classes with event handler methods that transform events into read model updates.

When building aggregates, agents are directed to implement Apply() methods for rebuilding state from event streams and command methods that validate business rules and then yield new events. The file prohibits direct property setters and requires immutable event types, preferably using C# records. Agents must name event streams following the “{aggregate}-{id}” pattern and include full metadata with each event.

For performance optimization, agents are instructed to implement snapshot stores that cache aggregate state when streams exceed 50-100 events, loading aggregates from the latest snapshot plus subsequent events rather than replaying entire streams. The file directs agents to handle event versioning through upcaster classes that transform old event formats during reads.

Agents must implement idempotency through MediatR pipeline behaviors that track command identifiers and prevent duplicate processing. Testing code should follow Given-When-Then patterns, verifying events produced by commands, reading model updates from projections, and state transitions in aggregates.

The instruction file explicitly prohibits several patterns: querying event stores for reads, mutating aggregate state outside event application, deleting events, sharing events between aggregates, and loading multiple aggregates in command handlers. It enforces a strict project structure, segregating commands, queries, projections, aggregates, events, and infrastructure concerns into designated directories.

Throughout, agents are directed to use MediatR's IRequestHandler interface for all command and query handlers, EventStoreDB's AppendAsync with ExpectedVersion for writes, and dedicated read database contexts for queries. The file provides code templates showing exactly how to structure each component, ensuring agents generate consistent, pattern-compliant implementations.

At this point, the AI has:

  • Business requirements
  • Project-level instructions
  • Architecture-level instructions

To complete the foundation, we need technology-specific instructions and project implementation guidance.

Checking the Context

Before moving on, it's a good idea to review the .github governance (prompts, instructions, etc.) to ensure there isn't conflicting governance that could confuse Copilot. In Part 2, I introduced the check-context.prompt.md file that examines the current context and reports any anomalies that should be addressed.

The prompt checks for:

  • Conflicting instructions
  • Factual inconsistencies
  • Logical contradictions
  • Scope/priority conflicts
  • Technical incompatibilities
  • Communication gaps
  • Duplication/redundancy

This is a prompt that should be submitted any time the .github governance changes. Copilot didn't find any issues to address, so we are good to proceed.

What's Next?

In Part 5, I'll add instruction files for the technologies we're implementing. These instructions will guide Copilot in the details for implementing specific technologies. That post will cover naming conventions, patterns, namespaces, standards, and templates for implementing the classes that will be implemented.

If you'd like to explore the files or follow along with your own implementation, everything is available in the Academia GitHub repository. Fork it, experiment with it, and adapt it to your own workflow.

Feedback Loop

Feedback is always welcome. Send your thoughts to john.miller@codemag.com.


Disclaimer

AI contributed to the writing of this post, but humans reviewed, refined, and enhanced it, giving it soul.

Prompts:

  • Rephrase these points as prose:
    • Traditional: In a typical CRUD application, one model handles both reads and writes.
    • CQRS: With CQRS, there are two models—one for commands, one for queries.
  • Summarize generate-csharp-implementation-instructions.prompt.md in prose. Don't explain CQRS or event sourcing. Describe what the file instructs an AI agent to do.
  • Summarize generate-cqrs-eventsourcing-instructions.prompt.md in prose. Don't explain CQRS or event sourcing. Describe what the file instructs an AI agent to do.
  • Write a paragraph defining event sourcing.
  • Explain the CQRS architecture pattern.