← Home

The 4A Pattern: Stop Vibe Coding. Start AI Engineering.

· 15 min read

In this article I’ll be covering an AI engineering pattern that I’ve had success with building a high-quality SaaS MVP with no manual coding.

This is an approach intended for solo-devs, or as I’ll go onto elaborate, solo-engs. It’s especially good for green-field projects. It uses traditional engineering concepts, and emphasises their importance in the age of AI.

Although this pattern create good quality software to be managed one-person, it doesn't mean that I believe all software should or will. Quite the contrary - I believe that code is but one fragment of well-engineered software and high-functioning teams.

Before I begin, I would like to take pause to reflect and understand the difference between software development and software engineering. The lines were blurred for a long time, as were job specs - many of us often wore both hats - but it matters more than ever to think about the separation of those roles.

Developing software is writing the code for a system to create functionality that meets a spec. Engineering is thinking about and building whole systems, and defining the specs for new code that needs to be written.

Vibe Coding vs Software Engineering

Many vibe coders and early experimenters of AI development - who may have lets say, an enhanced imagination of what AI is capable of - will type their idea into a chat window, and get something back.

I’m not arguing how impressive this is - it’s truly revolutionary tech - but AI will fill in so many gaps. It’ll make assumptions about your idea, your features, and the system architecture behind it.

Once it’s created what you’ve asked for, it’ll stop, and wait - it won’t think ahead several months or years into where you want to go with it. It quickly forgets long term vision. It won’t think about how this feature breaks another. It’s difficult to deploy at any sort of scale beyond 1 user.

This is unbridled, chaotic software development in its purest form.

Software Engineering - it’s the opposite of this. It’s about designing systems that keep working, and anticipating how code will be maintained, and scaled. It’s about bringing accountability to decisions and tradeoffs. It's managing complexity, instead of building hidden technical debt.

Vibe coding is great for prototypes, and for personal mini-apps. But for deployment at scale, we must take a different approach.

By spending more time on process and good-quality inputs we sacrifice some of the vibe coding velocity (a small project may take a couple weeks instead of a few hours) but gain long term stability. Good process and plans will allow you to go beyond the MVP through intentional engineering.

AI Engineering with the 4A Pattern

To bridge this gap between vibe coding and software engineering, whilst still taking advantage of generative AI, I propose this 4A pattern:

  1. Atomic Context (one unit of work)
  1. Artifacts (the engineering specs)
  1. Agile Workflow (the process)
  1. Agentic Roles (the team/swarm)

Similar patterns are now emerging in CLI tools and frontier LLM providers. I prefer this specific implementation for a few reasons;

  • It uses familiar concepts, and is straightforward to understand. It should be easy for new team members to pick up and run with
  • It’s local-first, non-proprietary, literally just folders and filenames. It’s all self-contained, within your project folder, persistent and version-controlled. You can switch between LLM providers at any point.
  • You maintain complete control and oversight over your process, including project direction, priorities, and compromises and importantly, understanding.

The importance of LLM Memory Management

LLMs are stateless, meaning they have no memory of recent sessions and interactions. The aim of this pattern is deliberate memory management.

Each ‘A’ in the 4A pattern serves a different purpose, for a different type of memory management.

  • Atomic Context is the short term memory - what the Agent is working on right now
  • Artifacts are the long term memory. The product requirements, architectural decisions and constraint
  • Agile is the medium term memory - how we’re getting on between sessions and between agents. What we’re working on as a collective, and our medium-term goals.
  • Agentic Roles have expertise-specific memories, preferences, and a log of past mistakes

1. Atomic Context - The short term memory

The context window is every bit of information that is loaded into the AI model during an interactive session.

Whether you’re doing simple prompts or full-on engineering, what you load into your context window is one of the biggest determining factors on the quality of your output. This is one of the most important things to understand about using LLMs, period.

Your AI code terminal may add bits of context itself - like tools, system instructions, mcp servers - but other than those, when you start a new session, the context window is pretty much clean.

