{"slug": "your-ai-coding-workflow-keeps-drifting-i-gave-it-a-navigator", "title": "Your AI Coding Workflow Keeps Drifting? I Gave It a Navigator", "summary": "A team at Data Leads Future built a Python state-machine graph that acts as a navigator for AI coding workflows, eliminating the workflow drift they saw in spec-driven development frameworks such as Amazon's AIDLC, OpenSpec and Superpowers. The team reported that loading those frameworks' dozens of Markdown files consumes 30k to 50k tokens per session, and that key rule documents falling into low-attention zones of the context window caused the model to ignore instructions, especially on long-context models like deepseek-v4.1-flash. The team says the graph-based navigator assigns judgment to the model, precision to the tool and decisions to humans, and that its AI coding workflow has not drifted since adoption.", "body_md": "[Harness Engineering](https://www.dataleadsfuture.com/tag/harness-engineering/)\n\n# Your AI Coding Workflow Keeps Drifting? I Gave It a Navigator\n\nJudgment to the model, precision to the tool, decisions to humans\n\nWhat stops you from using AI coding at scale in your work?\n\nBesides the fact that AI generated code quality is not stable, another big problem is that AI never follows the process you told it to follow.\n\nYou tell it to do requirements analysis first, and it just runs off and starts writing code. You make a five step plan, and by step three it forgets what the first two steps decided. Open a new session, and it cannot even remember where it left off yesterday.\n\nOver the past few months, our team used a Python script to fix this bad habit of AI. This script acts as a navigator for the AI coding workflow. It uses a graph based on a state machine, and this graph decides where each step should go. Since then, the AI coding workflow has never drifted again.\n\nIn this article, I will show you how we did this.\n\n**You can find all the source code for this article at** **the end****, feel free to grab it.**\n\n## What Problem I Ran Into\n\nI have been formally pushing AI coding in my team for more than half a year now.\n\nAt first, we only made the kind of demo used to show off a product idea. It looked cool, but it could not really be used.\n\nLater, we brought AIDLC into our AI development workflow. This is a workflow skill that came from Amazon, and it is a set of workflows made to standardize the AI development life cycle. It fully follows the enterprise level SDLC (software development life cycle) process, and it guides the LLM to generate code through detailed spec files.\n\nAfter a few months of tuning, we were finally able to get AI to build applications that run stably in production.\n\n[I also shared our experience using AIDLC online](https://www.dataleadsfuture.com/from-openspec-to-aidlc-how-i-improved-my-teams-ai-code-quality/), and it got a warm welcome from many people.\n\nBut as the work went on, we found that AIDLC could only help us build small projects or small features. When the project got bigger, problems started to show up.\n\nWhen the context got too long, or when we switched sessions, AIDLC would start to lose track of the spec documents. This caused the whole workflow to stop strictly following the spec files generated ahead of time, and in the end there was always a bug or some gap in understanding.\n\nWe also switched back to OpenSpec and Superpowers to test it out, and the result was the same. Both had the problem of workflow drift.\n\n## Why This Problem Happens\n\nThe root cause is that these are all workflow frameworks based on SDD (spec-driven development).\n\nWhether it is AIDLC's skills or OpenSpec's commands, they are both made up of dozens of Markdown files. These frameworks get loaded into the harness when the session starts, and this takes up 30k to 50k tokens.\n\nAt the same time, before coding even starts, an SDD based development workflow also generates a large number of spec files. These files also get loaded into the context, and they take up a lot of the context window.\n\nFrontier models often have context windows of more than 1 million tokens. It looks like they can hold a lot, but the model does not pay the same amount of attention to every position in the context.\n\nOnce a key rule document falls into a low weight zone, the model ignores it, and the instructions start to drift. It is like a thick instruction manual. The further you flip through it, the less you remember about the details at the front.\n\nThis is especially true for models like `deepseek-v4.1-flash`, which have a very long context window and super cheap caching. To chase a high cache hit rate, people tend to stuff a lot of content into the context window. Then they find that once the session gets long, the coding quality of these models drops a lot, and their ability to follow instructions also goes down.\n\nIn an article I wrote last year, [I explained why LlamaIndex at the time could not accurately carry out workflow tasks based on the handoff mechanism.](https://www.dataleadsfuture.com/fixing-the-agent-handoff-problem-in-llamaindexs-agentworkflow-system/) The reason was that the context was too long, and this caused the process to drift.\n\n## Using a Graph Engine in AIDLC\n\nNow that we know where the problem comes from, the next step is to look at how to fix it.\n\nThe answer is not in the AI itself, but in traditional agent frameworks. These frameworks figured out one thing a long time ago: who should drive the workflow should not be left entirely to the LLM's own judgment.\n\nBut if the goal is the same, having agents hand off tasks to each other, why did everyone end up choosing the graph engine path? To answer that, we need to look back at a bit of history in multi agent frameworks.\n\nIn early 2025, OpenAI released an agent framework called OpenAI Swarm. The core idea of this framework was to let the LLM call a function called `handoff`. This let the main agent hand off a planned task to a sub agent to carry out, which created a `planner-executor` architecture. Does this sound a lot like how modern AI coding tools (harnesses) use the `task` method to call up sub agents?\n\nBut this framework had a big limitation. When to hand off which task to which agent was written in the prompt given to the LLM. Because of this, the framework only worked well on the most advanced GPT models of that time. It did not work with other open source models. The root cause was that open source models back then were not yet good enough at following instructions.\n\nThis is why LangChain's LangGraph, which came out later (along with Crew.ai from around the same time), used a different approach. It used a scripted execution engine based on a state machine and a directed acyclic graph (DAG).\n\nThis approach is actually simple when you say it out loud. You use a Python script to first define a traditional workflow based on a graph. Each node in the graph is an agent that runs its own logic and produces structured output. Each edge is a conditional edge, and it decides which node to route the flow to next, based on the output of the previous node.\n\nThe LLM itself works on probability, so in the graph it is only responsible for making judgments, in other words, updating the state. What really decides how the workflow runs is a traditional scripted process defined by LangGraph. Because the script runs in a very deterministic way, the whole process never drifts.\n\nBy now, you have probably already seen where this is going. Yes, to let the harness also carry out the workflow accurately, I decided to add a graph based script engine to AIDLC. And at each stage, I let the LLM output a structured state to guide each step the script engine takes.\n\nNow that the logic behind this is clear, let me walk you through how I designed this script engine.\n\nI split the design of the engine into two phases: the authoring phase and the runtime phase. The authoring phase is mainly about how to define the workflow, and the runtime phase is about how to use the workflow.\n\n### Step one: define the workflow metadata\n\nWhether it is AIDLC or an SDD framework like OpenSpec, they both actually record the definition of the whole AI coding workflow in prose, inside skill files or prompt files. The LLM then follows this prompt definition to move agents and process nodes along the flow.\n\nThis creates a problem. The LLM can pull information out of text, but a script program cannot. Neither Python nor JS can understand the meaning of text without help from an LLM.\n\nOne way to do this is like LangGraph's API, where the whole workflow gets defined directly in code. When a new development task comes in, it gets routed strictly according to the code that was already written.\n\nBut this method has a big downside: it is almost impossible to customize. I want to turn AIDLC into an open framework, which means it also allows users to modify the workflow themselves. And while using it, I also want to be able to adjust the implementation details of the workflow. If every change means I have to touch the script engine, that is too risky.\n\nSo I thought, could we use a structured YAML text file to define the workflow, the way crew.ai does?\n\nBut I also did not want to throw away the workflow definitions already in the existing Markdown files and start a whole new spec from scratch. That would mean every time I adjust the workflow, I would need to change both the Markdown file and the YAML file.\n\nSo I came up with a solution. I kept the existing 14 stage Markdown prompt files of AIDLC unchanged. But at the top of each file, I added a frontmatter. This means I put a block of config information at the start of the Markdown file that only the script reads. Then I pulled all the workflow related definitions out of the prompt and put them into this config block.\n\nHere is a typical frontmatter, using the `requirements-analysis.md` file as an example:\n\n```\n---\nslug: requirements-analysis\nphase: inception\nexecution: ALWAYS\ncondition: Always executes with adaptive depth — every request needs its intent and requirements assessed; depth (minimal/standard/comprehensive) scales with clarity, complexity, and risk\ngate: approve-continue\nproduces:\n  - inception/requirements/requirements.md\n  - inception/requirements/requirement-verification-questions.md\nconsumes:\n  - artifact: inception/reverse-engineering/*\n    required: true\n    conditional_on: brownfield\n  - artifact: inception/product-design/product-design.md\n    required: false\nrequires_stage:\n  - workspace-detection\n  - reverse-engineering\n  - product-brainstorm\ndepth: adaptive\nscopes:\n  classic: EXECUTE\n  bugfix: EXECUTE\n  refactor: EXECUTE\n  security-patch: EXECUTE\n  infra: EXECUTE\n  express: EXECUTE\n---\n```\n\nThis frontmatter looks pretty complex, but it is actually very simple to understand:\n\n- Keys like `slug` ,`phase` ,`execution` ,`condition` ,`gate` ,`produces` are all metadata. They define the conditions needed before the current node runs, what phase it is in, what it produces, and so on. The script engine uses these keys to check if the current node is working correctly when it routes the state.\n- `consumes` and`requires_stage` define which upstream nodes the current node depends on, and which states of the upstream nodes it needs to consume.\n- `depth` and`scopes` define which workflows the current node shows up in, and how deep the branch of the graph goes. This makes it clear exactly when a Markdown file needs to be loaded, instead of loading every single Markdown file right at the start.\n\nI also wrote a `stage-contract.md` document under the `reference/common` directory of AIDLC. This document works as a meta spec, and it records in detail what each key in the frontmatter means and what values it can take. So the next time I adjust the workflow, or add or remove a stage, the LLM can use this document to help me write the frontmatter correctly, and it can update the dependencies between the existing frontmatters without making mistakes. This is very handy.\n\n### Step two: set up multiple workflows based on scenario\n\nNext, let me focus on the `scopes` key. This key is used to let AIDLC generate different workflows for different scenarios. Yes, after bringing in the new script engine, AIDLC no longer has just one single workflow. Instead, it now has 6 completely different workflows.\n\nWhat is the benefit here?\n\nIn the original AIDLC V1.0, there was only one workflow, and all 14 stages were marked with different activation conditions. Depending on whether it was a new project, how complex the project was, whether it was a bugfix or a feature request, and so on, it was decided which stages would run and which would be skipped.\n\nBut whether a stage would run or get skipped, the prompt defining it would still get loaded into the context as soon as the skill loaded. This wasted a lot of tokens.\n\nSo this time I split AIDLC's workflow by business scope, from one scope into six. Each business scope maps to a different set of stages to run. When the user types a prompt and this triggers the `aidlc-workflows` skill to load, the LLM figures out which `scope` the current iteration falls into, and it only loads the Markdown files it needs.\n\nAs your project moves through different stages, the system also adjusts which `scope` it picks on its own, instead of sticking with the same one `scope` forever.\n\nHere is an example: say your project starts out as just an MVP you want to build quickly to test your idea in the market. In this case, AIDLC decides this is an `express` scope, so it only loads the fewest stages needed to quickly finish a product prototype.\n\nThen, as your project wins over users and slowly grows into a product running stably in production, AIDLC's workflow uses the audit log and past spec files to shift the `scope` to `classic`. At this point, optional stages like user stories, non functional requirements, security, and scalability all get loaded in, helping you polish your product step by step.\n\n### Step three: turn the metadata into a workflow graph\n\nAs I mentioned earlier, a script engine cannot possibly build a workflow at runtime by reading natural language text. So we need a descriptive syntax to let the engine run according to a definition made ahead of time.\n\nWe used frontmatter to define AIDLC's metadata at each stage. We also used scope to sort out which stages should be used in which scenarios. Now, just like crew.ai, we need to use a structured syntax to turn these workflows into predefined workflows.\n\nThe approach here is actually pretty simple. I did not generate the workflow dynamically at runtime (meaning, while the user is using AIDLC). Instead, I generate the workflow graph while developing the AIDLC skill.\n\nI placed a `generate.py` script under `aidlc-workflows/scripts`. Every time the workflow definition changes, you can have the harness run the `generate.py` script to regenerate the graph file.\n\nThe `generate.py` script also supports a `--check` flag. Every time the AIDLC skill gets updated, you can use this flag to run an integrity check. I also set up a GitHub CI process that automatically checks the integrity of the graph every time code gets committed. This is very handy.\n\nIn the end, the `generate.py` script produces a graph in JSON format, stored under the `aidlc-workflows/scripts/data/` directory. This graph defines what the workflow architecture looks like under each scope, what its entry conditions are, what it is responsible for, what it outputs, and so on. At runtime, the script engine reads this graph and uses it to build the final workflow.\n\n### Step four: use the script engine to run the workflow precisely\n\nNow that we have talked about how the workflow gets defined, let's talk about how I use the script engine to make sure the workflow runs precisely.\n\nOther frameworks also use scripted mechanisms to make sure the workflow runs precisely, but they all need hooks from the harness to listen to the different states of the workflow as it runs. This often means an SDD framework needs to work with more than twenty different harnesses, and it needs a custom plugin for each one.\n\nBut in an enterprise level AI coding environment, this approach does not work very well, because we always build our own harness on top of an open source harness. So I would rather use a workflow framework that is not tied to any specific harness.\n\nThe AIDLC skill I built was designed from the start to be harness agnostic. It still follows the AgentSkill spec, and it keeps the script engine as a CLI script stored under the skill directory's `scripts` folder, with the script named `engine.py`.\n\nThe nice thing about this is that you do not need to care at all about how this script is built or used. You just copy the skill directory into your project's root folder like before, and then you can use it.\n\nLet me give a quick intro to how the `engine.py` script works. As a CLI script, `engine.py`'s most important commands are these:\n\n- `init` . This command sets up a state file when the workflow starts. All the different states of the workflow get recorded in this file later on, so the script engine can use the state machine to route each node of the workflow.\n- `next` . This command reads the state file, figures out which stages are already finished and what those finished stages produced, and uses this to decide what the next node is and routes to it.\n- `report` . After each stage finishes, this command gets used to update the state file. This way, whether you are continuing after the context got compressed or starting a new session, you can always pick up from the last finished stage.\n- `status` . This reads the global workflow properties set in the state file. For example, which scope is in use right now, whether optional stages are turned on, whether team collaboration mode is turned on, and so on, can all be read through this command. This way, every time a session resumes and reloads`aidlc-workflows` , there is no need to ask the user the optional questions all over again.\n\n### Step five: use a state file to precisely record the workflow state\n\nAs I mentioned earlier, the script engine I designed is basically a graph engine based on a state machine, similar in principle to LangGraph. So besides the graph file that defines the workflow, the state file is another very important file.\n\nThis file gets generated each time a new workflow starts. It still uses the original `aidlc-state.md` file from AIDLC V1.0, but this file has been heavily reworked, and now it is split into two parts.\n\nThe first part is the workflow related config. Whether it is a new project or an old project, which scope is in use, which stages need to run, where the artifact documents are stored, which extended features are turned on, all of this gets recorded here. This way, whether it is a new session or picking up from a break in the session, there is no need to scan through the artifact documents one by one. You just read this file and can pick up the process from where it left off.\n\nThe second part is the task checklist that `engine.py` generates based on the config. While the workflow is running, the engine follows this checklist strictly, and after finishing, it goes back to this checklist to update the task status.\n\nThe script engine uses the two XML tags `<!-- BEGIN ENGINE-STATE>` and `<!-- END ENGINE-STATE>` to mark the content of the task checklist. Only the script engine is allowed to change the text wrapped inside these tags, not even the LLM is allowed to edit it directly.\n\nAlso, every time the task status is updated, a sha256 hash gets generated for the whole checklist. If the sha256 hash changes during a run, this means the node status has been tampered with, either by a human or by the LLM. The script engine will then raise a warning, and it will rebuild a correct checklist by working backward from the artifact files that were already generated. This greatly reduces the chance of workflow drift during a long running task, or cases where the LLM planned a task but never actually carried it out.\n\n```\n# AI-DLC State Tracking\n## Project Information\n- **Project Type**: Greenfield\n- **Start Date**: 2026-10-08T04:10:57Z\n## Workspace State\n- **Existing Code**: No\n- **Reverse Engineering Needed**: No\n- **Workspace Root**: D:\\Documents\\PythonProject\\b15-dogfood2-chess\n...\n<!-- BEGIN ENGINE-STATE | do not hand-edit — maintained by scripts/engine.py -->\nState Version: 1\nEngine: aidlc-workflows/scripts/engine.py\n## Stage Progress\n### inception\n- [x] workspace-detection\n- [S] reverse-engineering\n- [x] product-brainstorm\n...\n## State Digest\nsha256: 33cc76d5ae995526968640649c234282291b00e42949b40c826722fc5ee5ac02\n<!-- END ENGINE-STATE -->\n```\n\nAlright, that covers the whole implementation of the script engine. You might feel a bit anxious thinking this is so complex, do I need to spend time learning a whole new framework again?\n\nActually, no. This new script engine, just like the `aidlc-workflows` skill itself, is harness agnostic. You just drop the skill into your project's root folder and it runs on its own. You do not need to worry at all about how to use this skill.\n\nNext, let me use a simple project to show you how the script engine works within a workflow.\n\n## Demo the Script Engine with a Small Project\n\nI will use a small request, \"build a bookkeeping app\", to show you how this script engine works.\n\nSince this is just a demo project, I used a one sentence request. But if you want to use this in a production project, it is best to prepare a full product design document ahead of time, writing out clearly what features your product should have. Or you can first use OpenCode's `plan` mode to talk through your idea with AI, and write it down as a design document, then use `build` mode to start the aidlc-workflows and kick off the development process.\n\nSince this starts from a new session, once I submitted my development intent to OpenCode and `aidlc-workflows` finished loading, the script engine first ran the `status` command to find out what state the workflow was currently in. Of course, the result was that this is a brand new, empty project.\n\nSo it used the `init` command to set up the new workflow.\n\nAfter each stage finishes, the script engine uses the `report` command to update the workflow state. You can see that the LLM is no longer involved in moving the workflow forward at all. This is all handled by the skill calling the CLI.\n\nThat is pretty much it. The script engine compiles every node that the whole iteration needs to move through into a flow graph, and no matter how long the session stretches, it never drifts off track.\n\nAll you need to do is, at the approval gate set up for each stage (the gate configured for that stage), take a quick look at what it produced and give it a thumbs up. Once it passes review, the engine calls the `next` command to move you forward to the next stage.\n\nAnd at every important point, like writing a document, calling an outside tool, or moving between states, the script engine uses the `park` command to leave a note. So even if your workflow gets cut off unexpectedly for whatever reason, the AI can pick back up from the spot where the last note was left.\n\nIf you start a new session to pick up a development process that was not finished before, the script engine also uses `status` first to read the current state and continue from there. There is no need to ask the user to choose again, and no need to scan through every single artifact file that has already been saved. This saves a lot of time.\n\nThat covers the demo of the core features. As you can see, while the script runs, every step follows the predefined process exactly, and even in a long session, nothing drifts off track, because the state file keeps everything in line.\n\nYou also do not need to give any special instructions. Just tell the AI your intent normally, and you do not need to worry about how the workflow is actually built.\n\n## Conclusion\n\nThat is the story of how I used a script engine to make AIDLC run exactly according to the predefined workflow. This script engine borrows a core idea from Amazon's AIDLC v2.0: \"judgment to the LLM, precision to the tool, decisions to humans.\" It also draws on the design wisdom of traditional agent workflow frameworks like LangGraph and Crew.ai.\n\nThe new `aidlc-workflows` skill, now with the script engine, has been running as a trial in my team for more than two months. The biggest thing I have noticed is that the workflow almost never drifts off track because of a long session anymore, and this precise execution of the workflow has further raised the quality of the code produced by AI coding.\n\nI enjoyed writing this article. A lot of people say that AI technology moves so fast that whatever you learn today might be useless in just a few months. But we do not need to be too pessimistic about this. Take the solution shown in this article as an example. Even though the technology keeps changing, the principles behind the technology can still help you solve problems you have not even seen yet.\n\nMy story of improving AIDLC is not over yet. In my next article, I will walk you through how the AIDLC workflow can help you start from a \"one sentence wish\" and iterate step by step, eventually growing into a large, sustainably run project. Stay tuned.\n\nThanks for reading and subscribing. You can find the source code for this article at the end of the post, and try it out yourself. If you have any questions, feel free to leave a comment anytime, and I will reply as soon as I can.\n\n## Further Reading\n\n## Source Code\n\nAll the source code for this article is here, feel free to grab it:\n\nHere's the **source code for this article**. Sign up now to get it for free.\n\n[Grab the Source Code](#/portal/signup)", "url": "https://wpnews.pro/news/your-ai-coding-workflow-keeps-drifting-i-gave-it-a-navigator", "canonical_source": "https://www.dataleadsfuture.com/your-ai-coding-workflow-keeps-drifting-i-gave-it-a-navigator/", "published_at": "2026-10-16 09:09:06+00:00", "updated_at": "2026-10-16 09:10:51.452355+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "large-language-models", "developer-tools"], "entities": ["Data Leads Future", "AIDLC", "Amazon", "OpenSpec", "Superpowers", "deepseek-v4.1-flash"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/your-ai-coding-workflow-keeps-drifting-i-gave-it-a-navigator", "markdown": "https://wpnews.pro/news/your-ai-coding-workflow-keeps-drifting-i-gave-it-a-navigator.md", "text": "https://wpnews.pro/news/your-ai-coding-workflow-keeps-drifting-i-gave-it-a-navigator.txt", "jsonld": "https://wpnews.pro/news/your-ai-coding-workflow-keeps-drifting-i-gave-it-a-navigator.jsonld"}}