[{"content":"Every week my feed hands me a new verdict on vibe coding. Vibe coding is the future. Vibe coding is garbage, you still have to verify everything. It is only good for grunt work. Honestly, manual is faster. One verdict for the whole technique, case closed.\nMy hunch was that the debate is broken because it treats vibe coding as one thing, and it is not one thing. Whether it works depends on what you are building, and above all on what it costs to validate the result. I carry four scenarios in my head, and they get four different verdicts.\nBut I just wrote a post arguing that any claim about the world should carry a receipt. \u0026ldquo;Everyone on LinkedIn is doing blanket verdicts\u0026rdquo; is a claim about the world. So before publishing it, I went and counted.\nI counted 51 takes, and my hunch was half wrong I collected every vibe coding take I could actually read and classify, 28 search-indexed LinkedIn posts and 23 blog essays and press pieces. For each one I asked one question. Does it issue a single verdict for all of vibe coding, or does it say it depends on the scenario?\nMy own tally, August 2026, classified one by one. Survey sources are linked at the end of the post. About 63 percent of what I could read was scenario-based. So the strong version of my hunch, that nobody breaks it down, is simply false. I am glad I checked before writing it.\nThe count surfaced something better though. Look at where the blanket verdicts live. The most viral posts in my sample were almost all lump-sum. \u0026ldquo;Welcome to the Age of Vibe Coding\u0026rdquo; sits at 1,271 reactions. \u0026ldquo;Adapt or become obsolete\u0026rdquo; pulled 309 comments. \u0026ldquo;Vibe coding is eating SaaS\u0026rdquo; got 257 reactions. Four of the five highest-engagement posts I found gave one verdict for everything, and the nuance was underneath them, in the comment sections, where people quietly did the segmentation the author skipped. Fine for internal tools, not for core systems, that kind of thing.\nThere is also a pattern I started calling the headline lie. A lump-sum title, \u0026ldquo;Vibe Coding: A Waste of Time and Money,\u0026rdquo; sitting on top of a body that is actually scenario-based. Judged by headline alone, which is how a feed gets read, several items flip categories.\nSo the honest finding is this. The discourse is not ignorant, it is flattened. The scenario thinking exists, but the algorithm pays for verdicts, so verdicts are what you scroll past. Even Andrej Karpathy, who coined the term in February 2025, scoped it in the same breath, \u0026ldquo;not too bad for throwaway weekend projects.\u0026rdquo; The lump-sum framing is what the feed did to a scoped idea.\nDevelopers already vote with their hands Here is the part I find genuinely funny. While the feed argues yes or no, actual developer behavior is a gradient, and it is exactly the gradient you would expect if everyone privately agreed that scenario is what matters.\nSonar\u0026#39;s State of Code survey. Adoption falls as the stakes rise. That is a segmented verdict, delivered as behavior. Adoption falls step by step as the stakes rise. Nobody in that survey is acting out \u0026ldquo;vibe coding is the future\u0026rdquo; or \u0026ldquo;vibe coding is garbage.\u0026rdquo; They are acting out \u0026ldquo;it depends,\u0026rdquo; including, I would bet, some of the people posting verdicts.\nThe Stack Overflow survey shows the same split inside individual heads:\nStack Overflow Developer Survey 2025, about 49,000 respondents. 84 percent use the tools. 46 percent distrust the output. Only 15 percent vibe code professionally. Those three numbers only fit together if developers are segmenting. Use it here, verify it there, refuse it over there.\nMy four scenarios This is the breakdown I actually use. The axis underneath it never changes: what does validation cost, and who pays if I skip it?\n1. A small fix in an existing codebase A defect, a security patch, a button that stopped working. Vibe coding is viable today. You give the AI the intent and the context, and the diff is small enough that reviewing it is cheap. Validation costs minutes. This is where the \u0026ldquo;you still have to verify everything\u0026rdquo; objection is weakest, because verifying everything is a two-minute read.\n2. A decent-sized new feature Still earns its keep, but differently. It is best at getting you unstuck. Where to start, where things go, iterating toward the shape. The catch is that the benefit does not scale with the output. The more code it generates, the more you have to read and mentally connect, and validation cost grows faster than typing time ever did.\n3. A full production feature or application This is where it breaks, and not because the generation fails. The generation succeeds all too well. It breaks because validating everything, correctness and security both, stops being practical. Fastly surveyed 791 developers and found nearly a third spend so long fixing AI code that it offsets most of the time saved. Veracode ran benchmark tasks against more than a hundred models and got security vulnerabilities in 45 percent of them, and newer models were not better. Generation is cheap now. Validation is the bottleneck, and in production the bill for skipping it goes to your users.\n4. Local, personal, non-public software Full-app vibe coding works here, today, and I do not say that hypothetically. I have vibe coded a project dashboard, a budget tracker, and a token usage dashboard. All of them run locally, and all of them got validated the honest way personal tools get validated: I use them every day, and they either work or I fix them. Nothing is exposed and nobody\u0026rsquo;s data is at risk. This is the scenario the lump-sum skeptics erase entirely.\nA teaser while I am here: demos of these apps are coming to SleemAI soon.\nNotice the two axes doing the work. The size of the change sets the validation cost. The exposure of the result sets the price of a miss. Every published framework I found in the research runs on one axis only. Stakes only, or code size only, or whether anyone will ever maintain it. All useful, all half the picture. You need both, because a tiny change to an exposed system and a huge change to a private one are both fine, and the debate keeps mistaking one for the other.\nOne honest caveat against my own scenario 1. A controlled study by METR found experienced developers were 19 percent slower with AI on small tasks in code they knew deeply, while believing they were faster. So viable does not always mean faster. My claim for small fixes is that validation is cheap, not that you will beat an expert who already knows the file.\nAsk the better question I am not going to hand you a verdict on vibe coding, because a verdict is the wrong shape for the answer. The question is not whether vibe coding works. The question is what validation costs here, and who pays if I skip it. Cheap validation and a small blast radius, go ahead. Expensive validation and a public blast radius, that is not caution talking, that is arithmetic.\nThe feed will keep serving verdicts, because verdicts travel and nuance sits in the comments. Next time a post tells you vibe coding is the future or a scam, check which of the four rooms the author is standing in. They are usually describing one room, loudly, as if it were the whole house.\nSources for the numbers: my own 51-item classification (August 2026, search-indexed posts only, so the real feed likely skews even more lump-sum than my tally); Sonar, State of Code developer survey, 1,100+ developers, January 2026; Stack Overflow Developer Survey 2025, about 49,000 respondents; Fastly developer survey, 791 developers, 2025; Veracode GenAI Code Security Report, 2025; METR, July 2025; and Karpathy\u0026rsquo;s original tweet, February 2025.\n","permalink":"https://www.rajasleem.com/posts/vibe-coding-is-not-a-yes-or-no-question/","summary":"\u003cp\u003eEvery week my feed hands me a new verdict on vibe coding. Vibe coding is the future. Vibe coding is\ngarbage, you still have to verify everything. It is only good for grunt work. Honestly, manual is\nfaster. One verdict for the whole technique, case closed.\u003c/p\u003e\n\u003cp\u003eMy hunch was that the debate is broken because it treats vibe coding as one thing, and it is not one\nthing. Whether it works depends on what you are building, and above all on what it costs to validate\nthe result. I carry four scenarios in my head, and they get four different verdicts.\u003c/p\u003e","title":"Vibe Coding Is Not a Yes or No Question"},{"content":" Part 8 of Building My Agentic Workflow in Public. Part 7 audited a painful bill and found my own specs were the culprit. This is what round two of testing revealed: the plan was not wrong because it thought badly. It was wrong because it never looked.\nAfter the retro in Part 7, I rebuilt my pipeline around a set of new rules and ran the whole thing again on the same two projects, SleemAI and Morpheus Observability. Round two went better, and I will share the full numbers in a coming post. But one finding from the audit was so simple, and so embarrassing, that it deserves its own short post.\nThe question the machine kept asking me Quick context if you are new here: my pipeline is a chain of AI agents that build software in stages. A planning stage writes the specs, the documents that say what to build. Building agents implement them. Evaluator agents check the work. When a spec is ambiguous or two specs contradict each other, the run halts and waits for me to answer a question. Every halt costs tokens and time, because I have to come back, read the question, rule on it, and resume.\nRound two still halted. So I did what Part 7 taught me to do, I refused to accept the halts as the cost of doing business and went to count them instead. I sorted every question the pipeline had stopped to ask me into buckets: which of these actually needed a human?\nThe answer: not even half.\nRoughly 45 percent of the halt pain on one project traced back to questions that were already answered on the hard drive. Not answered in some deep, hidden way. Answered by one command. One find. One grep. Five seconds at planning time.\n259 out of 486 Here is my favorite example, favorite in the way a bruise is a favorite.\nOne spec stated, confidently, that every plugin file in the codebase sits inside a directory named after its kind. It sounded reasonable. It was written in the same calm, authoritative tone as everything else in the document. Every downstream agent took it as fact and reasoned correctly from it. The building agents built for it. The evaluators evaluated against it.\nThen a run collided with reality and halted, and I finally ran the one command that checked the claim.\nOf 486 plugin files, 259 did not match the assumption. The majority. The spec was built on a guess, the guess was wrong more often than it was right, and the entire chain inherited it without anyone, agent or human, spending five seconds to look.\nThinks well, never looks That is the pattern, and once I saw it I could not unsee it. The planning chain thinks well but never looks. The reasoning at every stage was genuinely good. Each agent drew correct conclusions from what it was told. The failure was upstream of all the thinking: the premise was never checked against the disk it was describing.\nIt is the consultant who writes a brilliant strategy for a warehouse they never visited. Humans do this constantly, plans built in meeting rooms on assumptions nobody walked downstairs to verify. My agents inherited the habit from me, because I was the one who let confident prose stand in for evidence.\nflowchart TB A[Plan makes a claim\u0026lt;br\u0026gt;about the codebase] --\u0026gt; B{Did anyone look?} B -- no --\u0026gt; C[Every agent reasons\u0026lt;br\u0026gt;from a guess] C --\u0026gt; D[Run collides with reality,\u0026lt;br\u0026gt;halts, human pays] B -- \u0026#34;yes: one command,\u0026lt;br\u0026gt;one count\u0026#34; --\u0026gt; E[Claim carries a receipt] E --\u0026gt; F[Build proceeds]The fix is one rule, not more process My first instinct was to add a review stage. More checking, more agents, more paperwork. Part 7 already taught me where that road goes. The actual fix is one rule, and it is cheap:\nAny claim a spec makes about existing code or data must carry the command that checked it and the number it returned.\nNot \u0026ldquo;every plugin file sits in a kind-named directory.\u0026rdquo; Instead: \u0026ldquo;checked with find at planning time, 486 plugin files, 227 match the kind-named pattern, 259 do not.\u0026rdquo; The first version is a guess wearing a suit. The second version cannot quietly be a guess, because the receipt is attached. And when the receipt says 259 out of 486 break your assumption, the plan changes before a single token is spent building on it.\nThe rule works because it moves verification to the cheapest possible moment. At planning time, checking a claim costs one command. Three stages later, the same wrong claim costs a halted run, an expensive eval round, and a human context switch.\nTrust, but grep If you work with AI agents, or honestly with people, the takeaway travels well: a plan is only as good as its least-checked assumption, and the least-checked assumptions are usually the ones stated most confidently. Reasoning quality gets all the attention. Premise quality is where the money went.\nSo that is the rule I now hold every plan to, machine-written or not. Claims about the world come with receipts. Trust, but grep.\nRound two produced real numbers on cost and quality, including a result on escaped defects I am still a little surprised by. That is the next post.\n","permalink":"https://www.rajasleem.com/posts/agentic-workflow-part-8-trust-but-grep/","summary":"\u003cblockquote\u003e\n\u003cp\u003ePart 8 of \u003cem\u003eBuilding My Agentic Workflow in Public\u003c/em\u003e.\n\u003ca href=\"/posts/agentic-workflow-part-7-the-paperwork-problem/\"\u003ePart 7\u003c/a\u003e audited a painful bill and found my own\nspecs were the culprit. This is what round two of testing revealed: the plan was not wrong because it\nthought badly. It was wrong because it never looked.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003eAfter the retro in Part 7, I rebuilt my pipeline around a set of new rules and ran the whole thing again on\nthe same two projects, SleemAI and Morpheus Observability. Round two went better, and I will share the full\nnumbers in a coming post. But one finding from the audit was so simple, and so embarrassing, that it\ndeserves its own short post.\u003c/p\u003e","title":"Trust, but Grep: The Plan Was Perfect and the Premise Was False"},{"content":" Part 7 of Building My Agentic Workflow in Public. Part 6 said do not be obedient, verify, because your own context window is small. This is the first time I turned that rule on my own process.\nOver six parts I built a pipeline that can design, plan, and ship a batch of features mostly on its own. Then I finally pointed it at two real repos, back to back, on the same day. One of them took about ten hours and burned close to ten million tokens to ship roughly five features. I sat with that for a minute. Ten hours. Ten million tokens. Five features.\nThe easy thing was to shrug. This is just what autonomy costs. The agents are thorough, the loop is careful, and careful is slow. Accept it and move on.\nPart 6 is the entire reason I did not. The whole point of that post was that you do not accept what the system hands you just because it hands it to you with confidence. A bill that feels wrong is not a verdict. It is a signal. So instead of accepting it, I went to look.\nThe accidental A/B test Here is the lucky part. I had run the exact same pipeline on a second repo the same day. Same commands, same model, same loop. The only real difference was the two codebases and the specs I wrote for each. That accident turned into a clean A/B test, and the two runs are not close.\nOne repo paid about twelve thousand six hundred tokens for every line of shipped code. The other paid about two thousand seven hundred. Same pipeline, same day, a 4.7x gap.\nExpensive repo Cheap repo Tokens burned ~9.8M ~5.2M Source code shipped 757 lines 1,956 lines Tokens per line of code ~12,600 ~2,700 Average feature spec 539 lines 255 lines Code contract 1,298 lines 362 lines Planning docs to shipped code 6.2 : 1 1.7 : 1 I went looking for a benchmark to tell me whether twelve thousand tokens a line is a lot, and there is not really one. Nobody publishes a clean tokens-per-line-of-code figure, because it depends entirely on how your loop is built. What is well established is that in an agentic loop almost all of the cost is input tokens, and the full context gets re-sent on every single turn. The loop design, not the model, controls how fast that adds up.\nThat one fact explains the whole gap. Tokens per line is really a measure of how many times the agent re-read how much spec. My expensive repo had specs twice as long, and it went through more evaluation rounds, and every round re-read the whole spec. Twice the spec, read many more times, is not twice the cost. It is almost five times the cost. The length multiplies through the entire loop.\nWhere the money actually went Not where I expected. In the expensive repo the batch stopped and asked for my help nine times. Zero of those nine halts were caused by a bug in the shipped code. Every one of them was the specification arguing with itself.\nI had written my spec templates so every requirement got stated three times: once in an acceptance table, once in a task validation cell, once in a done checklist. Three copies of anything will eventually disagree. And every time two copies disagreed, the evaluator flagged it, a ticket got rewritten, and sometimes the whole batch halted. When I counted, somewhere between half and sixty percent of everything the AI reviewer found was one copy of a requirement contradicting another copy of the same requirement. Not bugs. Not design flaws. Just my own restatements drifting apart.\nThe single most expensive moment is almost funny. One eval round demanded that a test suite report exactly four passing tests. A later round discovered the fourth test could not pass, because the way I had specified it was physically impossible in the language runtime. That one contradiction, entirely mine, cost about six hundred thousand tokens and a full batch halt before a single line of product code was written.\nThe full run logs (real numbers, from the workflow completion reports) Every row is a real workflow run, tallied from task notifications, not an estimate. The expensive repo on top, the cheap one below.\nsleemai (real numbers from the run reports) run subagent tokens wall-clock F1.1 ships 1,169k 50 min F1.1 purity fix 841k 27 min F1.2 ships 888k 29 min F1.3 (four rounds to ship) 2,537k ~95 min F1.4 halt 1,367k 39 min F1.4 ships, F1.5 halt 1,425k 53 min F1.5 ships (5/5) 625k 21 min four smaller runs + three wrap agents ~950k ~60 min TOTAL ~9.8M ~5h 52m agent / ~10-11h wall ------------------------------------------------------------------------ morpheus-observability (7 runs, 6 features shipped) run tokens duration 1 crashed (args bug) 15.6k 0:16 2 halt, F1.1 pre-eval 603k 16:46 3 halt, F1.1 post-eval (false halt) 676k 26:45 4 halt, F1.2 (a real bug) 862k 34:06 5 session limit (nothing shipped) 341k 13:48 6 shipped F1.3 + F1.4 1,822k 1:16:53 7 F1.6 blocked on a human decision 911k 29:19 TOTAL (6 features) 5.23M 3h 18m agent / ~6h wall The part I did not enjoy admitting Here is the hunch I had going in, and the data confirmed it. The quality of what an agent produces is maybe eighty percent a reflection of the spec you gave it. You do not usually fail because the agent is weak. You fail the agent through your specs.\nMine were too long. A feature spec that ran five hundred and thirty nine lines was really a hundred-line spec wearing a suit. I could cut most of them by a factor of seven and lose nothing that mattered.\nAnd the length was not just wasteful. It was disqualifying, for a reason that goes straight back to Part 6. A spec I cannot hold in my head is a spec I cannot review. When each feature is five hundred lines and there are five of them, the specs overflow my own context window, so I stop actually reading them, so I stop being the human in the loop. And when I am not in the loop early, the problems I would have caught at spec time surface later, during the run, as expensive eval rounds. I paid in tokens and hours for the reviewing I did not do up front.\nI was micromanaging senior engineers When I read my expensive specs back, I was a little embarrassed. I had dictated the exact name of a private variable. Which of two identical Python idioms to use. The exact test fixture to capture output with. How to read a value out of a .env file. I had pasted the same proof table into one spec twice, byte for byte.\nNone of that crosses a boundary between components. None of it is a real contract. It is internal detail that Opus 5 or Sonnet 5 is entirely capable of deciding on its own. These models are closer to senior engineers than to interns. You do not hand a senior engineer a five-hundred-line instruction sheet on how to name a variable. And the data is blunt about it: every detail I dictated became one more thing my three copies could disagree about. The micromanagement did not buy me quality. It manufactured the churn.\nWhat actually worked, and it matters I do not want this to read as the pipeline failing. It did not. The part that carried its weight was the part that runs the code instead of re-reading the spec. The autonomous evaluation loop caught real bugs that the implementer\u0026rsquo;s own passing tests missed, because it actually executed what got built:\na logging bug that would have flooded stderr without limit in a hot path log fields that were being silently dropped, data loss with no error an error message that leaked a credential embedded in a URL a DNS lookup that stalled seventeen seconds every time an object was built an async test suite that was skipping every test while reporting all green Every one of those was found by running the code, not by reading the spec harder. That is the honest split in all this data. Execution-based review carried the quality. Spec detail carried the churn. The lesson is not to review less. It is to review by running, not by re-reading.\nThe rules I am keeping Five changes, and they are all cheap:\nWrite each requirement once. Every restatement is a copy that can drift, and with agents you pay for drift twice, once to find it and once to fix it. Specify the seams, not the internals. Name what crosses a boundary, the interfaces and shared shapes. Let the agent name its own variables and tests. Agents are best at exactly the detail work we micromanage worst. Verify by execution. The bugs that mattered came from running the code. Rounds spent re-reading ticket wording after the code already existed changed nothing and cost a fortune. Halt only on blocking findings. Log the rest and keep moving. Every halt costs a full resume. A short spec is not a lazy spec. The repo with half-length specs shipped code almost five times cheaper, with the same bug-catch rate. Where this leaves the series This is Part 6 turned on myself. The guardrail there was do not accept what you cannot verify. Here the thing I refused to accept was a bill, and refusing it taught me that my own specs had been the problem the whole time. The fix even closes the loop back to where the series started: shorter specs are readable specs, and readable specs put me back in the loop, which is the only place the human is worth anything.\nI ran this test on two of my own projects, two reports I am building out right now, SleemAI and Morpheus Observability. They are early, and I will share something concrete on both in the coming months. For now they were the perfect place to catch myself doing the exact thing this whole series argues against: handing my judgment to the machine because holding it myself felt like too much work.\nIf you run autonomous batches of your own, I would genuinely like to know where your tokens go. Mine went to my own paperwork, and I did not see it until I counted.\n","permalink":"https://www.rajasleem.com/posts/agentic-workflow-part-7-the-paperwork-problem/","summary":"\u003cblockquote\u003e\n\u003cp\u003ePart 7 of \u003cem\u003eBuilding My Agentic Workflow in Public\u003c/em\u003e.\n\u003ca href=\"/posts/agentic-workflow-part-6-obedience-is-futile/\"\u003ePart 6\u003c/a\u003e said do not be obedient, verify,\nbecause your own context window is small. This is the first time I turned that rule on my own process.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003eOver six parts I built a pipeline that can design, plan, and ship a batch of features mostly on its own.\nThen I finally pointed it at two real repos, back to back, on the same day. One of them took about ten\nhours and burned close to ten million tokens to ship roughly five features. I sat with that for a minute.\nTen hours. Ten million tokens. Five features.\u003c/p\u003e","title":"The Paperwork Outweighed the Product: What Testing My Own Pipeline Cost"},{"content":" Part 6 of Building My Agentic Workflow in Public. Part 5 settled which engine runs my loop. This one is about a different bottleneck, and it is not in the machine. It is in my chair.\nWay back in Part 0 I said the bottleneck in all of this is human. You can spin up two hundred agents, but you cannot keep up with two hundred agents, because your attention does not scale the way agent count does. That was the first face of the limit. This post is about the second face, and it is quieter and more dangerous: my context window.\nThe question I could not answer Here is the shape of the problem. I run one of my own commands, something like \u0026ldquo;design the architecture for this module,\u0026rdquo; and it points at a folder with five spec files in it. Each file is around four hundred lines. The agent reads all two thousand lines, holds every one of them, and finds a real contradiction buried in two or three of them. Then it stops and asks me.\nThe question comes back looking like this: \u0026ldquo;C from use case blah needs one two three, and it conflicts with the logging rule. What do you think?\u0026rdquo;\nAnd I am stuck. Not because I am slow, and not because I never understood the material. I wrote those specs. But I wrote them weeks ago, and I have since run the whole flow from Part 1 to Part 5 without holding any of it in my head. I do not remember which file that rule is in. I do not remember what \u0026ldquo;C\u0026rdquo; refers to. I cannot see the two lines out of two thousand that the question is actually about. The agent has all of that context. I have almost none of it.\nA real question from my own tool. Four rulings, each \u0026#39;three specs require...\u0026#39;, not one file named, not one line, not one quote. I accepted the recommendation, because checking it meant opening the whole corpus. Why I cave, and why that is the real bug So what did I do with that question? I accepted the recommendation. Of course I did. The alternative was to stop the whole session, open five files, hunt for the two relevant lines, re-read enough of the surrounding specs to understand the conflict, and only then form an opinion. That is ten or fifteen minutes of work for one question, and there are five more behind it.\nThis is the failure, and it is worth being precise about where it lives. The failure is on my side. My brain has a small context window and the agent has an enormous one, and when the question assumes I can hold what it holds, I cannot, so I default to yes. The record then says I decided. I did not decide. I waved it through.\nThat is not a small thing. When I stop actually deciding, I am no longer in the loop, and the design starts drifting away from what I intended, one accepted recommendation at a time. Not with a bang. Just a slow slide where the thing being built stops being the thing I meant to build, and I signed off on every step of the drift without ever really seeing it.\nTo be clear, the agent is usually not doing anything wrong here, and it is almost never doing anything malicious. It could be, and that matters more as these systems get more capable, but that is a different guardrail for a later post. The danger I am describing happens even when the agent is perfectly well behaved. I hand away the decision simply because I cannot hold the context to keep it.\nTrust, but verify, especially yourself The instinct the whole industry pushes is to trust the model and move fast. I think the correct posture is the old one: trust, but verify. Not obedience. And the thing I most need to verify against is not the agent. It is my own limitation.\nI know my context window is small. That is not a maybe. So I have to build a guardrail around that known weakness, or it will quietly steer everything I make. This is where the framing clicked for me. A workflow that lets a human rubber-stamp what they cannot see is not really a workflow with a human in the loop. It just looks like one.\nSo I stopped thinking of this as a workflow and started thinking of it as a guarded workflow. The guard is not mainly against the machine. It is against me, against the very human urge to cave to a limitation instead of engineering around it. This is the first of several guardrails I want to write about. It happens to be the foundational one, because it is the one that keeps me genuinely in the loop at all.\nThe fix: make every question carry its own context The guardrail itself is simple, almost dumb. If I cannot hold the context, the question has to bring the context to me. Every decision question my tools ask now has to be self-contained: everything I need to rule on it lives inside the question, not in the prose scrolling by above it.\nI wrote that down as a fixed format. Six blocks, every time.\nThe format every question now follows (my decision-question rule, trimmed) Six blocks, always all six. A block that genuinely does not apply is filled in as \"none, and why\", never dropped. It goes inside the question itself, not in the prose above it.\nWhere you are The command and argument as I typed it, the agent/phase, the step, and the file about to change. Sources file §section Lline \"the load-bearing line, quoted verbatim, never paraphrased\" What breaks the concrete mechanism of the failure, not its category Example: real paths, calls, or output showing the symptom Recommend the choice and a one-line why; the alternative and what it costs Confidence High = mechanical, safe to accept. Low = what deserves my eyes. The load-bearing block is Sources. It is not enough to say \u0026ldquo;the spec requires this.\u0026rdquo; The question has to name the file, the section, the exact line number, and quote the line verbatim, so I can verify it in one jump instead of a ten-minute hunt. A section name alone still sends me searching, and searching mid-interview is exactly when I give up and accept. A paraphrase is worse, because a summary is the very thing I am being asked to check.\nHere is the same kind of question, rebuilt to the format:\nThe same question, carrying its own context. Now I can rule on it in under a minute, because everything I need to check is in front of me. The other quiet killer is labels. A question that says \u0026ldquo;C3 turned out better than expected\u0026rdquo; means nothing to me, because C3 was a handle the agent coined three messages ago, or inside a sub-agent I never saw. So the rule is: expand every label at first use, every time.\nThe other failure mode: dangling labels. \u0026#39;C3 turned out better than expected\u0026#39; and ten decisions crushed into one line. Shorthand for the agent, noise for me. Making it actually stick Writing a format down does not make anything follow it. I have watched myself write good instructions and then watched the model quietly ignore them under pressure. So this guardrail has three layers, weakest to strongest.\nThe first layer is the format document itself, referenced by the commands that interview me. The second is a single line in my global config that applies to every session and every project, including questions asked as plain prose. The third is the one with teeth: a hook.\nThe hook fires right before the agent is allowed to ask me a structured question. It reads the question, checks that all the blocks are there and that Sources actually cites a line number, and if anything is missing it blocks the question and tells the model to rewrite it instead of putting it in front of me. It fails open on purpose: if anything about it breaks, it gets out of the way rather than wedging my session.\nThe hook with teeth (sanitized PreToolUse check on AskUserQuestion) Runs right before the agent may ask a structured question. Missing a block, or a Sources cite with no line number, and it blocks the call and makes the model rewrite. Fails open: any parse error or missing tool exits 0, so a broken hook never wedges a session.\n#!/bin/bash # PreToolUse hook wired to AskUserQuestion. set -uo pipefail REQUIRED=(\"Where you are\" \"Sources\" \"What breaks\" \"Recommend\" \"Confidence\") payload=$(cat) || exit 0 [ -z \"$payload\" ] \u0026amp;\u0026amp; exit 0 command -v jq \u0026gt;/dev/null || exit 0 tool=$(jq -r '.tool_name' \u0026lt;\u0026lt;\u0026lt; \"$payload\") # Only ever act on AskUserQuestion; wave everything else through. [ \"$tool\" != \"AskUserQuestion\" ] \u0026amp;\u0026amp; exit 0 count=$(jq -r '.tool_input.questions | length' \u0026lt;\u0026lt;\u0026lt; \"$payload\") missing=() # Validate each question on its own. for ((i=0; i\u0026lt;count; i++)); do q=$(jq -r \".tool_input.questions[$i].question\" \u0026lt;\u0026lt;\u0026lt; \"$payload\") for block in \"${REQUIRED[@]}\"; do grep -qi -- \"$block\" \u0026lt;\u0026lt;\u0026lt; \"$q\" || missing+=(\"$block\") done # Sources must cite a line number unless it is explicitly \"none\". if grep -qi \"Sources\" \u0026lt;\u0026lt;\u0026lt; \"$q\" \u0026amp;\u0026amp; ! grep -qiE \"Sources.{0,40}none\" \u0026lt;\u0026lt;\u0026lt; \"$q\"; then grep -qE \"\\bL[0-9]+\" \u0026lt;\u0026lt;\u0026lt; \"$q\" || missing+=(\"line number L\u0026lt;n\u0026gt;\") fi done # Nothing missing, allow. Something missing, block (exit 2) and say why. [ ${#missing[@]} -eq 0 ] \u0026amp;\u0026amp; exit 0 echo \"BLOCKED: question not self-contained. Missing: ${missing[*]}\" \u0026gt;\u0026amp;2 exit 2 I also wired the same rule into the parts of my toolkit that ask the most questions: the one that designs a solution, the one that writes the contract, and the one that breaks work into features. One sentence each, pointing at the same format, so the heaviest interviewers all ask the same way.\nWhere this leaves the series Part 0 said the bottleneck is human and pointed at attention. This post points at the other half: context. Both are limits I cannot wish away, so both need guarding, not willpower.\nThat is the real idea here, bigger than one format or one hook. The goal is not to approve everything, and it is not to drop out of the loop. It is to stay in the loop only for the decisions that actually need me, and only in a form I can judge in a minute. Getting there is not about trusting the machine more. It is about being honest that I am the weak link in specific, predictable ways, and building guards around exactly those.\nMore guardrails to come. This one had to be first, because without it I am not really deciding anything. I am just signing.\nIf you have felt this, the question you could not answer so you clicked approve and moved on, I would like to hear how you handle it. Mine is one guardrail against one limit, and I know I am not the only one hitting it.\n","permalink":"https://www.rajasleem.com/posts/agentic-workflow-part-6-obedience-is-futile/","summary":"\u003cblockquote\u003e\n\u003cp\u003ePart 6 of \u003cem\u003eBuilding My Agentic Workflow in Public\u003c/em\u003e.\n\u003ca href=\"/posts/agentic-workflow-part-5-two-ways-to-run-a-loop/\"\u003ePart 5\u003c/a\u003e settled which engine runs my\nloop. This one is about a different bottleneck, and it is not in the machine. It is in my chair.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003eWay back in \u003ca href=\"/posts/ai-fatigue/\"\u003ePart 0\u003c/a\u003e I said the bottleneck in all of this is human. You can spin\nup two hundred agents, but you cannot keep up with two hundred agents, because your attention does not\nscale the way agent count does. That was the first face of the limit. This post is about the second\nface, and it is quieter and more dangerous: my context window.\u003c/p\u003e","title":"Obedience Is Futile: The Guardrail You Build Against Your Own Limited Context Window"},{"content":" Part 5 of Building My Agentic Workflow in Public, and the open end of it. Part 4 got me an autonomous build loop. This one is about a fork I am standing at right now, with no final answer yet.\nThe last four parts had endings. This one has one, but a provisional one. I am still in the middle of it, and the whole reason I write these in public is to think out loud while the question is still live.\nHere is the fork. I have a loop that can build a batch of features mostly on its own. There are two very different ways to run that loop, and they pull in opposite directions.\nThe portable way The first is what I built in Part 4: a loop made of plain commands, a skill that orchestrates, and a few sub-agents one level deep. Its best quality is that it is boring, in the good way. The instructions are just text. Nothing about them is welded to one specific tool, and in principle the same approach could run on a different model entirely. It is steady, it is simple to reason about, and it goes almost anywhere.\nBecause the instructions are just text, I can show you the shape of one without giving anything private away. Here is the orchestrator, sanitized:\nThe skill that runs the loop (sanitized /ship-features) Plain instructions, no code. It reads a range of features and walks each one through the same cycle. The try-limits live in a tiny separate script so the model cannot talk past them.\n--- description: Ship a batch of features on their own. For each one, vet the ticket, build only a clean ticket, then review the result. Stop and ask me after a few failed tries. argument-hint: \u0026lt;feature range, e.g. F1.1-F1.8\u0026gt; --- For each feature in $ARGUMENTS: 1. Evaluate the ticket. If it has blocking gaps, fix them, up to 3 tries. 2. Only a clean ticket gets built. Hand it to the implementer. 3. Evaluate the result the same way, up to 3 tries. 4. Keep the try-counters in a small script, not in your own head, so the limit cannot be negotiated. Never auto-commit. On any hard limit, stop the whole batch and ask me. flowchart TB S[\u0026#34;A skill orchestrator\u0026lt;br/\u0026gt;(plain instructions, portable)\u0026#34;] S --\u0026gt; A[\u0026#34;A few sub-agents,\u0026lt;br/\u0026gt;one level deep\u0026#34;] A --\u0026gt; R[\u0026#34;Steady and simple,\u0026lt;br/\u0026gt;runs almost anywhere\u0026#34;]The cost is ceiling. One level of sub-agents and a mostly sequential loop will only go so fast and so wide. For the work I have thrown at it, that has been fine. For bigger ambitions, I can feel the limit.\nThe powerful way The second is a dynamic workflow. This one is not something I built. It is a feature built into Claude Code itself, which Anthropic shipped on May 28, 2026, still as a research preview. Instead of a fixed set of commands, it generates code, JavaScript, on the fly to drive the loop, and that unlocks a different scale: many agents running in parallel, a process that can churn for hours, far more happening at once than I would ever orchestrate by hand.\nflowchart TB W[\u0026#34;A dynamic workflow\u0026lt;br/\u0026gt;(generates code to drive the loop)\u0026#34;] W --\u0026gt; P[\u0026#34;Many agents in parallel,\u0026lt;br/\u0026gt;running for hours\u0026#34;] P --\u0026gt; R2[\u0026#34;More raw power,\u0026lt;br/\u0026gt;tied to one platform\u0026#34;]The cost here is the mirror image of the other one. All that power is tightly coupled to a single platform. The portability I liked so much in the first approach is mostly gone. I would be trading \u0026ldquo;runs anywhere\u0026rdquo; for \u0026ldquo;runs hard, here.\u0026rdquo;\nWhat happened when I ran both So I stopped guessing and ran the same batch through both, on real work. The dynamic workflow won, and not by a little. It needed about five times fewer interruptions, it ran in the background while I did other things, and the code came out at least as good on every axis that mattered. On one feature it even caught a runtime bug that my portable skill had shipped without noticing. On my scorecard it came out ahead, 25 to 21.\nThe portable skill only beat it in two places: it kept an on-disk record of what happened, and it could resume across sessions. Both real, both mine, and both small next to everything the workflow did better.\nMy head-to-head test on one real batch. The dynamic workflow scored 25/30 to my portable skill\u0026#39;s 21/30, losing only on the two rows that make a setup mine: an on-disk audit trail and resume across sessions. So I did the obvious thing. I took those two strengths from my own skill, the on-disk audit trail and the cross-session resume, and I built them into the dynamic workflow. The gap that made me hesitate is mostly closed now, and it is closed on the more powerful side.\nWhy portability keeps winning my attention There is a reason I keep leaning toward the portable side, and it is bigger than this one decision. Every piece of this series has been quietly pointed at the same goal: a personal system I actually own, that runs on my terms, that I can move and keep and understand. I have been thinking of that direction less as a product and more as a principle. My process and my skills, packaged so they move with me across any model or machine, instead of living inside one vendor\u0026rsquo;s walls. That is where I want all of this to land.\nSomething you can pick up and run on a different model next year fits that goal. Something welded to one vendor\u0026rsquo;s platform fights it, no matter how powerful it is on a good day. So when I weigh power against portability, I am not weighing them evenly. I am weighing them against where I am trying to go.\nWhere the series lands That is the whole arc, at least so far. It started in Part 0 with a problem: the tools got faster and my brain did not. Everything since has been one answer to that, built in layers. A process so I stop starting from scratch. Handoffs and sub-agents so the work survives the context window. A contract so many agents can build without diverging. A loop that runs within limits I set. And now a choice about how to run that loop, which is really a choice about how much I am willing to depend on any one tool.\nSo here is where I have actually landed, for now. I am using the dynamic workflow, because today it gets me where I need to go, and I have taught it the two tricks my portable version did better. But I am not done with the portable one. I keep sharpening it on the side, because the one thing I will not give up is portability, not being locked to a single vendor. The day my own portable setup scores better than the workflow is the day I move back to it. That is the real finish line, and I am not there yet.\nI do not have the final ending yet, only that provisional one. That is the honest part, and it is also the point. I am building this in the open, one layer at a time, and the next post in the series will exist because I built the next thing, not because a calendar told me to. If any of this is useful to you, or if you have walked a version of this road yourself, I would genuinely like to hear how it went.\n","permalink":"https://www.rajasleem.com/posts/agentic-workflow-part-5-two-ways-to-run-a-loop/","summary":"\u003cblockquote\u003e\n\u003cp\u003ePart 5 of \u003cem\u003eBuilding My Agentic Workflow in Public\u003c/em\u003e, and the open end of it.\n\u003ca href=\"/posts/agentic-workflow-part-4-letting-it-run/\"\u003ePart 4\u003c/a\u003e got me an autonomous build loop. This one\nis about a fork I am standing at right now, with no final answer yet.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003eThe last four parts had endings. This one has one, but a provisional one. I am still in the middle of it, and the whole\nreason I write these in public is to think out loud while the question is still live.\u003c/p\u003e","title":"Two Ways to Run a Loop: Portable Agents vs Dynamic Workflows"},{"content":" Part 4 of Building My Agentic Workflow in Public. Part 3 gave parallel agents a shared contract so their work stayed coherent. That coherence is what let me finally take my hands off the wheel.\nBy this point I had the pieces: a process, session handoffs, sub-agents, a contract, and an evaluator that could not cheat. What I wanted next was simple to say and hard to do. Hand the system a batch of features, walk away, and come back to something that is 85% to 90% done.\nFirst, stop the interruptions The first thing in the way was permission prompts. The model would stop and ask me before running this command or writing that file, over and over, for things I had already decided were fine. You cannot walk away from something that needs you every ninety seconds.\nSo I told it, up front, what it is allowed to do without asking. Each project has a settings file with an accept list and a deny list, and there is a global version too. Safe, routine actions just happen. Genuinely risky ones still stop and ask. It is the difference between a coworker who checks in on every keystroke and one who knows the house rules and only flags the real decisions.\nThis is the unglamorous half of autonomy. Before a system can run on its own, you have to be explicit about its boundaries, and you have to mean it.\nAn honest caveat: this helped, it did not fix everything. My rough guess is it removed about half the interruptions, not all of them. The stubborn ones cluster in one place: running the small scripts that live inside my skills. Whether a script sits in the shared toolkit I reuse across projects or inside the project itself, it still stops to ask more often than I would like. So the allow list bought me real quiet, not silence. Untangling the rest is a thread I pick up in Part 6.\nHere is a trimmed version of that settings file. The allow list is what runs without a prompt; the deny list is what always stops and asks, no matter what:\nA project's permission rules (sanitized .claude/settings.local.json) Routine, safe actions sit in allow and just happen. Anything genuinely destructive goes in deny and is stopped even if the model thinks it needs it. Everything not listed still falls back to asking me.\n{ \"permissions\": { \"allow\": [ \"Bash(ls:*)\", \"Bash(git status:*)\", \"Bash(python -m pytest:*)\", \"Bash(uv pip install:*)\", \"mcp__playwright__browser_navigate\" ], \"deny\": [ \"Bash(rm -rf:*)\", \"Bash(git push:*)\" ] } } The loop Then comes the part that does the work. One command, /ship-features, takes a range of features and runs a loop over them. It does a few preflight checks, aligns everything to the contract once up front, and then walks each feature through the same cycle: evaluate the ticket, fix anything blocking, build it, evaluate the result, fix anything blocking, move on.\nflowchart TB START[\u0026#34;/ship-features F1.1 through F1.8\u0026#34;] START --\u0026gt; PF[\u0026#34;Preflight, then align everything\u0026lt;br/\u0026gt;to the contract once\u0026#34;] PF --\u0026gt; LOOP[\u0026#34;Take the next feature\u0026#34;] LOOP --\u0026gt; CYCLE[\u0026#34;Run the eval-and-fix cycle\u0026#34;] CYCLE --\u0026gt; NEXT{\u0026#34;More features?\u0026#34;} NEXT --\u0026gt;|yes| LOOP NEXT --\u0026gt;|no| DONE[\u0026#34;Batch done\u0026#34;] CYCLE -.-\u0026gt;|\u0026#34;too many tries: hard stop\u0026#34;| STOP[\u0026#34;Pause and ask me\u0026#34;]The inner cycle is where Part 1\u0026rsquo;s lesson shows up again. The ticket gets evaluated before it gets built, so blocking problems in the spec are caught while they are cheap. Only a clean ticket gets implemented. Then the result gets evaluated too. Both checks can repeat, but only a few times.\nflowchart TB T[\u0026#34;A feature ticket\u0026#34;] T --\u0026gt; E1[\u0026#34;/eval-ticket\u0026lt;br/\u0026gt;vet the ticket\u0026#34;] E1 --\u0026gt;|\u0026#34;blocking (up to a few tries)\u0026#34;| FIX1[\u0026#34;tighten the ticket\u0026#34;] FIX1 --\u0026gt; E1 E1 --\u0026gt;|clean| R[\u0026#34;/run-feature\u0026lt;br/\u0026gt;build it\u0026#34;] R --\u0026gt; E2[\u0026#34;/eval-ticket\u0026lt;br/\u0026gt;review the result\u0026#34;] E2 --\u0026gt;|\u0026#34;blocking (up to a few tries)\u0026#34;| FIX2[\u0026#34;fix the code\u0026#34;] FIX2 --\u0026gt; E2 E2 --\u0026gt;|clean| OK[\u0026#34;Feature done\u0026#34;]Why it can\u0026rsquo;t lie to itself A loop that runs on its own needs a hard floor, or it will happily try the same broken fix forever. So the counters that track \u0026ldquo;how many tries has this had\u0026rdquo; are not kept in the model\u0026rsquo;s head. They live in small deterministic scripts. The model cannot talk itself into a fourth attempt when the limit is three, because it is not the one counting. After enough failed tries, the whole batch stops and asks me, instead of burning hours pretending to make progress.\nThis is the part I am most glad I built. The scary thing about an autonomous loop is not that it makes mistakes. It is that it can hide them from you while spending your time and money. Putting the limits in code that the model cannot soften is what makes walking away actually safe.\nThe subtle bug that almost sank it One detail nearly stopped all of this, and it is worth telling because it is not obvious. I first built the orchestrator, the thing that runs the loop and calls the specialists, as a sub-agent. At first it seemed to work, which is exactly what fooled me. When a batch only needed small edits, the orchestrator could make them itself and keep going. The trouble showed up the moment a feature needed real building work handed off to a specialist. The platform has a rule: a sub-agent cannot spawn its own sub-agents. My orchestrator needed to spawn the evaluator and the implementer, and it could not, because it was itself a sub-agent.\nThe fix was to move the orchestrator out of that layer. Instead of a sub-agent, it became a skill that runs in the main session. The main session is allowed to spawn sub-agents, so from there the orchestrator could call the evaluator and implementer it needed.\nflowchart TB M[\u0026#34;Main session\u0026lt;br/\u0026gt;runs the orchestrator as a skill\u0026#34;] M --\u0026gt;|can spawn| EV[\u0026#34;dev-evaluator\u0026#34;] M --\u0026gt;|can spawn| IM[\u0026#34;dev-implementer\u0026#34;]It sounds like plumbing, and it is, but it was the difference between an autonomous loop that worked and one that was stuck one level too deep to do its job.\nIt actually ran I tried this on a real project, a trading site I build for myself, and handed it a run of features, one after another. It worked through them mostly on its own: vetting each ticket, building it, checking the result, fixing what it could, and only coming back to me when it hit a wall it could not get past in a few tries. Not perfect, and not zero-touch, but a genuine batch of work moved from \u0026ldquo;I drive every step\u0026rdquo; to \u0026ldquo;I review the outcome.\u0026rdquo;\nWhat this phase bought me This is where the workflow stopped being a set of tools I operate and started being a system that operates itself, within limits I set. Permissions decided up front. A loop that evaluates before and after it builds. Counters it cannot fudge. Hard stops it cannot skip. And an orchestrator in the one place that could actually run it.\nIt is also where a new question opened up, the one Part 5 is about. I built this loop out of commands, skills, and sub-agents, which keeps it simple and portable. But there is another way to run a loop like this, one that trades that simplicity for a lot more raw power. I am in the middle of comparing the two, and I will show you what I am finding.\n","permalink":"https://www.rajasleem.com/posts/agentic-workflow-part-4-letting-it-run/","summary":"\u003cblockquote\u003e\n\u003cp\u003ePart 4 of \u003cem\u003eBuilding My Agentic Workflow in Public\u003c/em\u003e.\n\u003ca href=\"/posts/agentic-workflow-part-3-when-agents-diverge/\"\u003ePart 3\u003c/a\u003e gave parallel agents a shared\ncontract so their work stayed coherent. That coherence is what let me finally take my hands off\nthe wheel.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003eBy this point I had the pieces: a process, session handoffs, sub-agents, a contract, and an evaluator\nthat could not cheat. What I wanted next was simple to say and hard to do. Hand the system a batch of\nfeatures, walk away, and come back to something that is 85% to 90% done.\u003c/p\u003e","title":"Letting It Run: Toward an Autonomous Build Loop"},{"content":" Part 3 of Building My Agentic Workflow in Public. In Part 2 I pushed work onto parallel sub-agents to save context. This post is about the mess that created, and how I cleaned it up.\nParallel sub-agents let me build faster. They also introduced a problem I did not see coming. Each agent built its piece reasonably. The pieces did not match each other.\nThe divergence problem Picture three sub-agents, each handed one feature of the same epic. Each one sees the epic. None of them sees the others. So they each make their own small decisions: how to log, how to handle errors, what to name things, where shared helpers live, how their feature talks to the next one. Every one of those decisions is defensible on its own. Together they are a mess.\nflowchart TB EP[\u0026#34;One epic\u0026#34;] EP --\u0026gt; A[\u0026#34;Sub-agent A builds Feature 1\u0026#34;] EP --\u0026gt; B[\u0026#34;Sub-agent B builds Feature 2\u0026#34;] EP --\u0026gt; C[\u0026#34;Sub-agent C builds Feature 3\u0026#34;] A --\u0026gt; X[\u0026#34;Three reasonable pieces that don\u0026#39;t fit:\u0026lt;br/\u0026gt;different logging, naming, error handling\u0026#34;] B --\u0026gt; X C --\u0026gt; XI felt this as a grind. I would evaluate the features one by one, and the evaluation almost always came back with blocking problems. Not because any single feature was wrong, but because they disagreed with each other. I spent hours reading long reports, fixing seams, and re-checking, and I was not getting much for it. The faster I fanned work out, the worse the pile-up got.\nWrite the rules down first The fix sounds obvious once you say it: agree on the rules before anyone builds, not after. So I added a step that runs before features get created. /generate-architecture writes a single file, the code contract, that locks the cross-cutting decisions: naming, logging, error handling, where shared utilities live, the seams between features. It is the one place that says \u0026ldquo;this is how we do things here.\u0026rdquo;\nThe command that writes the contract (sanitized /generate-architecture) It runs between /generate-epic and /generate-features, in its own sub-agent. A short description up top, then plain instructions. The last line is the load-bearing one: it makes the step a gate.\n--- description: Before any feature is built, write the one file that locks the cross-cutting decisions every feature must share. argument-hint: \u0026lt;epic id\u0026gt; --- Read the epic in $ARGUMENTS and a representative sample of the existing code. Write one code-contract.md under 01-product-owner/00-architecture/ that locks: module layout, naming, logging, error handling, where shared utilities live, and the public seams between features. Do not write feature code. Show me the contract and wait for my approval before saving it. This is a gate: no features get generated until the contract exists. And it is a gate. No features get built until the contract exists. Every agent then reads the same contract before it writes a line, so they are all building to the same rules.\nflowchart TB EP[\u0026#34;One epic\u0026#34;] EP --\u0026gt; ARCH[\u0026#34;/generate-architecture\u0026lt;br/\u0026gt;writes the contract first\u0026#34;] ARCH --\u0026gt; K[\u0026#34;code-contract.md\u0026lt;br/\u0026gt;naming · logging · errors · shared seams\u0026#34;] K --\u0026gt; A[\u0026#34;Feature 1\u0026#34;] K --\u0026gt; B[\u0026#34;Feature 2\u0026#34;] K --\u0026gt; C[\u0026#34;Feature 3\u0026#34;] A --\u0026gt; OK[\u0026#34;Pieces that fit together\u0026#34;] B --\u0026gt; OK C --\u0026gt; OKThis one change did more for quality than anything before it. The agents stopped inventing their own conventions because the conventions already existed.\nWhat the contract looks like (trimmed code-contract.md) The section headers are stable on purpose, other commands target them by name. It lists module purposes and the seams between features, not every function, because an inventory rots the moment code is renamed. Copy the shape, fill in your own rules.\n# Code Contract # # Module Layout | Path | Purpose | | ------------- | ---------------------------------------------- | | src/api/ | HTTP routes only, no business logic | | src/services/ | business logic, called from routes | | src/models/ | data shapes, defined once, imported everywhere | | core/ | cross-cutting utils: logging, errors, config | # # Logging Strategy - Get the logger the same way everywhere; never roll your own. - info = significant event, warning = recoverable, error = a user-visible failure. - Never log secrets, tokens, or PII. # # Error Handling | Layer | Behavior | | -------- | ------------------------------------------------ | | services | raise typed errors (ParseError, ValidationError) | | routes | catch typed errors, map each to an HTTP status | | never | a bare except that swallows the traceback | # # Public Seams Between Features | Producer | Seam | Consumer | | --------- | -------------------------- | --------- | | Feature 1 | parse(file) -\u003e ParsedDoc | Feature 3 | | Feature 2 | analyze(input) -\u003e Analysis | Feature 3 | When the contract is silent No contract is complete on day one. So I gave the builders a release valve. When an implementer needs a decision the contract does not cover, it does not just improvise and it does not edit the contract either. It writes its suggestion to a separate file, code-contract-pending.md, that sits right next to the contract. Later, /sync-contract reads those pending notes, checks each one against the actual code, and folds the good ones into the real contract. The contract stays the single source of truth, and it grows from what actually came up during building, instead of me trying to predict everything up front.\nA pending entry (code-contract-pending.md) An implementer hit something the contract did not cover, so it wrote down a suggestion instead of editing the contract or improvising in silence. The file is just an append-only log of these, and /sync-contract drains it later.\n# Code Contract - Pending Entries # ## [date] - from /run-feature, Feature 4 Section: Shared Utilities Proposed entry: add core/cache.py, an in-memory memoization helper. Why needed: Feature 4 re-ran the same scoring 200 times per request. The contract did not cover caching, so we put the helper next to the other cross-cutting utilities rather than invent a new home for it. Verification: the service imports memoize from core/cache.py; tests cover it. The command that folds it back in (sanitized /sync-contract) One of only two commands allowed to write the contract. It verifies each pending note against the real code before adopting it, so a stale suggestion (from code that was later reverted or refactored) never sneaks in.\n--- description: Fold the good pending suggestions back into the contract. --- Read code-contract-pending.md and the current contract. Verify each pending entry against the actual code: does it still exist as described? For each one, decide adopt / modify / defer / reject. Show me the plan and wait. On approval, add the adopted entries under the right section, note it in the changelog, and clear those entries from the pending file. Defer anything you are unsure about; it stays pending and comes back next time. There is a matching command for code that was written before a contract existed. /align-to-contract reads the new contract and all the existing features at once, and produces a single set of changes to bring everything in line. I review it once and approve it once, instead of grinding through the feature-by-feature evaluation loop that used to eat my afternoons.\nThree roles instead of one The other half of the fix was to stop asking one agent to do everything. I split the work into three roles that check each other. A planner breaks the work down. An implementer writes the code. An evaluator reviews that code against the contract, and only reviews. The evaluator literally cannot write code, by design, so its judgment stays honest and it can never quietly \u0026ldquo;fix\u0026rdquo; something into existence.\nWhen the evaluator reviews a feature, every finding lands in one of four buckets, which makes the result something I can act on instead of a wall of text:\nflowchart TB E[\u0026#34;The evaluator reviews work\u0026lt;br/\u0026gt;against the contract\u0026#34;] E --\u0026gt; B1[\u0026#34;Blocking\u0026lt;br/\u0026gt;broken, must fix\u0026#34;] E --\u0026gt; B2[\u0026#34;Contract violation\u0026lt;br/\u0026gt;fix the code\u0026#34;] E --\u0026gt; B3[\u0026#34;Drift\u0026lt;br/\u0026gt;the contract is wrong, fix the contract\u0026#34;] E --\u0026gt; B4[\u0026#34;Pattern candidate\u0026lt;br/\u0026gt;a new idea worth adopting\u0026#34;]That third bucket matters more than it looks. Sometimes the code is right and the contract is what is out of date. Naming that explicitly, instead of forcing the code to obey a stale rule, is what keeps the whole thing from calcifying.\nThe same idea, for tests Once this worked for code, I gave testing its own version of it. A separate contract for test code, and its own planner, builder, and evaluator. Tests have their own conventions, page objects, fixtures, the shape of a scenario, and they deserve their own rulebook rather than being crammed into the code one. Two contracts, kept apart, each free to evolve on its own.\nWhat this phase bought me This is the phase where the workflow grew up. Before, parallel work meant parallel chaos. After, the contract meant many agents could build at once and still produce something coherent, because the rules existed before the work did. The evaluator gave me a trustworthy second opinion that could not cheat. And the four buckets turned review from a slog into a short list of decisions.\nThree posts in, the toolkit is no longer a pile of commands. It is one loop, and most steps now run in their own agent with a single job. Here it is end to end, the command on the left, the agent behind it on the right:\ncommand agent what it does -------------------------- -------------------- -------------------------------------------- /generate-epic you plain English becomes a structured epic | v /generate-architecture arch-architect writes code-contract.md \u0026lt;-- THE GATE | v /generate-features dev-planner the epic becomes small tickets, one contract | v /eval-ticket dev-evaluator vets a ticket; 4 buckets, review only | v /run-feature -task -defect dev-implementer builds it; a gap goes to the pending file | v /create-defect -\u0026gt; /eval-ticket a bug becomes its own tracked ticket | v /sync-contract contract-reconciler folds pending notes back into the contract | v /align-to-contract contract-reconciler pulls pre-contract code into line two files the loop turns on: code-contract.md the rulebook (only /generate-architecture and /sync-contract write it) code-contract-pending.md the inbox builders append to, never the contract itself tests get the same shape in parallel: their own contract + qa-planner / qa-implementer / qa-evaluator The shape that matters: the evaluator cannot write code and the implementer cannot rewrite the contract. Each role is boxed in, and that is what keeps the loop honest when several agents are building at once.\nThat coherence is exactly what made the next step possible. Once independent agents could build to a shared contract and be checked against it, I could stop driving every step by hand and start letting the whole loop run on its own. That is Part 4.\n","permalink":"https://www.rajasleem.com/posts/agentic-workflow-part-3-when-agents-diverge/","summary":"\u003cblockquote\u003e\n\u003cp\u003ePart 3 of \u003cem\u003eBuilding My Agentic Workflow in Public\u003c/em\u003e. In\n\u003ca href=\"/posts/agentic-workflow-part-2-surviving-the-context-window/\"\u003ePart 2\u003c/a\u003e I pushed work onto\nparallel sub-agents to save context. This post is about the mess that created, and how I cleaned\nit up.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003eParallel sub-agents let me build faster. They also introduced a problem I did not see coming. Each\nagent built its piece reasonably. The pieces did not match each other.\u003c/p\u003e\n\u003ch2 id=\"the-divergence-problem\"\u003eThe divergence problem\u003c/h2\u003e\n\u003cp\u003ePicture three sub-agents, each handed one feature of the same epic. Each one sees the epic. None of\nthem sees the others. So they each make their own small decisions: how to log, how to handle errors,\nwhat to name things, where shared helpers live, how their feature talks to the next one. Every one of\nthose decisions is defensible on its own. Together they are a mess.\u003c/p\u003e","title":"When Agents Diverge: The Code Contract"},{"content":" Part 2 of Building My Agentic Workflow in Public. Part 1 turned my prompting into a repeatable process. This one is about the wall I hit right after: a single session is never big enough for real work.\nIn Part 1 I turned the way I work into a repeatable workflow: an agile-style vocabulary of epics, features, tasks, and defects, with a command to drive each step. It made the work predictable. It didn\u0026rsquo;t solve the bigger problem, which showed up the moment the work got real. An LLM session has a memory limit, and serious work blows right past it.\nThe wall Every model has a context window, the amount it can hold in its head at once. Mine was around two hundred thousand tokens. Sounds like a lot, until you\u0026rsquo;re a few hours into building something. The conversation fills up, and as it does, the model starts compressing what came before to make room. That compression is where the pain lives. The summary keeps the gist and quietly drops the detail, and the detail is usually the part I cared about. Decisions get fuzzy. The model forgets why we did something a certain way. Quality slides right when I need it most.\nSo I started watching the gauge. When a session hit roughly eighty percent full, I stopped adding to it and did something deliberate instead of letting it degrade.\nThat gauge isn\u0026rsquo;t built in, so I made one. Claude Code lets you set a status line, a small script that prints whatever you want under your prompt. Mine shows a context bar: how full the window is, as a percentage and a token count, so I can see the wall coming instead of getting surprised by it. Here\u0026rsquo;s a trimmed version you can drop in and adapt.\nA context-usage status line for Claude Code Save the script below as ~/.claude/statusline.sh and make it executable: chmod +x ~/.claude/statusline.sh.\n#!/bin/bash # Claude Code pipes session JSON to stdin; pull the context window out of it. input=$(cat) ctx=$(echo \"$input\" | jq '.context_window') used=$(echo \"$ctx\" | jq '.current_usage.input_tokens + .current_usage.cache_creation_input_tokens + .current_usage.cache_read_input_tokens') size=$(echo \"$ctx\" | jq '.context_window_size') pct=$(( used * 100 / size )) filled=$(( pct / 5 )); empty=$(( 20 - filled )) bar=$(printf '%*s' \"$filled\" | tr ' ' '#')$(printf '%*s' \"$empty\" | tr ' ' '-') printf '[%s] %d%% %dk/%dk\\n' \"$bar\" \"$pct\" $((used / 1000)) $((size / 1000)) Then point Claude Code at it by adding this to ~/.claude/settings.json:\n{ \"statusLine\": { \"type\": \"command\", \"command\": \"$HOME/.claude/statusline.sh\" } } Now, under your prompt, you will see a bar like [########------------] 42% 84k/200k that fills as the window does. On another tool like Codex, the idea ports: search \"\u0026lt;your tool\u0026gt; custom status line token usage\", or ask your assistant to write you one and adapt it.\nHanding off between sessions The fix is a clean handoff between two commands, the way one shift hands off to the next.\n/session-wrap ends a session on purpose. It looks at what changed, then writes a structured \u0026ldquo;Handoff State\u0026rdquo; block into a session.md file at the root of the repo: what got finished, what\u0026rsquo;s still in progress, what I\u0026rsquo;m blocked on, the next concrete action, any open questions, and which files are mid-edit. It also updates the status in my PO tracker, the running list of every epic, feature, and defect. The point is that everything the next session needs lives in those two files, in a predictable shape, instead of in my head. And it does all of that in a sub-agent, not in the session I\u0026rsquo;m in, so wrapping up barely touches the window I\u0026rsquo;m trying to protect.\nInside /session-wrap (sanitized, plus the file it writes) The command itself, trimmed and generic. The first instruction is the important one: do the work in a sub-agent, so wrapping up does not cost your live window.\n--- description: Wrap up a session: document what changed, hand off cleanly to the next one. --- Do NOT do this in the main session. Spawn a sub-agent and hand it everything. The sub-agent: 1. looks at what changed (git status / diff) 2. asks which feature or defect was worked on 3. writes a \"Handoff State\" block to session.md (the fields shown below) 4. updates the status of those items in the PO tracker 5. prepares a commit message (does not push) And the Handoff State block it writes into session.md, which the next session reads first:\n## Handoff State Updated: 2026-06-08 14:20 Last completed: F2.3 token-usage parser, tests passing In progress: F2.4 dashboard chart, ~70% done Blocked on: nothing Next action: finish the F2.4 chart, then run its validation checks Open questions: should the chart show cost, or just token counts? WIP files: src/dashboard/Chart.jsx, src/dashboard/Chart.test.jsx /session-start is the other half. It opens the next session by reading that Handoff State block first, then the tracker, then the project notes, and briefs me in plain language: here\u0026rsquo;s where you stopped, here\u0026rsquo;s the next thing to do. No archaeology, no re-reading a day of work. I\u0026rsquo;m back to productive in under a minute. It runs in its own sub-agent too, so the briefing doesn\u0026rsquo;t eat into the fresh session either.\nInside /session-start (sanitized) A read-only briefing that runs in its own sub-agent, so it does not eat into your fresh window.\n--- description: Start a session: read the handoff, brief me on where to pick up. Read-only. --- Run this in a sub-agent with its own context window. The sub-agent reads, in order: 1. session.md -\u003e the Handoff State block from the last session (read first) 2. the PO tracker -\u003e full epic / feature / defect status 3. project notes -\u003e conventions and current state Then it hands the main session a short briefing: where you left off and the next concrete step. It never writes code. Both commands run their work in a sub-agent. That\u0026rsquo;s not a side detail. It\u0026rsquo;s the whole idea of the next section, applied to the two commands that bookend a session.\nflowchart TB FULL[\u0026#34;Session hits ~80% of the window\u0026#34;] FULL --\u0026gt;|\u0026#34;do nothing\u0026#34;| COMPACT[\u0026#34;auto-compaction kicks in\u0026lt;br/\u0026gt;detail quietly lost, quality drops\u0026#34;] FULL --\u0026gt;|\u0026#34;/session-wrap\u0026#34;| HAND[\u0026#34;session.md Handoff State\u0026lt;br/\u0026gt;+ PO tracker updated\u0026#34;] HAND --\u0026gt;|\u0026#34;/session-start\u0026#34;| FRESH[\u0026#34;fresh session picks up\u0026lt;br/\u0026gt;exactly where you left off\u0026#34;] When the gauge gets near full, I wrap on purpose instead of letting the model start forgetting. Pushing work onto sub-agents Handoffs help across sessions. Sub-agents help inside one. The trick: a sub-agent gets its own separate context window. So when I run /run-feature or /run-defect, the heavy lifting happens in a sub-agent that reads what it needs, does the work, and hands back a short summary. My main session never has to hold all of that. It stays light and keeps the thread, while the messy detail lives and dies in the sub-agent.\nHere\u0026rsquo;s why that matters, in numbers. Say my window is 200k tokens. A few hours in, I\u0026rsquo;ve used 100k of it, half gone. If I hand a feature to a sub-agent, the expensive part, reading files, writing code, running tests, happens in the sub-agent\u0026rsquo;s own fresh window, not mine. My main session might spend 10k sending the request and reading back a summary, instead of the 100k it would cost to do all that work inline. I stay light. The sub-agent does the heavy lifting and then disappears.\nflowchart TB MAIN[\u0026#34;my session · 200k window\u0026lt;br/\u0026gt;~100k already used\u0026#34;] MAIN --\u0026gt;|\u0026#34;/run-feature delegates\u0026#34;| SUB[\u0026#34;sub-agent · its own fresh window\u0026lt;br/\u0026gt;reads, builds, runs tests, validates\u0026#34;] SUB --\u0026gt;|\u0026#34;returns a short summary, ~10k\u0026#34;| MAINA bigger window helps, and I\u0026rsquo;ll give it real credit. Some tiers and models go up to a million tokens (Claude Code already knows about a 1M-context model; check your plan for what you can use), and moving to that made a real difference on long, code-heavy sessions: more room before I hit a wall, fewer handoffs, more of the project held at once. But even there I still reach for sub-agents, and I think I always will. A 1M window fills up too, just later. It costs more and runs slower per turn, because the model re-reads that whole context on every call. And quality tends to dip as the window fills, so even when I have the room, I\u0026rsquo;d rather not stuff it. Sub-agents keep my main thread lean, and they can run in parallel, each in its own window. The bigger window raised the ceiling. It didn\u0026rsquo;t retire the technique.\nThere\u0026rsquo;s one more piece that makes this safe. Every feature carries its own tasks, and every task carries a small check, a way to tell whether it was actually done right. So when a sub-agent works a feature, it isn\u0026rsquo;t guessing at \u0026ldquo;done.\u0026rdquo; It has something concrete to validate against. That matters a lot once you\u0026rsquo;re not reading every line the sub-agent writes, which is the whole point of handing work to it.\nAnd this isn\u0026rsquo;t something I hope the model remembers to do. It\u0026rsquo;s written into the command. /run-feature spawns a sub-agent for each phase of the work and hands it the feature with one standing instruction: validate what you build against the checks written into each task. That\u0026rsquo;s where the structure from Part 1 pays off, because a feature isn\u0026rsquo;t just a description. It\u0026rsquo;s a set of tasks, and each task carries its own validation a sub-agent can actually test against.\nWhat a feature looks like (tasks + validation) A feature is broken into tasks, and each task carries a validation: a concrete check the sub-agent can verify instead of guessing at \"done.\" Copy the shape, adapt the content.\n## Feature F2.4: token-usage chart ### Task F2.4.1: read the per-day token totals Validation: given a sample file, returns one row per day with a numeric total; an empty file returns an empty list, not an error. ### Task F2.4.2: render the chart Validation: one bar per day; hover shows the token count; no console errors. ### Task F2.4.3: handle the no-data case Validation: with zero rows, show \"no usage yet\", not a broken chart. Finally seeing the work By now my projects had a lot of markdown. Epics, features, defects, a tracker, all in that shared 01-product-owner folder from Part 1. It was structured, but it was still a pile of files, and I\u0026rsquo;m not great at holding a pile of files in my head. I kept opening them one at a time to remember where things stood.\nSo I built a tool for myself, the PO Dashboard, that reads those exact files and shows them. It\u0026rsquo;s a plain local app, nothing deployed, that points at the 01-product-owner folder and turns it into something I can actually look at. Epics with progress bars. Features by status and priority. Open defects. A \u0026ldquo;what\u0026rsquo;s next\u0026rdquo; panel that tells me the most important thing to pick up. I can click into any item and read it, or jot a note.\nflowchart TB C[\u0026#34;/generate-epic and /generate-features\u0026lt;br/\u0026gt;write markdown\u0026#34;] C --\u0026gt; MD[\u0026#34;01-product-owner/\u0026lt;br/\u0026gt;epics · features · defects · tracker\u0026#34;] MD --\u0026gt; D[\u0026#34;PO Dashboard\u0026lt;br/\u0026gt;reads and visualizes the same files\u0026#34;]The PO Dashboard doesn\u0026rsquo;t own any data. The markdown is still the single source of truth, the same files the commands write and the sub-agents read. It\u0026rsquo;s just a friendlier window onto them.\nThat window needed one more command to stay reliable, and the reason is subtle. Different Claude sessions, on different days, format the same markdown a little differently. One session writes ## Epic 2: Resume Generator, another writes ## EPIC-02: resume generator; one lays a task out one way, the next does it slightly differently. To me it all reads fine. But the PO Dashboard parses these files with a strict parser, and a small format drift is enough to make it show an empty epic or \u0026ldquo;0 features\u0026rdquo; even though all the content is right there. So I added /fix-po-format. It reformats the files to the exact shape the parser expects, without changing a single word of content, so the dashboard keeps displaying everything correctly.\nThe same markdown the commands write, finally in a form I can scan in seconds. The \u0026#39;what\u0026#39;s next\u0026#39; panel: the most important thing to pick up, without re-reading every file. What this phase bought me Part 1 gave me a process. Part 2 made it survive contact with real, multi-hour, multi-session work. Sessions hand off cleanly instead of rotting at the eighty percent mark. Sub-agents absorb the expensive context so my main thread lasts. And the PO Dashboard means I can see the whole project at a glance instead of spelunking through markdown.\nTwo posts in, here\u0026rsquo;s the whole kit. Not a pile of commands, but a small repeatable system:\nCommand or tool What it does Added in /generate-epic turns a plain-English request into a structured epic Part 1 /generate-features breaks an epic into small, buildable feature tickets Part 1 /eval-ticket vets a ticket before it gets built Part 1 /run-feature builds a feature, in a sub-agent Part 1 /create-defect logs a bug as its own ticket Part 1 01-product-owner/ the shared filing system every repo uses Part 1 ~/.claude symlink one global toolkit every project inherits Part 1 /session-wrap writes a Handoff State to session.md, updates the tracker Part 2 /session-start reads the handoff, briefs me on where to resume Part 2 sub-agents do the heavy work in their own context window Part 2 PO Dashboard turns the planning files into something I can scan Part 2 /fix-po-format normalizes the markdown so the dashboard parses it Part 2 status line shows the context window filling up Part 2 Plan, build, hand off, watch. That\u0026rsquo;s the flow so far, and the point is that my own attention is no longer the first thing to break.\nThe pain this actually saved me from is specific. I\u0026rsquo;d be deep in a piece of work, real momentum going, and hit the 200k wall mid-task. The session would auto-compact to make room, and a chunk of what we\u0026rsquo;d figured out together would just thin out. The model would forget a decision from an hour earlier, right when I needed it. Wrapping on my own terms, before that happens, is the difference between handing off a clean state and watching the session quietly get dumber under me.\nNone of this makes the model smarter. It makes the system around it hold up under load, which is a different thing, and the thing that actually lets you build something nontrivial.\nThere was still a problem waiting, though, and it was a nasty one. Once I had sub-agents building different features in parallel, they started to disagree with each other. Each one built its piece reasonably, but they didn\u0026rsquo;t match. That divergence is what Part 3 is about, and it\u0026rsquo;s where this whole workflow had to grow up.\n","permalink":"https://www.rajasleem.com/posts/agentic-workflow-part-2-surviving-the-context-window/","summary":"\u003cblockquote\u003e\n\u003cp\u003ePart 2 of \u003cem\u003eBuilding My Agentic Workflow in Public\u003c/em\u003e. \u003ca href=\"/posts/agentic-workflow-part-1-from-prompts-to-a-process/\"\u003ePart 1\u003c/a\u003e\nturned my prompting into a repeatable process. This one is about the wall I hit right after:\na single session is never big enough for real work.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003eIn \u003ca href=\"/posts/agentic-workflow-part-1-from-prompts-to-a-process/\"\u003ePart 1\u003c/a\u003e I turned the way I work\ninto a repeatable workflow: an agile-style vocabulary of epics, features, tasks, and defects, with\na command to drive each step. It made the work predictable. It didn\u0026rsquo;t solve the bigger problem,\nwhich showed up the moment the work got real. An LLM session has a memory limit, and serious work\nblows right past it.\u003c/p\u003e","title":"Surviving the Context Window"},{"content":" This is Part 1 of Building My Agentic Workflow in Public, a series on how I actually work with Claude Code day to day. It starts with the problem from AI Fatigue: the tools got faster, my brain didn\u0026rsquo;t. This post is the first thing I did about it.\nFor a while, every session with Claude started the same way. I re-explained the project. I re-explained how I like things named, where files go, what \u0026ldquo;done\u0026rdquo; means. The model was capable. I was the bottleneck, retyping the same context over and over. Then the session ended, and all of it died with it.\nThe fix wasn\u0026rsquo;t a better prompt. It was turning the way I work into a small set of repeatable steps the LLM and I both follow. That\u0026rsquo;s what this post is. Nothing fancy, just structure.\nIt started with logging The very first thing I built was a logging command. Odd place to start, I know, but it\u0026rsquo;s the most \u0026ldquo;me\u0026rdquo; decision in the whole series. I\u0026rsquo;m a little obsessed with logging. Logs tell stories, and when something breaks you should be able to read them and understand why, fast. A senior dev drilled that into me early, and I\u0026rsquo;ve kept the habit ever since.\nThere\u0026rsquo;s a sharper reason it matters now that I build with an LLM. When something breaks, I don\u0026rsquo;t screenshot the error and paste a wall of terminal output into the chat. I point the model at the log file and let it read the trace itself. Consistent, detailed logs make the model a far better debugger of its own work, because it follows the actual story of what happened instead of my secondhand description of the symptom.\nSo before I asked Claude to build features, I gave it one rule it could not skip: log the way I log. Consistent levels, consistent format, enough context to trace a request end to end. One command, applied everywhere. That single habit made everything the model produced legible, to me and to the model itself, which matters a lot once you stop reading every line it writes.\nIf you want a starting point, here is the heart of that logging rule, trimmed and generic. Drop it into your own logging instruction or command and adapt it.\nThe logging rule (sanitized starting point) The idea: logs should read like a story, so that later you, or the model, can reconstruct what happened and debug most things without a breakpoint.\n# Logging: make the logs tell a story Levels: TRACE exact execution detail (queries, params, each step) DEBUG decision points and intermediate state INFO business milestones, in business terms WARN recoverable problems, something looks off ERROR failures, with enough context to act on Every line: state the business purpose, the decision and its outcome, and tag the entities involved (for example [user:12345] [order:987]) plus a request id, so one operation can be traced from start to finish. Example flow, one request, read top to bottom: INFO [req:abc] starting checkout for [user:12345], 3 items DEBUG [req:abc] cart total computed: $99.99 TRACE [req:abc] charge call -\u003e payment provider, amount=9999 INFO [req:abc] payment ok, [order:987] created in 142ms WARN [req:abc] receipt email queued, provider slow (1.8s) One honest thing while I\u0026rsquo;m here, because it ties straight back to Part 0. The code gets generated far faster than I can read and absorb it, and I won\u0026rsquo;t pretend otherwise. Keeping up with what the model writes, and validating it properly, is a real open problem for me right now. I\u0026rsquo;m building a flow to get up to speed on generated code and check it well, and when I have something that works I\u0026rsquo;ll write it up. For now, good logging is part of how I cope. It lets me, and the model, reconstruct what happened without my having read every line as it scrolled by.\nThen I needed structure Once the output was legible, the next problem showed up. I\u0026rsquo;d ask for something big, \u0026ldquo;build me a dashboard to track my token usage,\u0026rdquo; and get a wall of work with no shape. Too much to hold, too much to review.\nSo I broke the work into a shared workflow the model and I could both follow:\nAn epic is a big unit of work, like a feature area. A feature is one shippable piece of that epic. A task is a single step inside a feature. A defect is a bug, written up the same way as a feature so it\u0026rsquo;s tracked, not lost. If that vocabulary sounds familiar, that\u0026rsquo;s the point. Epics, features, tasks, and defects are the building blocks agile teams have used to ship software for two decades. I\u0026rsquo;m not inventing a process here. I\u0026rsquo;m borrowing a proven one and pointing it at an LLM. The same structure that keeps a human team from drowning in a big project keeps the model, and me, from drowning too. Work well with an LLM and it starts to look like running a small, disciplined agile shop, just with a much faster pair of hands.\nThen I made commands that produce each of these. I describe what I want in plain English, /generate-epic turns it into a structured epic, and /generate-features breaks that epic into feature tickets I can build one at a time. Before I build anything, /eval-ticket checks the ticket itself and catches missing detail or blocking problems while they are still cheap to fix. Once a ticket is clean, /run-feature does the actual work. And when a bug turns up, /create-defect writes it up as its own ticket, which goes through the same evaluation before it gets fixed.\nflowchart TB D[\u0026#34;A plain-English description\u0026#34;] --\u0026gt; E[\u0026#34;/generate-epic\u0026#34;] E --\u0026gt; F[\u0026#34;/generate-features\u0026#34;] F --\u0026gt; X[\u0026#34;/eval-ticket\u0026#34;] X --\u0026gt; R[\u0026#34;/run-feature\u0026#34;] R --\u0026gt; C[\u0026#34;Working code + tests\u0026#34;] C --\u0026gt; DONE[\u0026#34;Done\u0026#34;] C --\u0026gt;|\u0026#34;a bug turns up\u0026#34;| DEF[\u0026#34;/create-defect\u0026#34;] DEF --\u0026gt;|\u0026#34;re-evaluate, then fix\u0026#34;| XThe point isn\u0026rsquo;t the specific commands. It\u0026rsquo;s that \u0026ldquo;work\u0026rdquo; stopped being one giant ask and became a pipeline of small, named, reviewable steps. I went from one feature swimming in my head to one clear thing at a time, which is exactly the cure for the overload I wrote about in Part 0.\nThe whole toolkit, one slash away. Each command turns a plain description into structured work. A few people have asked what these commands actually look like, so here are sanitized versions of the five this post walks through, enough to start from and adapt.\nPeek at a few of these commands (sanitized samples) Each one is just a markdown file: a short description at the top, then plain instructions. Drop it in your commands/ folder and invoke it by name, like /generate-epic. These five cover the whole loop in this post.\n/generate-epic\n--- description: Turn a plain-English request into a structured epic (goal, phases, acceptance criteria). argument-hint: \u0026lt;what you want to build\u0026gt; --- Read the request in $ARGUMENTS and any linked docs. Write one epic under 01-product-owner/01-epics/ with: a one-line goal and the business intent, the work split into ordered phases, and acceptance criteria that define \"done\". Do not write code. Ask me if the goal is ambiguous. /generate-features\n--- description: Break an epic into small, buildable feature tickets. argument-hint: \u0026lt;epic id\u0026gt; --- For the epic in $ARGUMENTS, create features under 01-product-owner/02-features/, each with a clear scope, the tasks to get there, a short validation check per task (\"how do we know this works\"), and any dependencies. Keep each small enough to build and review in one pass. /eval-ticket\n--- description: Evaluate a feature or defect ticket before it gets built. Read-only. argument-hint: \u0026lt;feature or defect id\u0026gt; --- Review the ticket in $ARGUMENTS. Do not write code. Flag anything that would block a clean build: missing detail, unclear scope, hidden assumptions, or risky steps. Return a short, actionable list, not a wall of text. A clean ticket is ready to run; a messy one gets fixed first. /run-feature\n--- description: Build a single feature: work through its tasks, write the code and tests. argument-hint: \u0026lt;feature id\u0026gt; --- Implement the feature in $ARGUMENTS. Work through its tasks in order, write tests, and run them. Mark each task done in the feature file as you go. Keep the changes scoped to this one feature. /create-defect\n--- description: Write up a bug as its own ticket so it's tracked, not lost. argument-hint: \u0026lt;short description of the bug\u0026gt; --- Capture the bug in $ARGUMENTS as a defect under 01-product-owner/03-defects/: what's broken, steps to reproduce, expected versus actual, and the likely area. A defect is a ticket like any other, so it goes through /eval-ticket before a fix. A filing system every project shares Commands that produce epics and features are only useful if those files live somewhere predictable. So I standardized a folder that every repo I work in carries, identical each time:\n01-product-owner/ ├── 00-architecture/ the rules every feature follows (much more on this in Part 3) ├── 01-epics/ the big units of work ├── 02-features/ features broken out of each epic ├── 03-defects/ bugs, logged like features └── 01-po-tracker.md one board that lists all of it This sounds boring. In practice it\u0026rsquo;s the opposite. Because the structure is the same everywhere, the model always knows where to read and where to write, and so do I. Starting a new project isn\u0026rsquo;t \u0026ldquo;set up conventions\u0026rdquo; anymore. The conventions arrive with the folder.\nEvery repo I touch has this exact structure. The model never has to guess where things go. (The 09- and 10-temp folders are something I\u0026rsquo;m experimenting with, more on them in a later post.)\nPhase zero: build it once, use it everywhere Here\u0026rsquo;s the part that ties it together, and it\u0026rsquo;s a habit I\u0026rsquo;d recommend to anyone. I didn\u0026rsquo;t build these commands inside one project. I keep them in their own versioned repo and point Claude Code\u0026rsquo;s global config at it with a single symlink, the same way people manage dotfiles. ~/.claude, the folder Claude Code reads on every run, is just a link to that repo. So every project I open inherits the same commands automatically, with nothing to wire up per repo.\n📁 my toolkit repo (in git) .claude/ ├── commands/ generate-epic, eval-ticket ... ├── agents/ planner, implementer ... └── instructions/ logging, formatting ... ⟵ symlink 🏠 home directory ~/.claude → the repo's .claude/ Claude reads this on every run, in every project, so the whole toolkit comes along automatically. If you haven\u0026rsquo;t used a symlink before, it\u0026rsquo;s just a pointer from one path to another. The whole setup is one line: keep your config in a versioned repo, then point the folder Claude reads at that repo.\n# keep your Claude config in a versioned repo, then link ~/.claude to it ln -s ~/code/my-claude-toolkit ~/.claude From then on, every project on the machine reads your toolkit through ~/.claude, and editing the repo updates all of them at once.\nWhen I improve a command, every project gets the improvement at once, because they all read the same place. When I start something new, it inherits the whole process for free. Now and then a single repo needs its own one-off, and it can have one, but the default is global. Fix it in one spot, everyone benefits.\nThis also keeps me honest about portability. The commands are plain instructions, not anything locked to one machine or, in principle, even one model. That matters later in the series when I start comparing different ways to run them.\nWhat this bought me None of this is clever on its own. There\u0026rsquo;s no autonomy here yet, no agents reviewing each other, no contract keeping parallel work in line. That all comes later. What Phase 1 bought me was simpler and more important: I stopped starting from scratch.\nWork became a repeatable process. Every step got more organized, whether I was building a new feature or fixing a bad design. It stopped being a guessing game, no more back and forth until the model finally understood me, or until I finally found the words for what was in my head. It was structured now, predictable and traceable, and I could run it over and over and follow every step forward and backward. It started to feel like a small team. The cognitive load didn\u0026rsquo;t vanish, but it chipped away, and I felt more in control and a little more productive.\nOne post in, here is the whole foundation in one place, the pieces the rest of the series builds on:\nCommand or tool What it does /generate-epic turns a plain-English request into a structured epic /generate-features breaks an epic into small, buildable feature tickets /eval-ticket vets a ticket before it gets built, while fixes are cheap /run-feature builds a feature, working through its tasks in order /create-defect logs a bug as its own ticket, tracked like a feature 01-product-owner/ the shared filing system every repo carries 01-po-tracker.md the one board that lists every epic, feature, and defect ~/.claude symlink one global toolkit every project inherits Next in the series: what happens when a single session isn\u0026rsquo;t enough, the context window fills up, and I have to hand work from one session to the next without losing the thread. That\u0026rsquo;s where sessions, sub-agents, and a way to actually see all these files come in.\n","permalink":"https://www.rajasleem.com/posts/agentic-workflow-part-1-from-prompts-to-a-process/","summary":"\u003cblockquote\u003e\n\u003cp\u003eThis is Part 1 of \u003cem\u003eBuilding My Agentic Workflow in Public\u003c/em\u003e, a series on how I actually work\nwith Claude Code day to day. It starts with the problem from \u003ca href=\"/posts/ai-fatigue/\"\u003eAI Fatigue\u003c/a\u003e:\nthe tools got faster, my brain didn\u0026rsquo;t. This post is the first thing I did about it.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003eFor a while, every session with Claude started the same way. I re-explained the project. I\nre-explained how I like things named, where files go, what \u0026ldquo;done\u0026rdquo; means. The model was capable.\nI was the bottleneck, retyping the same context over and over. Then the session ended, and all\nof it died with it.\u003c/p\u003e","title":"From Prompts to a Process: Making Claude Code Repeatable"},{"content":"Before ChatGPT, a work task had a shape I understood. Get the task, sit with it for two or three days, solve it, move on. One problem at a time. These days I can build in days what used to take me months, sometimes faster than feels reasonable. And after about four hours of it, I\u0026rsquo;m wiped. Not satisfied-tired. Wrung out, a little anxious, short with the people around me, brain running at a thousand miles an hour while I\u0026rsquo;m trying to power down.\nThat gap is what this post is about. The tools got faster. My brain didn\u0026rsquo;t. This is the first in a short series about how I actually work with these tools now, and it starts with the honest part: AI fatigue is real, and I think it has a specific cause.\nHow I used to learn Some context on the old rhythm, because the contrast is the whole point.\nWhen I needed to do something new at work, say automate a process, the first and hardest step was figuring out what to even use. Ansible, a pile of shell scripts, something else. That decision, the top of the learning curve, took real research, especially for tools without much written about them.\nOnce I knew the tool, I had a routine. I lean on Udemy. I own around sixty courses. I\u0026rsquo;d find the one course closest to what I needed, then wake up before six, and from six to eight I\u0026rsquo;d work through it before a nine o\u0026rsquo;clock start. Two hours a morning, for two or three months. That gave me the baseline: how the tool works, how to use it, enough to start shaping it to the actual problem at work. When the course was done, the extra two hours stopped, and by then I\u0026rsquo;d usually delivered the thing. It was demanding. It was also rewarding, and it never left me feeling the way four hours with an LLM does.\nA note on learning fast I\u0026rsquo;m skeptical of fast learning as a gift you\u0026rsquo;re born with, though I\u0026rsquo;ll grant that some people genuinely pick things up quicker; working memory and prior experience are real. People are different, sure. Some are better at math, some at writing, some at code. But the mechanism by which a human actually learns is the same for all of us. You listen to someone explain it, you do a few exercises, you apply it, and then you apply it again on something real. It\u0026rsquo;s repetition. It matches how the brain is built.\nThe part that does speed up is selection. My rule of thumb is that for every hour of course, I need about two more hours of doing to actually own it. So a course that advertises twenty hours is really sixty hours of work, which at two hours a morning lands around the two or three months I mentioned. Knowing that, getting faster means getting better at picking: choosing the course whose examples sit closest to what I\u0026rsquo;m trying to build, instead of the one with the lowest hour count. Over time I also learned my own wiring, when to listen first and apply later, and when to apply while I listen. That part is personal. But that\u0026rsquo;s what learning fast means for me. Not a gift. A skill that compounds.\nAnd here\u0026rsquo;s the thing to hold onto: that loop was sequential, and it was paced to my brain. One tool. One concept. One application. It was tiring in the ordinary way, but it never fried me.\nBuilding with an LLM Now the new loop. I sit down to build a tool. I am not working on one feature. I don\u0026rsquo;t think you can. I find myself holding maybe a dozen at once. From a product standpoint I\u0026rsquo;m validating five to seven features at a time, not one. At the same time I\u0026rsquo;m orchestrating. At the same time I\u0026rsquo;m architecting, sometimes more than one thing. At the same time I\u0026rsquo;m reviewing the changes the LLM is asking me to approve, and that output can be long.\nStack all of that together. I\u0026rsquo;m not fixing one defect at a time. I\u0026rsquo;m not learning one concept at a time. What used to take three or four months now takes a day, maybe three if it\u0026rsquo;s something genuinely useful. The LLM executes. So after four or five hours, my brain is just shut. During those hours I\u0026rsquo;m anxious, running at a thousand miles an hour, and the only thing I want is to disconnect.\nThe tool changed, the brain didn\u0026rsquo;t Here\u0026rsquo;s my diagnosis. The productivity tooling changed. The technology changed. My memory, my attention span, my reading speed did not. When the LLM can execute in seconds, the slowest part of the loop becomes me.\nAnd it isn\u0026rsquo;t the volume that exhausts me. It\u0026rsquo;s the simultaneity. Before, I went one feature deep. Now I go a dozen features wide, wearing four hats at once: validator, orchestrator, architect, reviewer. The old loop let my brain do what it\u0026rsquo;s good at, one thing, deeply, with repetition. The new loop asks it to do what it\u0026rsquo;s bad at, many things, shallowly, all in the same moment, with no rest in between.\nAbout those 200 agents When ChatGPT showed up in late 2022, one of my pictures of 2028 was teams shrinking. Ten people become three. A lot of jobs gone. I still believe some version of that.\nBut something is shifting in how I see it. Even if one person gets far more productive, the human limit doesn\u0026rsquo;t move. You can spin up two hundred agents, assuming the tool even supports it. You cannot keep up with two hundred agents. The infrastructure of our brain was not built to manage two hundred workers, each chewing on a couple of tasks, each coming back to check with you. And even when they all produce something, who validates the output? All of it? Yes, you can automate part of that, agents checking agents, tests, sampling, gates at every layer. But judgment doesn\u0026rsquo;t parallelize. Someone still makes the final call on whether the output is actually right, and someone is still accountable when it isn\u0026rsquo;t. That part stays with me. The agent count scales. Your attention does not. The bottleneck is human, and it sits exactly where the validation happens.\nSo when someone says they manage two hundred agents, I genuinely don\u0026rsquo;t see how. Twenty agents building fifty features at once is already more than one mind can hold.\nWhat I take from this Two things.\nOne, deep focused work with an LLM is exhausting in a new way, and that isn\u0026rsquo;t a character flaw to push through. It\u0026rsquo;s a signal. Respect your mental capacity.\nTwo, the infrastructure of the brain hasn\u0026rsquo;t changed. The tool can do an enormous amount. There is still a hard limit to us. The move isn\u0026rsquo;t to pretend the limit away. It\u0026rsquo;s to use these tools, take the real advantage they offer, and do it in moderation, with some honest sense of what your own head can actually hold.\nThat\u0026rsquo;s the why behind how I\u0026rsquo;ve set up my own workflow, which is what the rest of this series is about. I just wanted to start with the honest part.\n","permalink":"https://www.rajasleem.com/posts/ai-fatigue/","summary":"\u003cp\u003eBefore ChatGPT, a work task had a shape I understood. Get the task, sit with it for two or\nthree days, solve it, move on. One problem at a time. These days I can build in days what used\nto take me months, sometimes faster than feels reasonable. And after about four hours of it,\nI\u0026rsquo;m wiped. Not satisfied-tired. Wrung out, a little anxious, short with the people around me,\nbrain running at a thousand miles an hour while I\u0026rsquo;m trying to power down.\u003c/p\u003e","title":"AI Fatigue Is Real"}]