The aim is to keep it clean and keep it focused. The less distractions you load in, the more relevant material you give up front, the better the quality of your plan - the cleaner the decision making will be, the easier the LLM will stay on track and under instruction, and the more clean and clear the output will be.

By reducing wrong turns, hallucinations and refactors, goals will be achieved faster, and overall less tokens will be spent getting there.

And conversely - if you load up the context with long term goals, and switching from task to task, trying to achieve everything all at once - you will end, frankly, with a pile of slop.

By offloading memory to Artifacts and project management to the Agile workflow, we can focus the Agent’s short-term memory, the Context Window, on a single, atomic action, and hopefully get a much cleaner output.

Ultimately, having a single-minded, focused, atomic context is what we are trying to achieve with this entire workflow.

Atomic Context:
One Chat Session = One Task + One Role

During an Agent role’s handling of a task, it should be creating Artifacts, to help the next role along.

And importantly - once the role’s task is complete and the file is handed over to the next role, we close and wipe the context, and start again.

2. Artifacts - The long term memory

A key difference between software developing and engineering - is writing things down.

Coders jump straight in and start coding. Engineers plan, make decisions, and create specs.

These plans, decisions and specs are known as Artifacts. They’re living documents that contain actionable, specific decisions.

By taking an intentional and determined approach of treating our project’s development artifacts as first-class citizens, these Artifacts also become the AI’s long term memory.

In this workflow, we don’t just ask the AI to “build a login page”. We ask it to create the Architecture Decision Record, Acceptance Criteria, and the API Contract, all before any code gets written.

We document:

  • Product Requirement Docs.
    Describes the bigger picture of what we are building. Defining purpose, user flows, features and functionality, things like target audiences and user flows and success metrics.
  • Architecture
    The architectural decisions behind features and functionality; the system structure, schemas, data flows and third party integrations
  • Criteria (Acceptance Criteria or Functional Specs)
    The considerations for a feature set. What APIs need to be built, frontend, crons, user flows, states and constraints, and any edge cases.
    (Written by UX + QA roles)
  • Contracts (interfaces, api docs)
    Describing the code that needs to be built to satisfy the criteria.
    (Written by Frontend and Backend Roles)
  • Runbooks
    How to deploy things; the instructions for CI/CD and different environments (eg development, staging, production) and release ceremonies
  • Releases
    The notes following a full release; changelogs for both the product and the process.

Depending on your needs, you may wish to document less, or more - such as decision logs, risk registers, project roadmap, incidents. You may also find yourself ‘refactoring’ documentation as time goes on, or adding new sections as their needs become apparent. That’s part of your role as the Engineer.

The folder structure:

    .agents/
    └── artifacts/
    ├── architecture/
    ├── contracts/
    ├── criteria/
    ├── prds/
    ├── releases/
    └── runbooks/

These artifacts will be written and handed-off between agents, and quality-controlled by you. It forces them, and you, to think about the wider context before the code is written.

Now, we need the Agents to know which task to work on next. We manage these priorities with processs, in the Agile workflow.

3. Agile Workflow - The medium-term memory

Software veterans know this pattern well. It allows for managed, phased development. It is flexible enough to adapt to the realities of blockers, unforeseen changes and imbalances.

Plan → Design → Develop → Test → Deploy → Review

Vibe coding skips straight to Develop. Engineering respects the entire lifecycle.

Keeping to to the local-first principle, we can create a folder-based kanban board to manage our Agile workflow:

    .agents/
    ├── inbox/
    ├── backlog/
    │ ├── features/
    │ ├── tech-debt/
    │ └── bugs/
    └── sprints/current/
                ├── todo/
                ├── in-progress/
                ├── test/
                └── done/
                        

The folder naming conventions should reflect familiar concepts to you:

  • The backlog is your long-term task list, containing features and bugs, and refactors
  • The inbox is a place for you to log ideas that aren’t fully formed or broken into tasks - raw dumps and brainstorms to make into future PRDs and tasks.
  • The sprints, a commitment to a specific set of tasks

Tasks will be broken down and saved as markdown files within within our sprints’ todo folder.

