{"slug": "from-epic-to-merge-an-end-to-end-workflow-for-software-development-with-ai", "title": "From Epic to Merge: An End-to-End Workflow for Software Development with AI Agents", "summary": "A developer has proposed an end-to-end workflow for implementing a software Epic using AI agents, structuring work as a task dependency graph where each task passes through Planner, Builder, and Reviewer stages before converging into an Epic integration PR gated by CI and human approval. The approach treats the Epic as a central source of intent, requirements, and constraints rather than an absolute source of truth, leaving the repository as the technical reality agents must reconcile against. The workflow aims to minimize human intervention while retaining controls proportional to the risk of autonomous changes.", "body_md": "Coding agents are becoming increasingly capable of implementing individual software tasks. Give an agent a repository, a clear issue, and enough context, and it can often inspect the codebase, modify files, write tests, and produce a working implementation.\n\nThe harder problem starts one level above that.\n\nWhat happens when we need to implement an entire feature consisting of ten related tasks? Some can run in parallel, some depend on others, some require architectural decisions, and some touch areas where autonomous changes should not be allowed.\n\nAt that point, the challenge is no longer simply:\n\nCan an AI agent write the code?\n\nThe more useful question becomes:\n\nHow do we transform a software initiative into units of work that agents can execute, validate, review, and integrate safely?\n\nThis article proposes an end-to-end workflow for implementing an Epic using AI agents while minimizing human intervention without removing the controls required by the risk of the changes.\n\nThe core architecture looks like this:\n\n```\n                         ┌─────────────────────┐\n                         │        Epic         │\n                         │ intent + constraints│\n                         └──────────┬──────────┘\n                                    │\n                                    ▼\n                         ┌─────────────────────┐\n                         │   Task dependency   │\n                         │        graph        │\n                         └──────────┬──────────┘\n                                    │\n                    ┌───────────────┴───────────────┐\n                    │                               │\n                    ▼                               ▼\n            ┌──────────────┐                ┌──────────────┐\n            │    Task A    │                │    Task B    │\n            └──────┬───────┘                └──────┬───────┘\n                   │                               │\n                   ▼                               ▼\n              ┌─────────┐                     ┌─────────┐\n              │ Planner │                     │ Planner │\n              └────┬────┘                     └────┬────┘\n                   │                               │\n                   ▼                               ▼\n              ┌─────────┐                     ┌─────────┐\n              │ Builder │                     │ Builder │\n              └────┬────┘                     └────┬────┘\n                   │                               │\n                   ▼                               ▼\n              ┌─────────┐                     ┌─────────┐\n              │Reviewer │                     │Reviewer │\n              └────┬────┘                     └────┬────┘\n                   │                               │\n                   └───────────────┬───────────────┘\n                                   ▼\n                         ┌─────────────────────┐\n                         │ Epic integration PR │\n                         │      + CI           │\n                         └──────────┬──────────┘\n                                    │\n                              human approval\n                                    │\n                                    ▼\n                                  main\n```\n\nThe specific tools are interchangeable. The important part is the workflow.\n\nAn Epic is useful because it gives the agents a shared description of what the system is supposed to accomplish.\n\nIt should contain at least:\n\nI would avoid treating the Epic as the absolute \"source of truth.\"\n\nIt is better understood as the **central source of intent, requirements, and constraints** for the initiative.\n\nThe repository still contains the technical reality of the system. Existing APIs, schemas, architectural decisions, infrastructure, tests, and implementation constraints may reveal information that the Epic does not contain.\n\nThis distinction becomes important once agents start making decisions.\n\nImagine that a task only says:\n\n```\nAdd retry support to payment processing.\n```\n\nAn agent might reasonably ask:\n\nThe task itself may not answer those questions.\n\nThe Epic can provide the product and architectural boundaries required to answer them without duplicating the entire context in every issue.\n\nA practical implementation is to represent the Epic as a parent GitHub Issue and its tasks as sub-issues. This keeps the planning artifacts close to the code and allows issues, pull requests, commits, diagrams, files, and technical decisions to reference each other.\n\nOne of the easiest mistakes when building agentic development workflows is to hand a very large objective directly to a coding agent:\n\n```\nImplement the entire billing Epic.\n```\n\nA sufficiently capable model may still make progress, but the execution becomes difficult to reason about.\n\nThe agent must simultaneously:\n\nThe problem is not simply context-window size.\n\nThe problem is the number of decisions that must remain coherent throughout the execution.\n\nA better workflow reduces the complexity of each execution.\n\nA useful rule is:\n\nA task is sufficiently granular when it represents one coherent delivery, can be implemented and validated independently, and can produce a pull request that can be understood, tested, and reverted without relying on undeclared changes.\n\nTask size should therefore not be measured primarily by lines of code or number of files.\n\nThe more important property is **cohesion**.\n\nFor example, adding a field to an API may require modifying:\n\n```\ndatabase schema\n    ↓\ndomain entity\n    ↓\nservice\n    ↓\nAPI endpoint\n    ↓\ntests\n```\n\nThat can still be one coherent task.\n\nSeveral layers are affected, but they all implement the same vertical capability.\n\nBy contrast, a change touching only three files may still be too broad if it combines:\n\n```\nauthentication\n+ billing rules\n+ event processing\n+ infrastructure changes\n```\n\nThe useful questions are therefore:\n\nThe last question is particularly useful:\n\nCan a reviewer understand and validate this diff as a single logical change?\n\nIf the answer is no, the task probably needs further decomposition.\n\nTasks become especially dangerous when uncertainty and implementation are mixed together.\n\nConsider:\n\n```\nChoose an asynchronous processing architecture and implement it.\n```\n\nThis contains at least two fundamentally different types of work:\n\nA better decomposition could be:\n\n```\nTask 1 — Investigate asynchronous processing alternatives\n\nTask 2 — Record the architectural decision\n\nTask 3 — Implement the event producer\n\nTask 4 — Implement the event consumer\n```\n\nThe first tasks reduce uncertainty.\n\nThe later tasks execute against a decision that already exists.\n\nThis distinction also makes agent behavior easier to control. We can allow an agent to investigate broadly without implicitly granting it permission to modify the architecture.\n\nBefore a task reaches a Builder, the workflow should verify that it is actually ready to be implemented.\n\nA practical checklist is:\n\nThese do not need to become rigid numerical rules.\n\nA 2,000-line generated schema migration may be simpler than a 100-line authentication change.\n\nCohesion, independence, and verifiability matter more than raw size.\n\nOnce tasks can run concurrently, filesystem isolation becomes necessary.\n\nA simple strategy is:\n\n```\nEpic\n│\n├── integration/epic-payments\n│\n├── task/payment-retry\n│   └── worktree A\n│\n├── task/payment-webhook\n│   └── worktree B\n│\n└── task/payment-events\n    └── worktree C\n```\n\nEach Builder receives:\n\nThis prevents two agents from directly modifying the same working directory.\n\nIt does **not**, however, eliminate integration conflicts.\n\nTwo isolated agents can still independently modify the same API, data model, or subsystem. Their worktrees are isolated operationally, but their changes may conflict semantically when integrated.\n\nThe orchestrator must therefore understand task dependencies and integration order.\n\nAn Epic should not be treated as a flat task list.\n\nIt is better represented as a dependency graph.\n\nFor example:\n\n```\n                 ┌───────────────┐\n                 │ Add DB schema │\n                 └───────┬───────┘\n                         │\n               ┌─────────┴─────────┐\n               ▼                   ▼\n      ┌────────────────┐   ┌────────────────┐\n      │ Write producer │   │ Create API     │\n      └───────┬────────┘   └───────┬────────┘\n              │                    │\n              ▼                    │\n      ┌────────────────┐           │\n      │ Write consumer │           │\n      └───────┬────────┘           │\n              └──────────┬─────────┘\n                         ▼\n                ┌────────────────┐\n                │ Integration    │\n                │ validation     │\n                └────────────────┘\n```\n\nA task can then have explicit metadata such as:\n\n```\nid: payment-consumer\nblocked_by:\n  - payment-schema\n  - payment-producer\n```\n\nThe orchestrator can execute independent nodes concurrently while waiting for their dependencies.\n\nThis is significantly safer than telling several agents to work through the Epic and hoping they discover the correct order themselves.\n\nThe workflow uses three main roles.\n\nThe Planner investigates before implementation.\n\nIts responsibilities include:\n\nThe Planner should not modify production files during this phase.\n\nIts output should be an execution plan, not an implementation.\n\nA typical result might look like:\n\n```\nAffected modules:\n- payments/service.ts\n- payments/repository.ts\n- payments/service.test.ts\n\nImplementation:\n1. Add retry classification for transient provider errors.\n2. Add bounded exponential retry behavior.\n3. Preserve idempotency key across attempts.\n4. Add tests for retryable and non-retryable failures.\n\nValidation:\n- unit test suite\n- payment integration tests\n- lint\n- typecheck\n\nRisk:\n- ensure declined payments are never retried\n```\n\nThat output becomes part of the Builder's context.\n\nThe Builder executes the approved task.\n\nIts responsibilities are intentionally narrower:\n\nThe Builder should not silently redefine acceptance criteria or expand scope because it discovered something interesting during implementation.\n\nIf implementation reveals a significant architectural issue, the correct action is usually to escalate the finding back to the orchestrator.\n\nThe Reviewer evaluates the result independently.\n\nIt should inspect:\n\nThe review should be based on the expected behavior, not merely on the Builder's explanation of what it implemented.\n\nThat distinction matters because the Builder and Reviewer may otherwise share the same incorrect assumption.\n\nThe Reviewer should return concrete findings such as:\n\n```\nBLOCKING\n\nRetry logic also retries PaymentDeclinedError.\n\nAcceptance criterion:\nOnly transient provider failures may be retried.\n\npayments/service.ts:87\n```\n\nInstead of:\n\n```\nThe implementation doesn't look quite right.\n```\n\nObjective findings make automated correction loops possible.\n\nThere are two broad ways to coordinate the agents.\n\nA primary agent delegates work through a native multi-agent runtime.\n\nConceptually:\n\n```\nmain agent\n    │\n    ├── planner agent\n    ├── builder agent\n    └── reviewer agent\n```\n\nThe runtime manages the child executions and returns their results to the parent.\n\nThis is useful when delegation is closely tied to the reasoning process of the primary agent.\n\nA separate process controls independent agent executions.\n\n```\norchestrator\n    │\n    ├── agent process -- task A\n    ├── agent process -- task B\n    └── agent process -- review A\n```\n\nThe executions communicate through structured output, files, Git, APIs, or another durable mechanism.\n\nExternal orchestration is particularly useful when we need:\n\nThe architecture described in this article favors external orchestration for the main workflow while still allowing individual agents to use internal subagents when useful.\n\nThe Epic contains global information.\n\nThat does not mean every agent should receive the entire Epic, every previous conversation, and every implementation log.\n\nInstead, the orchestrator should build a **task context package**.\n\n```\nepic:\n  objective: Add asynchronous invoice processing\n  constraints:\n    - existing synchronous API must remain compatible\n\ntask:\n  id: invoice-event-producer\n  objective: Publish an event after invoice creation\n\nacceptance_criteria:\n  - exactly one event is emitted after a successful transaction\n  - failed transactions must not emit events\n\ndependencies:\n  completed:\n    - invoice-event-schema\n\narchitecture:\n  - ADR-014-event-bus.md\n\nrelevant_files:\n  - src/invoices/service.ts\n  - src/events/publisher.ts\n\nvalidation:\n  - npm test -- invoices\n  - npm run typecheck\n\ninstructions:\n  - AGENTS.md\n```\n\nThe pipeline becomes:\n\n```\nEpic\n  ↓\ncontext selection\n  ↓\ntask-specific context\n  ↓\nisolated execution\n  ↓\nvalidated result\n  ↓\nEpic integration\n```\n\nLong context windows are useful, but they should be treated as available capacity rather than a target to fill.\n\nMore context is not automatically better context.\n\nExcessive context can introduce:\n\nContext engineering is therefore part of orchestration.\n\nThe question is not:\n\nHow much information can the model receive?\n\nIt is:\n\nWhat is the minimum sufficient context required to make this decision correctly?\n\nReducing human intervention does not mean giving agents unrestricted permissions.\n\nThe workflow should define which actions are safe to perform automatically and which require approval.\n\nA possible policy is:\n\nAgents may perform these operations inside their isolated task environment:\n\nChanges in this category may proceed automatically only when specific validation rules succeed:\n\nExamples include:\n\nThese categories should not be universal constants.\n\nA migration adding a nullable column may be routine in one system and dangerous in another with billions of rows.\n\nThe correct abstraction is therefore not a hardcoded list of actions.\n\nIt is a **risk policy**.\n\nWe can now put the pieces together.\n\nThe human or product process defines:\n\n```\nobjective\nproblem\nscope\nnon-goals\nrequirements\nacceptance criteria\nrisks\nsuccess metrics\n```\n\nAt this stage, the emphasis is on **what needs to be achieved**, not exactly how every part will be implemented.\n\nA planning process converts the Epic into tasks.\n\nEach task is checked for:\n\n```\ncohesion\nindependence\ntestability\nreversibility\narchitectural uncertainty\n```\n\nIf major design uncertainty exists, investigation tasks are created before implementation tasks.\n\nDependencies between tasks are declared explicitly.\n\n```\nA ──► C ──► E\n│\n└──► D ──► E\n\nB ───────► E\n```\n\nTasks `A` and `B` can begin immediately.\n\n`C` and `D` wait for `A`.\n\n`E` waits for all upstream work.\n\nThe orchestrator now has enough information to determine safe parallelism.\n\nA branch is created from the current target branch:\n\n```\nmain\n  │\n  └── epic/invoice-processing\n```\n\nIndividual task branches are based on an appropriate integration state.\n\nLong-running Epics should periodically synchronize with the target branch to avoid allowing the integration branch to drift too far from `main`.\n\nThe orchestrator selects only the information required for the task:\n\n```\nEpic summary\n+ task description\n+ acceptance criteria\n+ architecture decisions\n+ completed dependencies\n+ relevant files\n+ repository instructions\n+ validation commands\n+ risk constraints\n```\n\nThis becomes the Planner's initial input.\n\nThe Planner inspects the repository and produces a plan.\n\nPossible outcomes are:\n\n```\nREADY\nNEEDS_SPLIT\nBLOCKED_BY_ARCHITECTURE\nBLOCKED_BY_DEPENDENCY\n```\n\nOnly `READY` tasks proceed automatically.\n\nThis step acts as an important boundary between project planning and code generation.\n\nThe orchestrator creates:\n\n```\ntask branch\n+\nGit worktree or container\n+\ntask-specific context\nworktrees/\n├── payment-retry/\n├── payment-webhook/\n└── invoice-events/\n```\n\nIndependent Builders can now execute concurrently without sharing the same filesystem.\n\nThe Builder receives:\n\n```\ntask context\n+\nPlanner result\n+\nrepository instructions\n```\n\nIt implements the change and runs the required validations.\n\nThe result should include structured information such as:\n\n```\nstatus: completed\n\ncommit: a814ed3\n\nvalidation:\n  unit_tests: passed\n  integration_tests: passed\n  lint: passed\n  typecheck: passed\n\nfiles_changed:\n  - src/payments/service.ts\n  - src/payments/service.test.ts\n\nnotes:\n  - preserved existing idempotency behavior\n```\n\nThe exact schema is not important.\n\nStructured output is.\n\nAn orchestrator should not need to parse an essay to determine whether tests passed.\n\nEach task produces a pull request targeting the Epic integration branch:\n\n```\ntask/payment-retry\n        │\n        ▼\nepic/payment-improvements\n        │\n        ▼\nmain\n```\n\nThe task PR should remain independently reviewable.\n\nCI runs again outside the Builder's local environment.\n\nThis gives us two independent validation layers:\n\n```\nBuilder validation\n        +\nCI validation\n```\n\nThe Reviewer receives:\n\n```\ntask requirements\n+\nacceptance criteria\n+\ndiff\n+\ntest results\n+\nrelevant architecture constraints\n```\n\nIt returns structured findings.\n\n```\nstatus: changes_requested\n\nfindings:\n  - severity: blocking\n    file: src/payments/service.ts\n    line: 87\n    reason: declined payments are being retried\n    criterion: only transient failures may be retried\n```\n\nOr:\n\n```\nstatus: approved\nfindings: []\n```\n\nIf the Reviewer finds a blocking problem:\n\n```\nReviewer\n   ↓\nBuilder\n   ↓\nvalidation\n   ↓\nReviewer\n```\n\nThe loop continues within predefined limits.\n\nAn important operational detail is that retries should not be infinite.\n\nAfter a certain number of unsuccessful correction cycles, the task should be escalated.\n\n```\nattempt 1 → failed review\nattempt 2 → failed review\nattempt 3 → failed review\n               ↓\n        human escalation\n```\n\nRepeated failure is itself useful information. It may indicate that the task is poorly specified, incorrectly decomposed, or hiding an unresolved architectural problem.\n\nOnce:\n\n```\nBuilder validation = passed\nCI = passed\nReviewer = approved\n```\n\nthe task can be merged into the Epic branch according to the project's autonomy policy.\n\nThis may unblock downstream tasks in the dependency graph.\n\nThe orchestrator then schedules the newly available work.\n\nPassing every task independently does not prove that the Epic works as a whole.\n\nOnce all required tasks are integrated, the workflow runs broader validation:\n\n```\nfull test suite\nintegration tests\nend-to-end tests\ncontract tests\nmigration checks\nsecurity checks\nperformance checks\n```\n\nThe exact set depends on the project.\n\nThis stage catches problems that task-level validation cannot detect.\n\nFor example, two individually correct tasks may still implement incompatible assumptions.\n\nThe final Reviewer evaluates the integrated result against the original Epic rather than individual tasks.\n\nThe question changes from:\n\nDid we implement Task 7 correctly?\n\nto:\n\nDoes the system now satisfy the outcome defined by the Epic?\n\nThis distinction is important.\n\nA workflow can successfully complete every task and still fail to achieve the intended product behavior if the decomposition itself was incomplete.\n\nIf the final integration satisfies the Epic criteria, the workflow produces an Epic pull request:\n\n```\nepic/payment-improvements\n        │\n        ▼\n       main\n```\n\nThis is an appropriate place for a human approval gate.\n\nThe human is no longer expected to manually implement or review every small code change.\n\nInstead, human attention is concentrated where it has the highest value:\n\n```\nrequirements\narchitecture\nrisk\nexceptions\nfinal integration\n```\n\nThat is a more realistic interpretation of \"human-in-the-loop\" development than requiring a person to supervise every tool call made by an agent.\n\nThere is no requirement that every stage use the same model.\n\nDifferent roles have different computational requirements.\n\nThe Planner may benefit from stronger reasoning because it needs to understand architecture and dependencies.\n\nThe Reviewer may need similar capability because it must identify subtle inconsistencies.\n\nA Builder executing a very constrained change may not require the same model.\n\n```\nOrchestrator ── high reasoning capability\n\nPlanner      ── high reasoning capability\n\nReviewer     ── high reasoning capability\n\nBuilder      ── selected according to task complexity\n```\n\nThis also creates room for provider-independent workflows.\n\nAn orchestration layer could use OpenCode, Codex, Claude, or other coding-agent runtimes without fundamentally changing the architecture described here.\n\nThe model becomes an execution component rather than the workflow itself.\n\nOnce the process is structured, it can be measured.\n\nUseful metrics include:\n\nThese metrics should not be used only to minimize token usage.\n\nThey can help answer more useful questions.\n\nDoes adding a Planner reduce failed implementations?\n\nDoes a stronger Reviewer reduce integration defects?\n\nAre certain task types consistently escalated?\n\nAt what task size does autonomous completion become unreliable?\n\nIs parallel execution actually reducing lead time?\n\nAt that point, decisions about agents and models can be based on workflow performance rather than intuition.\n\nOnce everything above is explicit, the orchestration problem becomes surprisingly mechanical.\n\nA task can move through states such as:\n\n```\nPENDING\n   ↓\nREADY\n   ↓\nPLANNING\n   ↓\nBUILDING\n   ↓\nVALIDATING\n   ↓\nREVIEWING\n   │\n   ├── changes requested ──► BUILDING\n   │\n   ├── blocked ────────────► ESCALATED\n   │\n   └── approved\n           ↓\n        MERGED\n```\n\nThe Epic has its own lifecycle:\n\n```\nPLANNING\n   ↓\nEXECUTING\n   ↓\nINTEGRATING\n   ↓\nVALIDATING\n   ↓\nAWAITING_APPROVAL\n   ↓\nCOMPLETED\n```\n\nThis is the point where AI-assisted software development starts looking less like a chat interface and more like a distributed software-delivery system.\n\nAnd that is probably the more useful abstraction.\n\nThe most interesting problem in AI-assisted software development is increasingly not code generation itself.\n\nIt is orchestration.\n\nAn autonomous development workflow needs to answer questions such as:\n\nBetter models will make individual executions more capable.\n\nThey will not eliminate the need to answer those questions.\n\nA robust agentic development workflow therefore should not be designed around the assumption that a sufficiently powerful model can receive an entire project and simply \"figure it out.\"\n\nInstead, the system should reduce ambiguity before execution.\n\nThat means:\n\n```\nclear intent\n+ coherent tasks\n+ explicit dependencies\n+ minimal relevant context\n+ isolated execution\n+ objective validation\n+ independent review\n+ risk-based autonomy\n+ controlled integration\n```\n\nThe objective is not to remove humans from software engineering.\n\nIt is to move human attention away from supervising routine implementation and toward the decisions where judgment, product context, architecture, and risk actually matter.\n\nOnce those boundaries are explicit, AI agents stop being isolated coding assistants and become components of a software delivery pipeline.", "url": "https://wpnews.pro/news/from-epic-to-merge-an-end-to-end-workflow-for-software-development-with-ai", "canonical_source": "https://dev.to/rafael_dev/from-epic-to-merge-an-end-to-end-workflow-for-software-development-with-ai-agents-1ijn", "published_at": "2026-09-21 21:55:40+00:00", "updated_at": "2026-09-21 22:24:26.974399+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-tools", "mlops"], "entities": [], "alternates": {"html": "https://wpnews.pro/news/from-epic-to-merge-an-end-to-end-workflow-for-software-development-with-ai", "markdown": "https://wpnews.pro/news/from-epic-to-merge-an-end-to-end-workflow-for-software-development-with-ai.md", "text": "https://wpnews.pro/news/from-epic-to-merge-an-end-to-end-workflow-for-software-development-with-ai.txt", "jsonld": "https://wpnews.pro/news/from-epic-to-merge-an-end-to-end-workflow-for-software-development-with-ai.jsonld"}}