As established in the Atomic Context principle, we assign exactly one role to one task. We do this by filenames: tasks will be given a prefix to indicate which role should be working on it next.

sprints/current/todo/FD-003-login-form.md # FD- indicates frontend developer
sprints/current/todo/BE-004-login-api.md # BE- indicates backend engineer
                        

This imposes a process and keeps order to the software development lifecycle.

The file management itself will be handled by our Agentic Roles.

4. Agentic Roles - The seperation of concerns

“Agent” comes from the word Agency; the ability to make decisions and act independently.

In engineering teams, having separate roles is the way to acheive a Separation of Concerns.

Picture your Agent Roles as dream-team of software specialists. Each Agent Role will live in one or more markdown files, explaining its purpose, preferences, and goals.

Some goals will actually be pretty similar between the roles. We want every role to to:

  • Pick up the next task that’s relevant to it’s role
  • Manage the task lifecycle, by cycling the task file through the sprint folders and handing them off to other roles
  • Escalate certain decisions to humans (ie. you)
  • Self-Learn - especially logging mistakes, but key decisions too - super important! The Agent must write its mistake into a text file, which is manually re-fed into future contexts.
  • Document everything it does along the way, as artifacts

Other goals will be highly domain-specific, and personal to each role.

Before we define each role, here’s the last of the proposed folders:

    .agents/
        ├── role/
        ├── learnings/
        ├── command/
        ├── templates/
        └── role-core.md
    

A role will typically have one or more files in each folder.

  • Role/[role-name.md]
    The role file contains information about each role’s goals, responsibilities, preferences, and documentation guidelines. You can also reference relevant skills (superpowers for your role!) and when to invoke them, and even nudge towards MCP servers.
  • Learnings/[role.md]
    Each role will have exactly one learnings file. These The purpose of this file is for the AI to log mistakes and learnings whenever it wastes tokens. The role will read the learnings when invoked, preventing it from creating the mistakes over and over again. This is critical memory management for the roles, and hence why they are graduated into their own file.
  • Templates/[documentation-template.md]
    These templates are to help the role create good-quality artifacts as it builds. Not every role will need to document, and some roles will need multiple templates. Some templates will be shared between roles.
  • Commands/[role-invocation.md]
    These are commands to be invoked by the user (human) - effectively shortcuts to invoke a role and call a task. For example, starting a new task or reporting a bug. *Not every role will have a command
  • role-core.md
    Common instructions across all roles - how to manage sprints/tasks, how to escalate to a human, how to manage learnings, how to document changes, and how to hand-off to the next role.

The handoff process defined in role-core, instructs the agent to progress tasks along to the next team member or development stage.

It’ll do this by editing the task filename, or moving it to the test folder:

    FD-003-login-form.md # Ready for Frontend Developer
    FD-003-login-form--handoff-CR.md # FE task Ready for code review role
                        

Mapping Roles to Agile Workflow

The 4A pattern I’ve been describing is intentionally open, customisable and flexible.

You may decide that for your project you need more roles, less roles, or different roles entirely. A project for an indie game may look completely different to an iOS native app. Even if the broad roles seem the same, the specifics will be very different.

At a bare minimum, you’ll want to ensure your Agile workflow is covered off for each task, by each role.

Plan → Design → Develop → Test → Deploy → Review

For a smaller project and for getting to MVP you could get going with these key roles:

  • Product Owner.
    Contains the responsibilities of the product manager (managing backlog), engineering manager (creating sprints and assigning task), UX designer (defining user flows)
  • Architect
    Contains the responsibilities of the technical architect (system decisions, schema design, contract writing)
  • Builder
    Contains the responsibilities of the frontend developer (developing frontend code), backend engineer (developing APIs)
  • Reviewer
    Contains the responsibilities of the QA (writing acceptance criteria, writing tests), the Code Reviewer (checking code for accuracy to criteria/contracts), considering updating Artifacts, Security auditing.

As you scale, you might want to consider breaking these roles down further. For example - individual roles for each of the Product Manager, Engineering Manager, Technical Architect, UX Designer, UI Designer, QA Tester, Frontend Developer, Backend Engineer, Code Reviewer, DevOps.

And at the end of each sprint or release is a great time to take stock, review and iterate on your roles.

Tying it all together

Once we have the Artifacts, Agile Structure, Agentic Roles defined - we can initialise our task within an Atomic Context.

Open your LLM CLI of choice, pick a task and pick a role

The prompt:

    > @.agents/role/frontend-developer.md @.agents/sprints/current/todo/FE-build-user-login.md
                        

The agents working together, one context at a time, may look like this:

  1. PM creates FE-001 in todo/
  2. FE picks up, implements, renames to FE-001--handoff-CR
  3. CR reviews, approves, moves to test/ (deploys to staging)
  4. QA tests on staging, moves to done/
  5. DevOps batches with other done/ tasks for production release
    todo/ → [Dev] → in-progress/ → [CR] → test/ → [QA] → done/
                        ↑                    ↓
                        └────────────────────┘
                            (bugs found)
                        

The handoff process - renaming files and moving tasks between folders - is fully handled by the Agents, instructed by the role-core.md file.

The New Engineer

Congratulations, you’re now software engineering and architecting with a swarm of AI coders.

There’s a lot happening, and there’s hard work afoot. You still have plenty to keep on top of. But as long as you keep maintaining the input, you’ll end up with better quality software, faster.

You have the most important role of them all. The role of ownership.

Collaborating on PRDs, features, logging bugs

It’s important to convey your vision within good plans and features, after all - this is your product you are building. You need to understand the problems it’s solving and the real-life users that interact with it. There's a new belief that product is the new bottleneck of software creation, and there's some truth to that.

Architecture and tech stack decisions

You know your tolerance for cost, your necessity to scale, your priorities when it comes to the choices of libraries and frameworks. If you don’t make these decisions early and often, the AI will make the decisions for you. You may end up with higher-than-necessary server costs, API integrations, or unnecessary slow frontend libraries. You should also pick tech stacks that you are either familiar with or open to learning, as you will need to check the output.

Checking the output

This method relies on creating artifacts as output which often become the input for the next task. Ensuring these artifacts remain high quality, focused and free of hallucination is an important role to ensure the continued quality of the output.

And of course, importantly, the code that is output should also be screened by your human eyes. As with all software, some bugs will leak through, but you want to ensure the overall code that is being generated is logical, clean and succinct.

If your model is consistently creating bad quality artifacts or code - which at some point, it will - you will want to improve your roles.

Building & improving the roles

When you first build out the roles, spend considerable time defining each role before you invoke them for the first time. Use an LLM to help, but fully research understand the decisions you make on tech stacks and toolings for your project, as it’s costly to significantly alter paths later down the line.

An often overlooked but important thing to monitor is your model’s “thinking”. This can give you key insights into overthinking, strange paths, difficulties its facing. Use the thinking to help improve your role files, to help overall token usage.

Monitoring and management, pruning learnings

You’ll occasionally need to nudge your LLM along - just because you have instructed it to do something in the role file, like handoff to the next agent, doesn’t mean it’ll do it.

Be mindful of learnings and artifacts becoming too verbose; you’ll want to occasionally ‘refactor’ or prune these down to keep them high-value (and low-tokens).

Engineering is foresight

Vibe coding is churning out something now. Engineering is thinking about the future.

Software developing, ‘just coding’, died last year. But thankfully writing good software has always been about more than ‘just coding’, it is an exercise in foresight.

It is the discipline of anticipating how code will be read, maintained, and scaled months down the line, long after the original context is forgotten.

True value isn’t found in the speed of the initial build - it’s found in the reliability of the overall system that endures. To achieve lasting quality, it means moving beyond that temporary high of a working prototype, and committing to an architectural rigor - ensuring what’s been built today doesn’t become unmanageable debt tomorrow.

In an era where functionality can be generated in seconds, the value proposition of a software engineer shifts its weight from syntax, to structure, and future-thinking.

Stop coding. Start engineering.