<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: kanfu-panda</title>
    <description>The latest articles on DEV Community by kanfu-panda (@kanfu-panda).</description>
    <link>https://dev.to/kanfu-panda</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3940859%2F45897ada-53a1-4e66-a3ca-356f624df48e.jpeg</url>
      <title>DEV Community: kanfu-panda</title>
      <link>https://dev.to/kanfu-panda</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kanfu-panda"/>
    <language>en</language>
    <item>
      <title>Running pdlc-skills on a Real Project: Three Features, Start to Release</title>
      <dc:creator>kanfu-panda</dc:creator>
      <pubDate>Tue, 22 Sep 2026 14:35:01 +0000</pubDate>
      <link>https://dev.to/kanfu-panda/running-pdlc-skills-on-a-real-project-three-features-start-to-release-2p70</link>
      <guid>https://dev.to/kanfu-panda/running-pdlc-skills-on-a-real-project-three-features-start-to-release-2p70</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;The first seven posts were about mechanics. This one goes back to a real project and answers the six questions you only hit after the thing is installed: how to split the work, who does what, how the loop actually runs, how long it took, how much it produced, and what holds quality up. The project is a console I run for myself. Three features went to pdlc's own loop engine in parallel, all three reached the review terminal state in 88 minutes, and after the quality gate was filled in, the release went out and got deployed to two machines. The machine numbers come from the event log and from git. The hours a human spent are estimates, and I flag them where they appear.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Where this run started
&lt;/h2&gt;

&lt;p&gt;I scaffolded the project in late August with &lt;code&gt;/pdlc-bootstrap&lt;/code&gt;, took it from a minimal working version to its third round of console work in five days, then left it alone for three weeks. Reopening it, I did two things before anything else. &lt;code&gt;/pdlc-test-setup&lt;/code&gt; wrote the unit-test, coverage and lint commands into &lt;code&gt;test-commands.yml&lt;/code&gt;, and all three have to actually run before they count. Then I migrated a few old state files to the current format. Skip those two and every "check passed" later in the run is resting on nothing. E2E had gone in the day before, with a test behind each of the 45 registered core flows. So the starting line was 421 unit tests, 52 E2E cases, 89.6% coverage.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to split the work
&lt;/h2&gt;

&lt;p&gt;Three things to build: let a review run on a different machine, let notifications be filtered by where a task came from, and add two review flags to the benchmark runner. I'll call them cross-node review, origin filtering and benchmark flags. None of them is large, which is what makes them a reasonable test for the loop. I split them on three rules.&lt;/p&gt;

&lt;p&gt;Rule one, split by code dependency into chains or independents. Benchmark flags needs the remote dispatch and the verdict-return path that cross-node review builds, so those two form a chain and the second waits for the first to converge. Origin filtering touches neither, so it starts immediately.&lt;/p&gt;

&lt;p&gt;Rule two, size a feature so that three steps can finish it, those steps being TDD, implementation and review. The three features here landed between 800 and 1500 lines of diff.&lt;/p&gt;

&lt;p&gt;Rule three, features running in parallel should not touch the same file. I did not hold this one. All three had to change the same receipt-aggregation module, and the bill came due at merge time: conflicts to resolve one at a time, about ten extra minutes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fggmbilrx8vdslcz114ms.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fggmbilrx8vdslcz114ms.png" alt="Three features, one dependency chain and one independent: cross-node review feeds benchmark flags, origin filtering runs on its own" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The PRDs came from &lt;code&gt;/pdlc-prd --autonomous&lt;/code&gt; with a few paragraphs of raw requirements as input, 17 minutes for all three, and the command worked out the dependency between them by itself. Each PRD ends with a handful of open questions, ten across the three. The coordinating session ruled on them one at a time and wrote the answers back: what event to record when a verdict-return query fails, what error to raise when the machine you named isn't in the config. Leave those open and three separate processes will each guess differently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who does what
&lt;/h2&gt;

&lt;p&gt;Four roles: me, one long-lived coordinating session, subprocesses that exit as soon as their step is done, and an outer script. The coordinating session is also AI, but it writes no feature code. It coordinates and it double-checks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fju3sgihjtv8idtb0zr8t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fju3sgihjtv8idtb0zr8t.png" alt="Four roles: the human sets scope and approves the release, the coordinating session drafts requirements, reviews designs, verifies and opens PRs, subprocesses do the stage work, the script schedules" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What gets built and how the parallelism is arranged is mine to decide. The coordinating session drafts the raw requirements, the command turns them into PRDs, and the coordinating session rules on the open questions.&lt;/p&gt;

&lt;p&gt;For design, each feature gets a fresh process running &lt;code&gt;/pdlc-design --autonomous&lt;/code&gt;. Three in parallel took a little over 12 minutes, and the coordinating session spent 15 minutes reviewing them and sent one back. In the benchmark flags design, the cross-node section said the dependency wasn't ready yet, so the code should reject the request and leave a record. But that feature sits on a branch cut after cross-node review, so by the time it runs the remote dispatch exists and the implementation should call it for real.&lt;/p&gt;

&lt;p&gt;TDD, implementation and review go to the loop with nobody watching. The model is sonnet throughout, and each feature has a budget ceiling for the whole run. Once a feature converges, the coordinating session reads the diff against the design, runs the three checks itself, and opens a PR; the release, deploy and acceptance commands are its job too. What I do is merge PRs, read the quality report and the retro, and decide whether it ships. Exactly two places need a human: deciding what to build, and deciding whether it ships.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running the loop
&lt;/h2&gt;

&lt;p&gt;pdlc's own loop engine is &lt;code&gt;/pdlc-loop-run&lt;/code&gt;. Starting from the current stage, it hands each segment — TDD, implementation, review — to a fresh subagent, reads the state file after each one, and consults a fixed table to pick the next step. It stops at &lt;code&gt;review_done&lt;/code&gt; and never releases anything itself. There are two layers here: one process per feature on the outside, and inside each process, loop-run dispatching one subagent per segment. The guardrails are a step cap of 4, stop on a failed step, and stop if the state didn't move.&lt;/p&gt;

&lt;p&gt;It handles one feature at a time. Running several in parallel needs a scheduling layer around it, which here is a bash script of a little over 350 lines. It reads &lt;code&gt;depends_on&lt;/code&gt; from each feature's state file to order them, starts anything without a prerequisite immediately, and for anything with one, waits for the prerequisite to converge and branches off it. Each feature gets its own git worktree, and each feature gets one process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nt"&gt;--model&lt;/span&gt; sonnet &lt;span class="nt"&gt;--max-budget-usd&lt;/span&gt; 20 &lt;span class="nt"&gt;--permission-mode&lt;/span&gt; acceptEdits &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"/pdlc-loop-run &lt;/span&gt;&lt;span class="nv"&gt;$fid&lt;/span&gt;&lt;span class="s2"&gt; --max-steps 4 --autonomous"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the process exits, the script reads the state file and commits the work. It also polls that file every 15 seconds to record when stages actually changed, because the timestamps the model writes into the state file can't be trusted.&lt;/p&gt;

&lt;p&gt;Cross-node review and origin filtering started together. Origin filtering was the fastest: three steps, 30 minutes. Cross-node review took 51, and 13 seconds after it converged the script branched off it and started benchmark flags, which took another 37. All three reached &lt;code&gt;review_done&lt;/code&gt; in 88 minutes, each in 3 steps. Nothing hit a rate limit, no step exhausted its budget, and nothing stopped along the way.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1t8pkv8vdj9sxxpmzdet.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1t8pkv8vdj9sxxpmzdet.png" alt="Timeline of the three features: two parallel tracks, the duration of each step, benchmark flags starting after its prerequisite converged" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One thing from the run is worth writing down. The three features did not agree on stage names in their state files: two wrote &lt;code&gt;review_done&lt;/code&gt; at convergence, one wrote &lt;code&gt;review&lt;/code&gt;, and one wrote its TDD step as &lt;code&gt;tdd_done&lt;/code&gt;. Read literally, a &lt;code&gt;_done&lt;/code&gt; suffix means finished, so the loop could have taken TDD for convergence and stopped there. loop-run wasn't fooled and started the implementation step as usual. But it does mean you cannot decide whether something moved forward from the stage name alone. You have to look at whether the next-step field changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Time and output
&lt;/h2&gt;

&lt;p&gt;Steps, machine time and diff size per feature, with new test cases in parentheses.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0x84l5igdsalzstli7ez.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0x84l5igdsalzstli7ez.png" alt="Steps, machine time, code, test and documentation lines for the three features and for filling the quality gate" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The three features added 3351 lines, 1770 of them tests, roughly three times the feature code itself. PRDs and designs are counted separately at 1833 lines. Unit tests went from 421 to 516, E2E cases from 52 to 65, coverage from 89.6% to 90.3%.&lt;/p&gt;

&lt;p&gt;The whole line ran like this: draft the requirements, generate the PRDs, review the designs, start the three features, all converged 88 minutes later, merge the branches, run the quality report, red. Fill in what was missing, report passes, release v0.3.0, deploy to two machines, then acceptance on real hardware. My own time is an estimate, something like two and a half hours, spent writing requirements, reviewing designs, checking each feature after it converged, merging, and filling the gate.&lt;/p&gt;

&lt;h2&gt;
  
  
  What holds quality up
&lt;/h2&gt;

&lt;p&gt;With nobody watching, quality rests on four layers.&lt;/p&gt;

&lt;p&gt;The first is an objective check on every step. Which commands a step has to run is written in &lt;code&gt;test-commands.yml&lt;/code&gt;, and only the exit code counts, not the model saying it checked. The TDD step verifies that the newly written tests really fail. Implementation and review verify unit tests, coverage and lint, and two of the three features carried E2E as well. The 85% coverage threshold is a command-line argument. pre-commit runs lint and pre-push runs the unit tests, both taken from that same file. Across three features and three steps each, not one recorded check came back red.&lt;/p&gt;

&lt;p&gt;The second is the review after convergence. The coordinating session reads the diff against the design and runs the three checks itself before opening a PR. All three diffs matched their designs, and the single correction in this run happened earlier, at design review, the one described above. Merging produced four conflicts across three files, mostly both sides adding a field, where keeping both is the answer. Then the full suite again: 516 unit tests, 90.3% coverage, 56 E2E cases, all green.&lt;/p&gt;

&lt;p&gt;The third is the pre-release quality report. &lt;code&gt;/pdlc-quality&lt;/code&gt; looks at four things: coverage, E2E core-flow coverage, lint, and a reconciliation between the PRDs and the core-flow registry. The first report was green on the first three and blocked on the fourth. The three new features contributed 19 acceptance items, and not one of them had been registered as a core flow. The report put it plainly: 45 of 45 green does not mean these three features passed the gate, it means the old 45 are still healthy. The subagents inside the loop had in fact written E2E tests for every feature. They just never registered them.&lt;/p&gt;

&lt;p&gt;The fix is not a signature, it's the work. Nineteen items into the registry, 4 of them covered by tests that already existed, 9 new E2E tests for the rest. The second report passed all four: 64 core flows, 65 cases, all actually executed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxt9mj1esz5o0964etsv8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxt9mj1esz5o0964etsv8.png" alt="Four quality layers, and the two quality reports: 19 items unregistered on the first, 64/64 passing on the second" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The fourth is acceptance on real machines after release. Both machines took the deploy and I put real tasks through them. Origin filtering was configured on the live console, with the acceptance and benchmark origins on the mute list, and every task after that carried its origin tag. The behaviour of that filter is verified in E2E: a matching origin suppresses the completion notification, failures still go out.&lt;/p&gt;

&lt;p&gt;Cross-node review ran for real too. A review task went to the other machine, that machine executed and archived it, and this one pulled the verdict back and showed which machine had done the review. The verdict was a failure, because the claude command on that machine had never been logged in. What this layer caught was an environment problem, but it did exercise the "review failed, how does the verdict get home" path end to end. Acceptance also turned up a missing lock on the result-collection step: two processes running at once would handle the same result twice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the loop stops helping
&lt;/h2&gt;

&lt;p&gt;The parts that ran fast are the parts with an objective check. The parts that slowed down or went wrong are the parts where the record was inaccurate.&lt;/p&gt;

&lt;p&gt;Time is the clearest case. The timestamps in the state file are written by the model. The retro tool reads them and reports a median TDD stage of 2.1 hours; the real durations, recorded by the outer script's polling, were 10, 21 and 13 minutes. The inconsistent stage names above are the same problem wearing a different hat.&lt;/p&gt;

&lt;p&gt;So don't build the outer judgement on fields the model wrote. Take durations from the event log and from git commit times, and take progress from the next-step field or from the completion marker the process prints when it exits. Those are also the two improvements this run sent back to pdlc-skills: make stage names consistent, and get timestamps from a command.&lt;/p&gt;

&lt;h2&gt;
  
  
  End of the series
&lt;/h2&gt;

&lt;p&gt;Eight posts: the three-layer model, getting it installed, running the loop, holding quality, making the process visible, and finally one real project from start to finish. All of it is one idea. Move the judgements you can't rely on to where there's an objective check, and a person only has to hold the two ends: what gets built, and whether it ships.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Want to try it&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/kanfu-panda/pdlc-skills/main/install.sh | bash &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--global&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The repo: &lt;a href="https://github.com/kanfu-panda/pdlc-skills" rel="noopener noreferrer"&gt;https://github.com/kanfu-panda/pdlc-skills&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If it's useful, a star goes a long way ⭐&lt;/p&gt;




&lt;p&gt;Eight posts in, thanks for reading. If you've run something like this on a real project, which part ate the most of your own time? Comments welcome.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claudecode</category>
      <category>llm</category>
      <category>tdd</category>
    </item>
    <item>
      <title>How pdlc-skills Makes Progress, Change Impact, and Quality Trends Visible</title>
      <dc:creator>kanfu-panda</dc:creator>
      <pubDate>Sat, 12 Sep 2026 03:06:24 +0000</pubDate>
      <link>https://dev.to/kanfu-panda/how-pdlc-skills-makes-progress-change-impact-and-quality-trends-visible-44me</link>
      <guid>https://dev.to/kanfu-panda/how-pdlc-skills-makes-progress-change-impact-and-quality-trends-visible-44me</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;The last post covered the quality chain. This one is about &lt;strong&gt;visibility&lt;/strong&gt;. An AI can push three features forward in an afternoon. If you can't tell where the project stands, what a change will touch, or how the last stretch went, the automation is running in a black box. pdlc has three tools for this: the statusline together with &lt;code&gt;/pdlc-status&lt;/code&gt;, &lt;code&gt;/pdlc-relate&lt;/code&gt;, and &lt;code&gt;/pdlc-retro&lt;/code&gt;. They watch three timescales: right now, before a change, and month by month.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Three tools, one data source
&lt;/h2&gt;

&lt;p&gt;All three only read the state files under &lt;code&gt;docs/.pdlc-state/&lt;/code&gt;. They don't parse documents and they don't guess. Post 3 described how the three layers coordinate through one shared scoreboard; these tools read that same scoreboard and differ only in the question they answer. The statusline and &lt;code&gt;/pdlc-status&lt;/code&gt; answer "where are we now?". &lt;code&gt;impact&lt;/code&gt; answers "what does changing this touch?". &lt;code&gt;retro&lt;/code&gt; answers "how did this stretch go?".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb4jccmywjh7qb30txmda.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb4jccmywjh7qb30txmda.png" alt="Three tools read the same state directory and answer questions on three timescales: the statusline shows where things are right now, impact checks the blast radius before a change, retro shows the trend month by month" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How accurately the state files are written decides whether what these tools show is true. I'll come back to that at the end.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where are we now: the statusline and /pdlc-status
&lt;/h2&gt;

&lt;p&gt;Here is a statusline entry from a real project, with the stage labels translated (the current release prints them in Chinese):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;● PDLC console-p3 · PRD·Design·TDD·Impl·[Review]·Ship · →ship · 🤖 · ✓unit ✓lint ✓cov · ⏱9d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Left to right: the feature name; the six-stage track (PRD, design, TDD, implementation, review, ship) with the current stage highlighted; the next step; the run mode (🤖 autonomous loop, 👤 manual); the three check results; and how long the feature has sat in the current stage.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fike7cu4gdu99c9qi75um.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fike7cu4gdu99c9qi75um.png" alt="The six fields of one statusline entry: feature name, six-stage track, next step, run mode, check results, time in stage; below it, the full-line format used when a feature is blocked" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Three design choices in this one line are worth spelling out.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It doesn't show "step 4 of 6". A bug fix doesn't go through all six stages, so a counter would mislead. Instead it shows the fixed track and highlights where you are.&lt;/li&gt;
&lt;li&gt;The three checks only show by default in autonomous mode. In manual mode you're running the tests yourself and the ticks are noise. Their value is being able to tell at a glance whether an unattended loop is healthy.&lt;/li&gt;
&lt;li&gt;When a feature is blocked, the whole line changes format: &lt;code&gt;⛔ PDLC xxx blocked: needs a product decision · ⏱12m&lt;/code&gt;. A loop that has stopped and is waiting for a human must be the first thing you see. That is the statusline's main job.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One command turns it on: &lt;code&gt;/pdlc-settings statusline&lt;/code&gt;. It appends itself after whatever statusline command you already have and leaves the rest alone. &lt;code&gt;/pdlc-status&lt;/code&gt; is the command-line view of the same data: in progress, done, and suggested to-dos, plus a relation tree if the relation index exists. It verifies rather than just listing. When three features had sat at "review done, not shipped" for over ten days, it went to the CHANGELOG and the git tags to confirm that nothing had actually shipped. &lt;code&gt;--stale 3&lt;/code&gt; tabulates how many days each feature has been sitting.&lt;/p&gt;

&lt;p&gt;That is as far as a tool goes: it puts the problem in front of you. What to do about it is a person's call.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does a change touch: the relation graph
&lt;/h2&gt;

&lt;p&gt;Which feature extends, depends on, or replaces which: there are six relation types. Four are directed: &lt;code&gt;extends&lt;/code&gt;, &lt;code&gt;depends_on&lt;/code&gt;, &lt;code&gt;supersedes&lt;/code&gt;, &lt;code&gt;resolves&lt;/code&gt;. Two are symmetric: &lt;code&gt;conflicts_with&lt;/code&gt;, &lt;code&gt;relates_to&lt;/code&gt;. Nobody fills these in by hand. When &lt;code&gt;/pdlc-feature&lt;/code&gt; assigns a feature ID it scans the existing features, and &lt;code&gt;/pdlc-prd&lt;/code&gt; scans the requirements text for words like "based on", "extends", "depends on", and "replaces"; whatever it finds goes into the PRD and the state file with a reason attached. In one real project with three iterations, phase 2 and phase 3 both extend phase 1, and phase 1 extends the original MVP.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;rebuild&lt;/code&gt; once and it scans the state files, builds an index of nodes and edges, and draws a mermaid graph. The MVP predates the project's adoption of pdlc and has no state file. Rather than reporting a dangling reference, rebuild kept it as a historical terminal node.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F29k15l37ld00jdwiwoqm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F29k15l37ld00jdwiwoqm.png" alt="The example project's relation graph: phase 2 and phase 3 extend phase 1, phase 1 extends the MVP; running impact on phase 1, red marks the direct downstream features and green the historical node" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;impact&lt;/code&gt; is the reason the graph exists. Run it on phase 1 and the output has three tiers: 🔴 direct impact (phase 2 and phase 3), 🟡 indirect impact (anything one hop further; none here), 🟢 historical (the MVP, audit only). It also gives advice: phase 1 is already extended by two features that have passed review, so a change to it should be a new feature that &lt;code&gt;supersedes&lt;/code&gt; it, not an in-place edit, or the downstream review results become void.&lt;/p&gt;

&lt;p&gt;The other subcommands: &lt;code&gt;query&lt;/code&gt; shows one feature's inbound and outbound edges, &lt;code&gt;orphans&lt;/code&gt; lists features with no relations at all, and &lt;code&gt;validate&lt;/code&gt; checks five rules: dangling references, self-references, cycles, contradictory pairs, and whether symmetric relations are recorded on both sides. &lt;code&gt;set&lt;/code&gt; is the only one that writes state files: add a symmetric relation and both files get a line, then the index is rebuilt.&lt;/p&gt;

&lt;h2&gt;
  
  
  How did this stretch go: the retrospective
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;/pdlc-retro&lt;/code&gt; looks at the last 30 days by default and aggregates the history in the state files into a report: features delivered, self-check pass rate per stage, median stage duration, and sticking points, written to a monthly file under &lt;code&gt;docs/07_reviews/retro/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Pass rates from one real run: requirements, design, and TDD at 100%, implementation 93.8%, review 54.9%. The rate is the share of self-check items that passed. The forty-odd percent that didn't pass at review are the items flagged for a person to decide, about seven per feature.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3kjkw7ypc1qwsao10j2g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3kjkw7ypc1qwsao10j2g.png" alt="Retrospective for the example project: self-check pass rate and median duration for the five stages; human intervention is concentrated in review" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That number is right. The first four stages settle everything a machine can judge, and whatever it can't judge is left for review. A low review "pass rate" means the earlier stages did their job. If review also came out at 100%, I'd want to know whether it actually looked.&lt;/p&gt;

&lt;p&gt;Median durations: requirements 0.0 hours, design 0.1, TDD 0.6, implementation 0.9, review 5.0. Take the review figure with a grain of salt. It measures wall-clock time from entering review to finishing it, overnight hours included, not working time.&lt;/p&gt;

&lt;p&gt;How the report handles bad data is worth noting. One feature's review had a completion timestamp earlier than its implementation. Instead of producing a negative duration, the report dropped the sample and listed it separately as "data anomaly, check the write timing". Re-run with a seven-day window that contained no activity, and all four sections said "no data" and explained why. Same rule as the false greens in the last post: if it can't be judged, say so, and never paint it green.&lt;/p&gt;

&lt;h2&gt;
  
  
  The limit: they only show what was recorded
&lt;/h2&gt;

&lt;p&gt;All three tools only read state files; none of them checks the code. The state files are written by the AI at the end of each stage, and they drift. When they do, the tools don't fail; they quietly show one item less or count one stage less. The example project has two cases. The check keys: older features wrote &lt;code&gt;tests_green&lt;/code&gt;, newer ones use the standard &lt;code&gt;tests_pass&lt;/code&gt;, and the statusline only reads the standard set, so the older features' checks don't show. And the history has no start timestamps, so durations can only be computed from consecutive completion times. Relations are the same: they're recorded automatically once, at kickoff. If the requirements change later, you &lt;code&gt;set&lt;/code&gt; the new relation yourself.&lt;/p&gt;

&lt;p&gt;So the precondition for all three tools is treating the state files as data to be maintained: fields, timestamps, and relations written to spec.&lt;/p&gt;

&lt;h2&gt;
  
  
  Once you can see
&lt;/h2&gt;

&lt;p&gt;Back to the opening question: the AI pushes three features in an afternoon, so how does a person keep up? Each tool answers one question, where things are, what a change touches, how the stretch went, and all the answers come from the same state files, with no digging through documents and no guessing. They don't make decisions. Whether to push a stalled feature, whether to touch a baseline, how to schedule the items review left for a person: still a human call, now made with data in hand. When the statusline is missing an item or the retro is missing a stage, suspect the records first, then the tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next post
&lt;/h2&gt;

&lt;p&gt;With the three tools covered, the mechanics part of this series is done. Next time we go back to a real project and walk it from the first command to the last release, to see how all of this gets used once it's installed.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Want to try it&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/kanfu-panda/pdlc-skills/main/install.sh | bash &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--global&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The repo: &lt;a href="https://github.com/kanfu-panda/pdlc-skills" rel="noopener noreferrer"&gt;https://github.com/kanfu-panda/pdlc-skills&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If it's useful, a star goes a long way ⭐&lt;/p&gt;




&lt;p&gt;What's the longest any feature in your project has sat untouched? Comments welcome.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claudecode</category>
      <category>testing</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>How pdlc-skills Keeps Quality Up When AI Writes the Code</title>
      <dc:creator>kanfu-panda</dc:creator>
      <pubDate>Thu, 03 Sep 2026 15:32:08 +0000</pubDate>
      <link>https://dev.to/kanfu-panda/how-pdlc-skills-keeps-quality-up-when-ai-writes-the-code-42fk</link>
      <guid>https://dev.to/kanfu-panda/how-pdlc-skills-keeps-quality-up-when-ai-writes-the-code-42fk</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;The last post covered how the loop runs on its own. The faster it runs, the sharper an old question gets: &lt;strong&gt;who vouches for the quality of what the AI produces?&lt;/strong&gt; It doesn't get tired. In one afternoon it can write more code than a person can review in days. This post is about how I handle that in pdlc: not with one gate, but with a chain of seven links.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why quality matters more when AI writes the code
&lt;/h2&gt;

&lt;p&gt;Code quality used to rest on two things: the person writing it had a feel for whether it was right, and there wasn't so much of it that reviewers couldn't keep up. AI removes both at once.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It has no "feel for whether it's right."&lt;/strong&gt; Ask an AI to grade its own work and it grades generously. It isn't lying; it genuinely thinks it did fine. That's why in pdlc the model's self-check is recorded in its own column and never feeds into any stop-or-continue decision.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The volume changed too.&lt;/strong&gt; The unattended run from the last post finished a three-phase iteration in one afternoon: four backend API groups, three frontend pages, a full set of notification rules. That used to be days of work. Output sped up; "is this correct?" did not. Same eyes, same hours.&lt;/p&gt;

&lt;p&gt;That gap is the risk. The faster you go, the further a mistake travels before anyone notices. So quality assurance isn't the thing slowing you down; it's the brakes and steering that make the speed usable. And it clearly can't be a human reading every line, because that hands back the time you just saved.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short version: seven links, one chain
&lt;/h2&gt;

&lt;p&gt;I split quality into seven links:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Requirements → Design → TDD → Implementation → Unit tests → E2E → Review by a different AI&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first two are written by AI, reviewed by AI, and checked once by a human at the end. The middle four are enforced by machine with no room for argument: TDD sets the red light, implementation is judged by exit codes, unit tests have to be plentiful, E2E guards only the core flows. The last link hands review to a different AI. The links are in series, not in parallel: if one fails, the guarantees of the ones before it are worth less. Get the requirements wrong and the strictest testing only builds the wrong thing more solidly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flgvhiirt2ca178or7niq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flgvhiirt2ca178or7niq.png" alt="The seven links of the quality chain: requirements and design are written by AI, reviewed by AI and checked by a human; TDD, implementation, unit tests and E2E are enforced by machine; the final review goes to a different AI" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here they are in order.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links 1 and 2: requirements and design. AI writes, AI reviews, a human checks
&lt;/h2&gt;

&lt;p&gt;Counting requirements and design as quality control might seem odd, but they sit furthest upstream: they decide what every test after them is actually verifying.&lt;/p&gt;

&lt;p&gt;Both documents are written by AI. The PRD stage has an eight-point self-check: is the background and goal clear, are there enough user stories, are the acceptance criteria measurable, does the feature list carry priorities, and so on. Fail the self-check and you don't move to the next stage. That last item looks the least important; by the time we get to false greens you'll see it's the one that bites.&lt;/p&gt;

&lt;p&gt;Once written, a different AI reviews it first, and a human checks it last. The order matters. If a human had to write and proofread requirements and design from scratch, the faster the AI produced, the more the human would be the bottleneck, which is the gap we started with. &lt;strong&gt;The human's job is to check, not to execute.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But that check can't be skipped. Whether to build it, where the boundaries are, how to split it: those are judgment calls, and no command returns an exit code for them. That's why the autonomous loop from post 5 never touches these two links and only takes over &lt;code&gt;TDD → implement → review&lt;/code&gt;. What a machine can detect goes to the machine; what it can't stays with a person.&lt;/p&gt;

&lt;h2&gt;
  
  
  Link 3: TDD. Write the failing tests first
&lt;/h2&gt;

&lt;p&gt;Before any code, write a batch of tests that are guaranteed to fail. This isn't "we recommend writing tests first"; it's a hard requirement. And it buys something concrete: from this moment on, "is it done?" has an answer that doesn't depend on the model. Run the tests. Exit code 0 means done; anything else means not done.&lt;/p&gt;

&lt;p&gt;This gate only holds if the &lt;code&gt;test-commands.yml&lt;/code&gt; from the last post is in place. The verdict comes entirely from running commands. The model saying "I think it's good" doesn't count here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Link 4: implementation. Judged by exit codes only
&lt;/h2&gt;

&lt;p&gt;Now the code gets written. People assume this step can't be controlled: the AI writes it, and you can't watch every line. In fact it's the most tightly controlled step, because there's a check on the way in and another on the way out.&lt;/p&gt;

&lt;p&gt;The way in checks one thing: &lt;strong&gt;the relevant tests must exist, and they must be red right now.&lt;/strong&gt; This is one of pdlc's iron rules. If no tests are found, the implement command refuses to run and sends you back to TDD. "I'll write the code first and add tests later" isn't accepted.&lt;/p&gt;

&lt;p&gt;Writing the code has one rule: the minimum code that turns the tests green, then refactor under their protection. The rule targets the laziest route an AI can take. When a test fails, editing the test is always easier than fixing the code. So the implementation stage isn't allowed to touch test files, and pdlc's automated acceptance suite has an assertion for exactly that: a modified test file is an automatic fail.&lt;/p&gt;

&lt;p&gt;The way out has three checks: unit tests, coverage, lint. All three run real commands and read exit codes. Lint means zero warnings, not "fewer warnings than last time." The results go into the state file, and pdlc is explicit that these three fields may only hold command exit codes; the model's own assessment can't stand in for them. One failure and the stage isn't complete, and the flow doesn't advance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw7f9urnbibr2734m8oc3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw7f9urnbibr2734m8oc3.png" alt="Implementation and the code review that follows it: implementation requires red tests on the way in and three exit codes on the way out; code review only accepts green tests, flags what it can't fix for a human, and writes blocked when it hits a product decision" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Getting through that door isn't the end. The code goes to review next, and review has its own entry condition: if the tests aren't fully green, review doesn't start. Between implementation and review sit the next two links.&lt;/p&gt;

&lt;h2&gt;
  
  
  Link 5: plenty of unit tests, but they only prove the parts
&lt;/h2&gt;

&lt;p&gt;With those two gates in place, the next job is building up the unit tests. One of my larger projects has over 4,000 unit tests and 90%+ coverage. But at that scale I'm also clearer about their limit: unit tests prove each part is correct on its own. That's all they prove.&lt;/p&gt;

&lt;p&gt;There's a number people treat as insurance: coverage. It measures "this line was executed," not "this logic is correct." This test maxes out a function's coverage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;calculates order total&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;calcTotal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBeDefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function ran, the branches ran, the report shows green. Whether the total is right, this test says nothing. Nobody is cheating here; coverage can only see execution, never assertions. The more you use it as an acceptance criterion, the more it drifts toward "make the number look good."&lt;/p&gt;

&lt;p&gt;So I still write 90%, but what it proves is "the tests are spread wide," not "the quality is high." For that, you need the next link.&lt;/p&gt;

&lt;h2&gt;
  
  
  Link 6: E2E for the core flows
&lt;/h2&gt;

&lt;p&gt;The same project has just over a hundred E2E tests for its core business flows. Four thousand to a hundred: the ratio itself tells you how the work is divided.&lt;/p&gt;

&lt;p&gt;Production incidents are rarely one function computing the wrong value. Usually it's several individually correct parts that don't fit together: state didn't get passed, the order was wrong, the two sides read a boundary differently. Unit tests can't see this by design. They mock the dependencies away, and the problem lives between the dependencies.&lt;/p&gt;

&lt;p&gt;So the core flows need E2E. I use Playwright driving Chrome against real pages: actually click through, actually wait for the API, actually check what rendered. It's slow and flakier, but it's the only thing that answers "does this flow still work today?"&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Futm4d1xbcdziuby28don.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Futm4d1xbcdziuby28don.png" alt="Unit tests mock dependencies away and verify a single part; E2E runs real pages and real APIs and verifies the whole flow still works once the parts are connected" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/pdlc-quality&lt;/code&gt; checks E2E bluntly: every core flow has to map to a test in the mapping file, and that test has to show as passed in this run's actual results. One missing is red. "I think another test already covers that flow" isn't allowed to fill the gap; that's exactly the subjective judgment being removed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Link 7: a different AI reviews every stage
&lt;/h2&gt;

&lt;p&gt;The last link is review, and it happens more than once: requirements review, design review, code review, each its own gate.&lt;/p&gt;

&lt;p&gt;The key word is &lt;em&gt;different&lt;/em&gt;. As noted at the start, an AI grades itself generously, and the AI that just designed something and is then asked to review it is no exception. So I start each review separately: a new session, a subagent running a different AI, sometimes a different model. A reviewer with clean context sees what the author can't. The author's mental footnotes ("I considered that, here's why") don't exist in the new session, so whatever the design document actually fails to say finally shows.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5ltx3k27yfizc1j9ljek.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5ltx3k27yfizc1j9ljek.png" alt="Self-review in the same session is grading your own homework; a subagent running a different AI has clean context and actually finds things" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Code review is the most detailed of the three. It checks the implementation against the design document item by item: do the API parameters and return shapes match, is error handling consistent, is there string-built SQL, are there missing auth checks, list endpoints without pagination, N+1 queries. What it can fix on the spot, it fixes. What it can't, such as architectural trade-offs or disputes about business logic, goes into the report marked for a human.&lt;/p&gt;

&lt;p&gt;The reviewer is still an AI, not a person. Human time shouldn't go to "read the whole thing and look for problems"; an AI can do that. People handle only the few points it reports and isn't sure about. When review hits something that needs a human decision, pdlc stops and writes &lt;code&gt;blocked&lt;/code&gt;. The "three config fields with no backend consumer" case from post 5 was caught exactly this way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Seven links in place. Now guard against false greens
&lt;/h2&gt;

&lt;p&gt;Chain complete, report all green: can you trust it? Not yet. The dangerous state was never red; red is at least honest. The dangerous state is a false green: everything looks fine while something underneath has already gone wrong.&lt;/p&gt;

&lt;p&gt;There are two kinds, and neither is fixed by trying harder.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One: the list rots.&lt;/strong&gt; The E2E coverage matrix compares against a "core flows list," and someone has to remember to update the list. Add a new core flow, forget to add it to the list, and the matrix stays green. It has turned "we don't know" into "we've covered it." That's worse than no check at all, because it comes with a green report that lets you keep being wrong in comfort. The fix is a forced reconciliation against the PRD on every run: in the PRD but not on the list means red, directly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two: "can't be judged" gets read as "no problem."&lt;/strong&gt; Remember the least impressive item on the PRD self-check, that feature lists must carry priorities? The reconciliation keys off those P0/P1 marks. If a PRD never had them, extraction yields an empty set; compare that to the list and there's zero drift, so the report says "reconciliation passed." What actually happened is that the entire PRD never entered the check. Old PRDs are the usual victims, and old PRDs are exactly the ones behind the flows already in production.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F26huv5rbfncjb1le3xtt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F26huv5rbfncjb1le3xtt.png" alt="Two sources of false green: list rot lets new flows slip through silently, and a PRD without priority marks never enters the check at all; both produce a green report" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So the rule changed: any PRD that skipped reconciliation for lack of priority marks must be listed separately as a warning, and the reconciliation item can't be marked passed, only "⚠️ no drift, but N PRDs could not be judged." It's the same principle as post 3's "no command to run means leave the cell empty, never fill in pass": if you can't measure it, write "not measured," and never let a blank pose as green.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this doesn't catch
&lt;/h2&gt;

&lt;p&gt;Seven links plus false-green guards still leave things out of reach.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If the requirements themselves are wrong, it's green anyway.&lt;/strong&gt; The chain guarantees "what you meant to build was built solidly," not "this was the right thing to build."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It doesn't guarantee you actually set everything up.&lt;/strong&gt; I have my own counterexample: a smaller project where unit tests and E2E both run, but coverage tooling was never configured. With a link missing, you don't get to say "quality is assured." Installing pdlc doesn't make you compliant; it lists what needs doing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A human still signs off.&lt;/strong&gt; &lt;code&gt;/pdlc-quality&lt;/code&gt; only turns measured data into a report you can verify. It doesn't rule on pass or fail; whether to ship is a person's call. If the party writing the code is also the party ruling on it, everything that put the machine in charge of the verdict is pointless.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this buys
&lt;/h2&gt;

&lt;p&gt;Back to the gap from the start: AI made output faster and judgment didn't keep up. What these seven links do, in the end, is speed up judgment until it keeps pace.&lt;/p&gt;

&lt;p&gt;For me personally, the result isn't "no bugs"; nobody can promise that. The result is &lt;strong&gt;I'm willing to let it run by itself&lt;/strong&gt;. That unattended afternoon in the last post finished a three-phase iteration with me stepping in three times. Not luck: I know a mistake will get stopped at some link instead of waiting for a user in production to find it.&lt;/p&gt;

&lt;p&gt;The AI will still make the mistakes it was going to make. What the chain does is bring them into the open early, while each one is still a bug and cheap to fix, not after it has become an incident.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next post
&lt;/h2&gt;

&lt;p&gt;Next time, a change of direction: &lt;strong&gt;visibility&lt;/strong&gt;. How to record dependencies between features, how to tell what a change will touch, whether you can see the state of the project at a glance, and how to keep retrospectives around.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Want to try it&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/kanfu-panda/pdlc-skills/main/install.sh | bash &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--global&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The repo: &lt;a href="https://github.com/kanfu-panda/pdlc-skills" rel="noopener noreferrer"&gt;https://github.com/kanfu-panda/pdlc-skills&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If it's useful, a star goes a long way ⭐&lt;/p&gt;




&lt;p&gt;This seven-link setup is what I've arrived at on my own projects; it won't fit everyone. If you run a leaner combination, or think one of these links can go, I'd like to hear about it in the comments.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claudecode</category>
      <category>testing</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>How pdlc-skills Runs Unattended</title>
      <dc:creator>kanfu-panda</dc:creator>
      <pubDate>Mon, 31 Aug 2026 14:17:05 +0000</pubDate>
      <link>https://dev.to/kanfu-panda/how-pdlc-skills-runs-unattended-3k4a</link>
      <guid>https://dev.to/kanfu-panda/how-pdlc-skills-runs-unattended-3k4a</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;The last post got the first feature through. The next problem shows up fast: it stops at every stage waiting for your nod, so you're still parked in front of the screen. &lt;strong&gt;Can it go round after round on its own while you do something else?&lt;/strong&gt; It can. But "running on its own" and "asking you at every step" are further apart than they look.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  That run wasn't a loop at all
&lt;/h2&gt;

&lt;p&gt;I've run a full loop on my own machine before, and it went smoothly — 60-odd PRs pushed through in one stretch, and it never once turned around to ask me something. So when I ran it again on a different machine, something felt off almost immediately.&lt;/p&gt;

&lt;p&gt;That time I'd asked the AI to "advance through the stages in a loop" &lt;strong&gt;inside a single session&lt;/strong&gt;. It was moving forward, all right, but it came back to me at every step: is this design OK? Should I keep going? Want me to continue?&lt;/p&gt;

&lt;p&gt;What I said at the time was roughly: &lt;strong&gt;why is your loop different from the one I've been using? A normal loop doesn't turn around and ask me this stuff — it just keeps working until the job is done.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The problem wasn't that it asked. It's that &lt;strong&gt;everything it asked about was already settled&lt;/strong&gt;. The PRD was settled, the design was settled, how the tests would be written was settled — and it still came back for confirmation. That kind of check-in does nothing but tie me to the chair. I can't go do anything else, because I don't know whether the next interruption is three minutes away or thirty.&lt;/p&gt;

&lt;p&gt;On the surface it was looping. In practice I was the one jogging alongside it.&lt;/p&gt;

&lt;p&gt;That's what made it click: &lt;strong&gt;there's exactly one line between a fake loop and a real one — who holds control of the loop.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1c4gbdbz04mrw2kqqxvs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1c4gbdbz04mrw2kqqxvs.png" alt="Fake loop vs real loop across four points: loop written inside the session or driven by code, whether each round starts on clean context, whether trouble means asking a human or hitting a guardrail, and whether the stop decision reads the model's mood or a file on disk" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It has nothing to do with how smart the model is, and nothing to do with whether the prompt says "please work autonomously, don't interrupt me." If control lives in the model's willingness, the loop is fake. If it lives in code, it's real.&lt;/p&gt;

&lt;h2&gt;
  
  
  One feature: one command is enough
&lt;/h2&gt;

&lt;p&gt;The hard prerequisite first: &lt;strong&gt;PRD and design must be signed off by a human. Nothing enters the loop until the design is final.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The loop speeds up the &lt;code&gt;TDD → implement → review&lt;/code&gt; convergence stretch. It does not speed up figuring out what to build. Whether this feature is worth doing, where its boundaries sit, how it splits — those are judgement calls, and no command can hand you an exit code for them.&lt;/p&gt;

&lt;p&gt;Once that's settled, the rest is one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/pdlc-loop-run F20260825-XXXXXX
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It picks up from whatever stage the feature is parked at and drives &lt;code&gt;tdd → implement → review&lt;/code&gt; forward until review passes or it stops on a block. Each stage goes to a brand-new subagent; when that returns, the loop reads the state machine and decides whether to advance, stop, or hand back to you. Four steps by default.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This assumes the &lt;code&gt;test-commands.yml&lt;/code&gt; from the last post is already in place.&lt;/strong&gt; Stop decisions rest on exit codes from real command runs — no file, no commands to run. Skip that step and everything here spins in place.&lt;/p&gt;

&lt;p&gt;What the command takes off your hands is exactly what I fumbled the first time I tried this by hand: &lt;strong&gt;the decision about whether to go one more round is taken away from the model.&lt;/strong&gt; Three design points hold it up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc5nvx4wog419ltbkrtl2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc5nvx4wog419ltbkrtl2.png" alt="One round in three beats: ask what's next (output filtered through a whitelist), do that step (clean context), read the state file to decide whether to stop; the in-plugin runner and an external script keep the same beat" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One: control flow is code, not something in the model's head.&lt;/strong&gt; Each round asks the model two things only — which command comes next, and getting that step done. The answer to the first has to pass a whitelist that accepts five tokens and nothing else; a single extra word of explanation gets filtered out. &lt;strong&gt;Rambling gets the model nowhere, because nothing downstream reads it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two: every stage starts on clean context.&lt;/strong&gt; The previous stage's hesitation, misreadings and self-inflicted detours don't carry over. Everything that has to survive across stages lives in the state file on disk — the one from post 3. &lt;strong&gt;Sessions can die; state doesn't.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Three: the stop decision reads a file, not an opinion.&lt;/strong&gt; After each step the loop doesn't ask "do you think that passed?" — it reads &lt;code&gt;last_phase_result.ok&lt;/code&gt;, the on-disk result of actually running the commands. Post 3 covered the two slots in that file; &lt;strong&gt;the stop decision uses only the one that holds real run results&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A dozen features: now you want an external script
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;/pdlc-loop-run&lt;/code&gt; runs inside the plugin, which suits one feature's short convergence. You can also write your own bash loop — every round gets a genuinely separate process, so context isolation is stricter and long runs hold up better — but &lt;strong&gt;running one feature point that way isn't worth much on its own&lt;/strong&gt;: it does the same job as &lt;code&gt;/pdlc-loop-run&lt;/code&gt; with a different process boundary.&lt;/p&gt;

&lt;p&gt;The script's real place is one layer out. Post 3 sketched the two-level structure: split the work into N reasonably independent feature points, and have the outer layer start a loop for each, every one in its own worktree. The outer layer starts loops, collects results and queues the next batch — it doesn't push any single feature through its stages. What this post adds is how that outer layer is arranged: &lt;strong&gt;batched by dependency&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;An earlier project of mine had something like a dozen feature points, and I ran them in three batches: &lt;strong&gt;foundation first, then the ones other work depends on, then everything mutually independent all at once.&lt;/strong&gt; Each batch runs in parallel internally; when a batch finishes I check it, then the next batch starts, until the whole set has converged.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu9gf1mtx4q3sjjsp0pat.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu9gf1mtx4q3sjjsp0pat.png" alt="A dozen feature points in three dependency batches: foundation, then depended-upon features, then mutually independent ones all at once; parallel within a batch, with a human check between batches" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The order can't be flipped. Without the foundation everything after it rests on nothing; until the depended-upon work is done, whatever depends on it just waits. That last batch waits on nobody, so opening it all at once is the cheapest — feature IDs use date-plus-timestamp precisely so parallel runs don't collide.&lt;/p&gt;

&lt;p&gt;To be clear: &lt;strong&gt;this batching layer is mine, not something pdlc provides.&lt;/strong&gt; What pdlc gives you is "how one feature point drives itself to done," plus the &lt;code&gt;/pdlc-relate&lt;/code&gt; dependency graph to see who depends on whom. How to split the batches, and how many go in each, stays a judgement call — and stays outside the loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four guardrails, and I've watched every one of them work
&lt;/h2&gt;

&lt;p&gt;Anyone can write guardrails into a doc. What's worth looking at is whether they've ever actually fired.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpi6s5cxafk1kj0wk8ayb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpi6s5cxafk1kj0wk8ayb.png" alt="What each of the four guardrails does and the time it actually fired: hard budget twice, fail-stop as everyday backstop, blocked escalation once, step ceiling once" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ① Hard budget: &lt;code&gt;--max-budget-usd&lt;/code&gt; per round
&lt;/h3&gt;

&lt;p&gt;Put a spend ceiling on each round's process; hit it and the process is &lt;strong&gt;killed outright&lt;/strong&gt;, no negotiation. This one is required for the external-script form.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It fired twice in a single run.&lt;/strong&gt; I set the first round's ceiling at 5 and implementation got cut off partway; I checked the half-finished work on disk, confirmed it could be resumed, raised the ceiling to 8 and ran again — capped again; 12 finally got it through.&lt;/p&gt;

&lt;p&gt;The thing worth saying about being cut off is this: &lt;strong&gt;what's on disk is intact.&lt;/strong&gt; The documents landed, the state machine kept its ledger, and what I lost was "this round didn't finish," not "start over." Writing to disk plus keeping a ledger is what turns a blunt process kill into a pause you can resume from.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6g5mo8l2b0nej4xbwdk5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6g5mo8l2b0nej4xbwdk5.png" alt="One budget-capped round: the process is cut off, but the documents and the state machine on disk are intact, so the next round resumes in place instead of starting over" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One honest note so those numbers don't get misread: &lt;strong&gt;5, 8 and 12 are ceilings I set per round, not what I actually paid.&lt;/strong&gt; I'm on a subscription billed by weekly volume, and per-token prices differ between vendors anyway. Treat those three as a rough sense of scale, not a price list — if you want real cost, look at token consumption and estimate it against your own vendor's published pricing.&lt;/p&gt;

&lt;h3&gt;
  
  
  ② and ④: stop when it's not ok, stop when the steps run out
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;fail-stop&lt;/strong&gt; covers the failure that's easiest to miss: &lt;strong&gt;a failed stage being treated as "done" by the next round&lt;/strong&gt;. Once that happens, every later round rests on a false premise, and the further it runs the worse it gets — all with a green light on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The step ceiling&lt;/strong&gt; guards against oscillation: break it, fix it, break it again, every round looking like work while nothing moves. Four steps by default = three convergence stages plus one for slack. I set it to 1 once, conservatively, and it stopped exactly as promised.&lt;/p&gt;

&lt;h3&gt;
  
  
  ③ blocked escalation: it really did stop when it should have
&lt;/h3&gt;

&lt;p&gt;If review turns up something that needs a product decision, it writes &lt;code&gt;blocked&lt;/code&gt; into the state machine, stops, and waits for a person.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The time this one fired is what convinced me the whole thing was trustworthy.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;During review it found that the three config fields added that round had &lt;strong&gt;no consumer anywhere in the backend&lt;/strong&gt;. The code was correct and the tests were green — this wasn't a bug, it was a product-level gap: should the fields be cut, or was the pipeline left unfinished? &lt;strong&gt;That's not a call the AI gets to make for me.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It didn't guess, and it didn't quietly delete the fields to keep the tests green — it wrote &lt;code&gt;blocked&lt;/code&gt;, stopped, and handed the question back. I decided to keep the fields and finish the pipeline, then let it continue. The follow-up surprised me: on the re-review it also fixed 2 genuine bugs in that pipeline implementation.&lt;/p&gt;

&lt;p&gt;It stopped where it should have, and it checked what it should have. That's what I wanted from it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What that run produced
&lt;/h2&gt;

&lt;p&gt;The work was a three-phase iteration on a console project: 4 backend endpoint groups, 3 frontend pages, plus a notification ruleset. &lt;code&gt;TDD → implement → review&lt;/code&gt; ran unattended end to end, with &lt;strong&gt;301 tests passing and coverage above 87%&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Human involvement came to three moments total: two verification calls when extending the budget, plus the one product decision at the block.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxf94sf8o1si3fwbsfmld.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxf94sf8o1si3fwbsfmld.png" alt="An afternoon on a timeline: after design sign-off, TDD, implementation and review run unattended; implementation is budget-capped twice, review stops once for a human decision, and the run ends at review-complete handed back to a person" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's an afternoon's worth of work, and I don't want to make it sound bigger than it was. But during the loop it was completely silent toward me — what I came back to wasn't a queue of "shall I do the next one?" but a terminal state. &lt;strong&gt;It isn't that it runs fast. It's that it doesn't need me present.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the line between human and machine sits
&lt;/h2&gt;

&lt;p&gt;The test hasn't changed since post 2: &lt;strong&gt;only hand the loop what can find its own errors.&lt;/strong&gt; Draw that line and two things never get handed over:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Figuring out what to build (human decision required).&lt;/strong&gt; PRD and design have to clear a human. That's a precondition for entering the loop, not a suggestion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shipping.&lt;/strong&gt; The loop's terminal state is review-complete; it stops there and a person decides whether to ship. &lt;code&gt;--autonomous&lt;/code&gt; has no effect on ship or deploy — once it's out, it's out.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That marks off which work can be handed over. There's a companion question: &lt;strong&gt;once it's handed over, what keeps it from going off the rails?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When post 1 covered prompt engineering, I gave that layer a ceiling: it's a soft constraint, the model may not fully follow you, and you may not notice at the time. Back then it was just a principle. This run gave it a concrete instance.&lt;/p&gt;

&lt;p&gt;Writing "go easy, watch the consumption" into a prompt is easy, but it belongs to the prompt layer — it can steer, it can't guarantee. &lt;code&gt;--max-budget-usd&lt;/code&gt; belongs to the process layer; it doesn't read what you wrote, it just cuts at the ceiling. Both overruns on this run were stopped by the latter, not talked down by the former.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Anything that steers but doesn't guarantee eventually has to move up a layer.&lt;/strong&gt; This time it moved to a process argument.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next up
&lt;/h2&gt;

&lt;p&gt;If this post leaves you one thing, I'd like it to be this: &lt;strong&gt;to tell a real loop from a fake one, look at one thing only — whether the control flow lives in code or in the model's willingness.&lt;/strong&gt; A loop that turns around to ask you isn't a loop.&lt;/p&gt;

&lt;p&gt;Next post is about &lt;strong&gt;quality&lt;/strong&gt;: the pipeline runs fast and unattended, so why should anyone trust what comes out of it? What the red-test gate, the review gate and coverage each hold back — and what they still don't catch together.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Want to try it&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/kanfu-panda/pdlc-skills/main/install.sh | bash &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--global&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The repo: &lt;a href="https://github.com/kanfu-panda/pdlc-skills" rel="noopener noreferrer"&gt;https://github.com/kanfu-panda/pdlc-skills&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If it's useful, a star goes a long way ⭐&lt;/p&gt;




&lt;p&gt;I wrote these four guardrails straight off the record of that run, including the parts where it got cut off and the part where it got stuck. If it left you thinking "all right, this can actually be trusted," let me know. And if you've run loops yourself — smooth ones or crooked ones — the comments are open — happy to talk it through.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claudecode</category>
      <category>agents</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Getting pdlc-skills Running in Your Own Project</title>
      <dc:creator>kanfu-panda</dc:creator>
      <pubDate>Sun, 30 Aug 2026 01:26:24 +0000</pubDate>
      <link>https://dev.to/kanfu-panda/getting-pdlc-skills-running-in-your-own-project-4713</link>
      <guid>https://dev.to/kanfu-panda/getting-pdlc-skills-running-in-your-own-project-4713</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;The first three posts were blueprints: what each layer is, where it lands, how they interlock. This one turns the other way — &lt;strong&gt;putting the blueprint onto your own project&lt;/strong&gt;. By the end you should be able to install it, know which command to start from, and get one feature through. There's one step in the middle that gets skipped constantly; I'll pull it out on its own, because skipping it makes the whole design from last post collapse.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That covers most of the theory. Now let's look at how pdlc-skills actually runs inside a real project.&lt;/p&gt;

&lt;p&gt;A lot of people have the same question first: do I need to backfill the tests? Write all the docs? If it's a codebase that's been running for two or three years, piled high, that nobody quite dares touch — does onboarding mean paying off the technical debt on day one?&lt;/p&gt;

&lt;p&gt;Here's the answer up front: &lt;strong&gt;none of that. Installing is one line, about a minute.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What will actually stall you is something else — the "so now what" right after install. The first project I onboarded, I sat staring at a screen full of commands starting with &lt;code&gt;/pdlc-&lt;/code&gt;, genuinely unsure which one to type. This post answers that "so now what": which command to start from, and which step you absolutely cannot skip.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing: one line, two landing spots
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Global — every project on this machine can use it&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/kanfu-panda/pdlc-skills/main/install.sh | bash &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--global&lt;/span&gt;

&lt;span class="c"&gt;# Project-scoped — only this one repo&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/kanfu-panda/pdlc-skills/main/install.sh | bash &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--project&lt;/span&gt; /path/to/my-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first three posts always gave the global line, because it's the shortest and hardest to get wrong. Here's &lt;strong&gt;when project-scoped is worth it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The only difference between the two is where it lands: &lt;code&gt;~/.claude/plugins/pdlc/&lt;/code&gt; or &lt;code&gt;&amp;lt;project&amp;gt;/.claude/plugins/pdlc/&lt;/code&gt;. What that buys you is real, though — project-scoped installs make &lt;strong&gt;the version travel with the repo&lt;/strong&gt;. Someone else clones it and gets the same version you have; and when you've got several projects open at once, one global upgrade doesn't move all of them at the same time.&lt;/p&gt;

&lt;p&gt;One person, one machine, not many projects? Go global, don't overthink it.&lt;/p&gt;

&lt;p&gt;Confirm it actually took, two steps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; ~/.claude/plugins/pdlc/          &lt;span class="c"&gt;# where the global install lands&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &amp;lt;project&amp;gt;/.claude/plugins/pdlc/  &lt;span class="c"&gt;# where the project-scoped one lands&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seeing &lt;code&gt;skills/&lt;/code&gt; &lt;code&gt;references/&lt;/code&gt; &lt;code&gt;VERSION&lt;/code&gt; in there means you're good. Then type &lt;code&gt;/pdlc-&lt;/code&gt; in Claude Code and the dropdown should list 38 commands. If it does, you're installed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3ndvtdyxkqsm3zoar3uf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3ndvtdyxkqsm3zoar3uf.png" alt="Two landing spots: global goes in your home directory and covers every project, project-scoped goes in the repo and covers only that one" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Which starting point are you?
&lt;/h2&gt;

&lt;p&gt;38 commands spread out in front of you is intimidating, but &lt;strong&gt;you only need to recognize three the first time&lt;/strong&gt;. Which one depends on what you're holding:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Your starting point&lt;/th&gt;
&lt;th&gt;First command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Brand-new project, no code yet&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/pdlc-bootstrap&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Existing project, plenty of code&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/pdlc-adopt scan&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Already onboarded, day-to-day work&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/pdlc-feature&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Brand-new project&lt;/strong&gt; uses &lt;code&gt;/pdlc-bootstrap&lt;/code&gt;: give it one line of description and it picks a stack, generates the directory skeleton and draft documents. Good for when "I want to build an X" is still just an idea.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Existing project&lt;/strong&gt; is where most people are, and it's the row I most want you to notice: the first command is &lt;code&gt;/pdlc-adopt scan&lt;/code&gt;, and &lt;strong&gt;scan is entirely read-only&lt;/strong&gt; — it surveys your stack, service layout, database, existing tests, and produces an onboarding report plus a health check, &lt;strong&gt;without changing a single byte&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I think that design is worth more than the feature itself. Letting AI touch a live legacy codebase makes anyone hesitate. So it splits "look" and "touch" into two commands: run &lt;code&gt;scan&lt;/code&gt;, read the report, and only if you like what you see do you run &lt;code&gt;/pdlc-adopt init&lt;/code&gt; to generate the baseline docs. The cost of trying it drops to zero.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx4c0c1pfveig3ldaqq4o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx4c0c1pfveig3ldaqq4o.png" alt="Three starting points each take their own first command, then merge into the same main flow" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't skip this: settle what "passing" means, first
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;This is the most important section in the post.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Last post covered the two boxes in the state file: the first box only takes &lt;strong&gt;exit codes from commands that really ran&lt;/strong&gt;, and the model's self-assessment sits in a second box, never part of the stop decision.&lt;/p&gt;

&lt;p&gt;Which raises a question — &lt;strong&gt;where do those commands come from?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The answer is &lt;code&gt;/pdlc-test-setup&lt;/code&gt;. It does four things: detect the stack, verify each command really runs, write them into &lt;code&gt;docs/00_standards/test-commands.yml&lt;/code&gt;, then scaffold the test directories and wire up local hooks.&lt;/p&gt;

&lt;p&gt;The repo is blunt about what this step is for: the whole thing hinges on "checks only accept exit codes, never the model's self-assessment," &lt;strong&gt;but until this point nothing has helped you stand that file up — and without it, the entire objectivity chain is empty&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It carries one non-negotiable rule: &lt;strong&gt;every command written into that file must have been really run once, with the exit code seen with your own eyes&lt;/strong&gt;. Guesses don't get written. The reasoning is the line I find most worth repeating —&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A command that "looks right but doesn't run" is &lt;strong&gt;worse than leaving it empty&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Empty, and everything downstream knows this stage has nothing to judge, so it stays honestly empty. A fake command that doesn't run hands every stage false checks — and the report still comes out green. There's a mirror image of the same idea: &lt;strong&gt;the most dangerous "auto-fix" is quietly blanking a check that was standing but broke&lt;/strong&gt; — the gate loosens on the spot and you can't tell.&lt;/p&gt;

&lt;p&gt;So what happens if you skip it? No commands to run → the first box must be left empty by rule → the stop decision has nothing to stand on → what you thought was "objective verification" has been the model feeling good about itself the whole time. &lt;strong&gt;The foundation for last post's design is this one step.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Worth mentioning: this file goes stale — scripts get renamed, tooling gets replaced, sub-projects come and go. You don't have to watch it; downstream stages will tell you when a command won't run, and you run &lt;code&gt;/pdlc-test-setup --refresh&lt;/code&gt; when you see the prompt.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8elvinfmrrgnrg3ucdom.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8elvinfmrrgnrg3ucdom.png" alt="Once test-commands.yml stands up, last post's " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Running your first feature
&lt;/h2&gt;

&lt;p&gt;With the foundation in place, starting work takes one sentence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/pdlc-feature add phone verification to login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From there it works down PRD → design → TDD → implementation → review, stopping and handing off at each stage. Fixing a bug is the same shape with &lt;code&gt;/pdlc-fix&lt;/code&gt;; to see where things stand, &lt;code&gt;/pdlc-status&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Day to day, those three are all you use.&lt;/strong&gt; The other 35 are for when you want fine-grained control — rerun just the design stage, do a single code review, add a database design. Go find them then.&lt;/p&gt;

&lt;h2&gt;
  
  
  What shows up on disk, and what belongs in git
&lt;/h2&gt;

&lt;p&gt;After one round, a batch of directories appears under &lt;code&gt;docs/&lt;/code&gt;: requirements, design, testing, deployment, review each have their place, plus a &lt;code&gt;docs/.pdlc-state/&lt;/code&gt; holding one JSON per feature.&lt;/p&gt;

&lt;p&gt;Those first ones are documents; committing them is your call. But one of them &lt;strong&gt;has to go in&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;docs/.pdlc-state/&lt;/code&gt; should be committed to git. Don't put it in &lt;code&gt;.gitignore&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It looks like a cache — a dot-directory full of machine-read JSON, easy to wave off. It isn't a cache, it's &lt;strong&gt;the handoff&lt;/strong&gt;. Change sessions, change machines, hand the work to someone else: the only thing that can say "this feature is at this stage, and the last one passed" is that directory. Not in git means losing your memory every time you reopen a session; on a team, nobody else can see where you are.&lt;/p&gt;

&lt;p&gt;The repo calls it a "project delivery audit record." Treat it as an audit record and you stop wanting to ignore it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fawby7xrfqemepubrodtq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fawby7xrfqemepubrodtq.png" alt="The docs directory after a run, with the state-machine directory marked as must-commit" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Two rules for onboarding an existing project
&lt;/h2&gt;

&lt;p&gt;If you came in from a legacy codebase, two rules are worth knowing on their own, because they decide whether this is realistic at all:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One: documents only, no code changes.&lt;/strong&gt; Not a line of business code is touched during onboarding — it only reverse-generates baseline documents.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two: incremental onboarding.&lt;/strong&gt; Existing code is marked "baselined" wholesale, and &lt;strong&gt;only new features go through the full flow&lt;/strong&gt;. You are not asked to clear the historical debt first.&lt;/p&gt;

&lt;p&gt;The second one is the load-bearing rule. I've watched plenty of process tools die on day one: you onboard, it reports several hundred existing violations, and one look at that number is enough to make people quit. Fence the existing code off and govern only what's new — that's what gives the process a chance of surviving to day two.&lt;/p&gt;

&lt;h2&gt;
  
  
  When not to use it
&lt;/h2&gt;

&lt;p&gt;Worth naming the boundary too. One-off scripts, throwaway demos, pure documentation repos — don't bother, the process doesn't pay for itself there. This is for projects that have to live a long time, get handed over, and answer for their quality.&lt;/p&gt;

&lt;p&gt;The test is simple: &lt;strong&gt;will anyone still open this project three months from now?&lt;/strong&gt; Yes, it's worth it. No, don't bother.&lt;/p&gt;

&lt;h2&gt;
  
  
  Walk it once
&lt;/h2&gt;

&lt;p&gt;Compressed into a single list you can follow directly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install&lt;/strong&gt;: &lt;code&gt;curl … | bash -s -- --global&lt;/code&gt; (swap in &lt;code&gt;--project &amp;lt;path&amp;gt;&lt;/code&gt; for multiple projects or team work)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify&lt;/strong&gt;: &lt;code&gt;ls ~/.claude/plugins/pdlc/&lt;/code&gt;, then type &lt;code&gt;/pdlc-&lt;/code&gt; in Claude Code and check for the 38 commands&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Know your starting point&lt;/strong&gt;: new project &lt;code&gt;/pdlc-bootstrap&lt;/code&gt;; existing project &lt;code&gt;/pdlc-adopt scan&lt;/code&gt; for the report, then &lt;code&gt;/pdlc-adopt init&lt;/code&gt; if you like it&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stand up the foundation&lt;/strong&gt;: &lt;code&gt;/pdlc-test-setup&lt;/code&gt; — &lt;strong&gt;don't skip this one&lt;/strong&gt;, it decides whether every later "did it pass" is real or fake&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start work&lt;/strong&gt;: &lt;code&gt;/pdlc-feature &amp;lt;your one-line requirement&amp;gt;&lt;/code&gt;, with &lt;code&gt;/pdlc-status&lt;/code&gt; any time to see where it is&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commit&lt;/strong&gt;: include &lt;code&gt;docs/.pdlc-state/&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Step 4 is the only one that looks postponable and isn't. The rest just go in order.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next up: can it keep going on its own?
&lt;/h2&gt;

&lt;p&gt;Installed, started, foundation laid, first feature through — that's the line, end to end. If this post leaves you one thing, I'd like it to be this: &lt;strong&gt;settle what "passing" means before you start running&lt;/strong&gt; — get that order backwards and every bit of automation afterwards is spinning in place.&lt;/p&gt;

&lt;p&gt;Next is the heavy one in this series: &lt;strong&gt;it's installed and running, so can it go round after round on its own, without you watching?&lt;/strong&gt; That post covers the convergence loop's mechanics, its contracts, and four non-negotiable guardrails — including the time I got caught myself: talking the model out of burning tokens didn't work, and what finally caught it was a hard budget.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Want to try it&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/kanfu-panda/pdlc-skills/main/install.sh | bash &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--global&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The repo: &lt;a href="https://github.com/kanfu-panda/pdlc-skills" rel="noopener noreferrer"&gt;https://github.com/kanfu-panda/pdlc-skills&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If it's useful, a star goes a long way ⭐&lt;/p&gt;




&lt;p&gt;I wrote this in the order I actually onboarded my own projects, and spent extra words on the steps that tripped me up. If you get through it, tell me; if you get stuck somewhere, tell me that too and I'll fold it into the next version.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claudecode</category>
      <category>agents</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>How Do the Three Engineering Paradigms Interlock in pdlc-skills?</title>
      <dc:creator>kanfu-panda</dc:creator>
      <pubDate>Sun, 23 Aug 2026 09:13:40 +0000</pubDate>
      <link>https://dev.to/kanfu-panda/how-do-the-three-engineering-paradigms-interlock-in-pdlc-skills-38id</link>
      <guid>https://dev.to/kanfu-panda/how-do-the-three-engineering-paradigms-interlock-in-pdlc-skills-38id</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Last post ended with a yardstick: to tell whether a tool's three layers are genuinely joined, check whether they share one piece of state. This post cashes that in — &lt;strong&gt;the three layers never call each other, not once&lt;/strong&gt;. They hand off through a single file on disk. There's also a side effect I didn't see coming: because that file is split per feature, the pipeline doesn't only run one line downward, it fans out sideways and runs several at the same time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Last post placed each layer inside &lt;a href="https://kanfu-panda.github.io/pdlc/" rel="noopener noreferrer"&gt;pdlc-skills&lt;/a&gt;: the rules every command shares are the prompt layer, the stretch that advances on its own is the loop layer, the stage order and the relation graph are the graph layer.&lt;/p&gt;

&lt;p&gt;But knowing who governs what is not the same as knowing how they fit together.&lt;/p&gt;

&lt;p&gt;Following that thought, the most direct move is to go into the code and find the call — where Graph calls Loop, where Loop calls the prompt layer. You won't find it. There is not one line of code in which these three layers reference each other.&lt;/p&gt;

&lt;p&gt;So how do they end up working together?&lt;/p&gt;

&lt;h2&gt;
  
  
  The key is timing, not calling
&lt;/h2&gt;

&lt;p&gt;The three layers don't need to know each other, because &lt;strong&gt;they don't act at the same moment&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;When it acts&lt;/th&gt;
&lt;th&gt;What it governs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Graph&lt;/td&gt;
&lt;td&gt;at stage &lt;strong&gt;boundaries&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;whether you may enter the next step&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prompt&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;inside&lt;/strong&gt; one invocation&lt;/td&gt;
&lt;td&gt;what the model sees this time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Loop&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;between&lt;/strong&gt; stages&lt;/td&gt;
&lt;td&gt;whether another round is needed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;An analogy: Graph checks tickets at the door, the prompt layer does the talking inside the hall, Loop stands outside counting how many sets are left. The three never speak to each other. They go by the same scoreboard.&lt;/p&gt;

&lt;p&gt;That scoreboard is the file on disk.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F75os8d8ks7ux6deteci8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F75os8d8ks7ux6deteci8.png" alt="Three swim lanes on a timeline: Graph appears only at stage boundaries, the prompt layer expands inside each invocation, Loop sits between two stages" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Following one feature all the way through
&lt;/h2&gt;

&lt;p&gt;Enough abstraction. Here's a real feature from start to convergence, one beat at a time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Beat one: the opening move.&lt;/strong&gt; A new feature has just been declared and there is nothing on disk yet. Exactly one command can pick it up — write the requirements. Why? Because every other command declares which prior document it needs: design needs requirements, tests need design, and not one of those preconditions is satisfied. &lt;strong&gt;This isn't advice to "write requirements first," it's that without the prior artifact you cannot get through the door.&lt;/strong&gt; That's Graph doing its job, and its job is only "do I let you in."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Beat two: doing the work.&lt;/strong&gt; Once you're through the door, Graph steps off and the floor belongs to the prompt layer. In this one invocation, the model sees more than the command's own text — it also sees the full set of rules shared by every command: artifacts must land on disk, self-check before handing off, fix once and don't recurse. Those rules live in one place and expand in at call time, rather than being copied into each command.&lt;/p&gt;

&lt;p&gt;What comes out isn't free-form prose either. The filename, the directory, the sections — all fixed; and the document carries a small identity header at the top saying which feature it belongs to, which stage it's in, and which document came before it. I won't unpack the format here; what matters is what it buys you: &lt;strong&gt;the artifact carries its own coordinates&lt;/strong&gt;, so you can walk backwards from it all the way to the original requirement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Beat three: closing out by writing to disk.&lt;/strong&gt; This is the critical beat. Finishing the main work isn't the end of it — the command has to record a line in that file: I've finished this stretch, here's how it went, here's who picks it up next. The file sits on disk, &lt;strong&gt;one per feature&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Beat four: the stop decision.&lt;/strong&gt; Only now does the loop appear, and it reads nothing but that file — not the code, not the artifacts, not the chat log. It reads and emits one result: which command runs next, or "done," or "blocked." The outer script takes that result, runs the next command, and we're back at beat three.&lt;/p&gt;

&lt;p&gt;Once review is complete the loop stops, emits "done," and waits for a human. Shipping and deploying are never inside the loop — once it's out, you can't pull it back, and what it touches is real users in production.&lt;/p&gt;

&lt;p&gt;So the whole chain has exactly three handoffs, and what crosses each one is &lt;strong&gt;a name, not a call&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what Graph hands the invocation: "here's the stretch you're on";&lt;/li&gt;
&lt;li&gt;what the invocation hands the disk: "I'm done, here's how it went";&lt;/li&gt;
&lt;li&gt;what the disk hands the loop: "keep going or not."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of the three ever touches another.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsvxrvos3nufu3ticsm34.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsvxrvos3nufu3ticsm34.png" alt="Three handoff points: Graph hands over which stretch to work on, the stage writes its result to disk on close, and the loop reads from disk whether to keep going" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The one design in that file that matters most
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What was actually run and what the model says about itself go in two separate boxes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first box takes only results from commands that really ran: did tests pass, is coverage high enough, is lint clean — all booleans translated from exit codes. If a stage has no command to run at all (requirements and design produce documents only), the box stays empty; you may not fill in "passed" because "I feel this went well."&lt;/p&gt;

&lt;p&gt;The second box is the model's own self-check, recording only how many items failed. &lt;strong&gt;Reference only. Never part of the stop decision.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Where's the difference? The loop's stop decision reads the first box and nothing else. Which means the model's self-assessment is excluded from the stop path at the level of the data structure, not by a line asking it to please report honestly. Whatever it writes in the second box cannot change whether this round stops.&lt;/p&gt;

&lt;p&gt;That's what "the three layers share one piece of state," from last post, actually comes down to.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkdie8pfk3ft2ec02t0k9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkdie8pfk3ft2ec02t0k9.png" alt="The two boxes in the state file: one holds only results from commands that really ran and decides whether to stop, the other holds the model's self-check for reference only" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The real loop has two levels
&lt;/h2&gt;

&lt;p&gt;Time to admit something: the loop drawn above is only the &lt;strong&gt;inner loop&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When I actually put this to work, the shape looks like this —&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Lead agent: overall design → split into N mutually independent features
    ↓
Outer script: start one loop per feature
    ↓
Inner loop × N (each on its own feature)   ← running at the same time
    ↓
Each stops at "review complete" or "blocked" → a human collects the results and decides on shipping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A lead agent does the overall design and splits the work into a set of mutually independent features. The outer script starts an inner loop per feature. Those loops run forward in parallel, each stopping at its own endpoint. Finally a human gathers up the N results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What makes it safe to run them at the same time?&lt;/strong&gt; The precondition is that what you split out really is &lt;strong&gt;relatively independent features&lt;/strong&gt; — no dependencies between them, or there's no parallelism to speak of. Given that, the state files are split per feature too: one feature, one file, no cross-dependency.&lt;/p&gt;

&lt;p&gt;Feature IDs use "date + hours-minutes-seconds" rather than the day's sequence number. The reason spelled out in the repo: when several people or several AIs start work at the same time, each one grabbing "today's highest number plus one" is guaranteed to collide, and colliding state files with the same name have to be renumbered by hand. Switch to the timestamp of the moment of creation and independent copies almost never collide. This ID format was built for parallelism from the start — I just didn't think of it as a piece of design at the time, only as a small trick against collisions.&lt;/p&gt;

&lt;p&gt;The code has to be isolated too: each feature's inner loop runs in its own git worktree, out of everyone's way, with artifacts going through separate PRs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So why must the split stay with a human, or with the lead agent?&lt;/strong&gt; Last post gave the test: hand the loop whatever can find its own errors, keep the rest with people. "How many features should this batch of requirements split into, and which depend on which" — get it wrong and no command reports an error. It's a judgment call, not a check. So it lives outside the loop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The two levels also end differently&lt;/strong&gt;: the inner loop ends at review complete, the outer one ends when all N have converged. And shipping remains the single human gate — no matter how many ran at once, the person is still the one who presses it.&lt;/p&gt;

&lt;p&gt;I've run this for real on a command-line tool project of my own. How to get it running, how the guardrails are set, what an overnight run actually produces — later posts cover that. This one only draws the shape.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6tjy90ezc1dwuixaoysy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6tjy90ezc1dwuixaoysy.png" alt="Two-level loop: the lead agent splits work into N relatively independent features, the outer script starts an inner loop each in its own worktree, and everything converges on a human shipping gate" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next up: getting it running in your own project
&lt;/h2&gt;

&lt;p&gt;If this post leaves you with one line, I'd like it to be this: &lt;strong&gt;the three layers interlock not because they call each other, but because they write into different boxes of the same file.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The interface is a name, not a function — which is why changing one layer doesn't ripple into another, and why this pipeline can be copied sideways several times over.&lt;/p&gt;

&lt;p&gt;I deliberately didn't drill down here: which fields that state file actually has, how the loop's guardrails and limits are set, how parallel runs are closed out — all of that is for later posts. &lt;strong&gt;Get the shape clear first, then look at the parts.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That covers it: what the three layers are, where each one lands, and how they interlock — three posts. Next post turns in a different direction: &lt;strong&gt;in your own project, how to install it, how to start, and how to bring an existing codebase in&lt;/strong&gt; — from this post's blueprint to the first command that actually runs in your terminal.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Want to try it&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/kanfu-panda/pdlc-skills/main/install.sh &lt;span class="se"&gt;\&lt;/span&gt;
  | bash &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--global&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The repo: &lt;a href="https://github.com/kanfu-panda/pdlc-skills" rel="noopener noreferrer"&gt;https://github.com/kanfu-panda/pdlc-skills&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If it's useful, a star goes a long way ⭐&lt;/p&gt;




&lt;p&gt;That two-level diagram is how I actually run this; it lived only in my head until I drew it. If it gave you a concrete picture, a reaction helps. And if someone near you is working out how to get AI to do several things at once, pass it along.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claudecode</category>
      <category>agents</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Why Does pdlc-skills Fit All Three Engineering Paradigms So Naturally?</title>
      <dc:creator>kanfu-panda</dc:creator>
      <pubDate>Thu, 13 Aug 2026 22:56:54 +0000</pubDate>
      <link>https://dev.to/kanfu-panda/why-does-pdlc-skills-fit-all-three-engineering-paradigms-so-naturally-50b6</link>
      <guid>https://dev.to/kanfu-panda/why-does-pdlc-skills-fit-all-three-engineering-paradigms-so-naturally-50b6</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Once the three concepts are sorted out, the next question is the interesting one: is there anything real where all three layers grew in together? This post holds one up against them — &lt;a href="https://kanfu-panda.github.io/pdlc/" rel="noopener noreferrer"&gt;pdlc-skills&lt;/a&gt;, the thing I've been building. Conclusion first: the fit &lt;strong&gt;is a coincidence&lt;/strong&gt;. But there's a reason behind the coincidence, and that reason is what this post is about.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Last time we separated three terms that get mixed up constantly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;prompt engineering governs how you talk to the model this one time;&lt;/li&gt;
&lt;li&gt;loop engineering governs how many rounds a thing repeats and what condition stops it;&lt;/li&gt;
&lt;li&gt;graph engineering governs which steps along the path can't be skipped.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They're not on the same level. It isn't a choice of one — they stack.&lt;/p&gt;

&lt;p&gt;Which raises the obvious question: all three sound reasonable, but &lt;strong&gt;is there anything real where all three layers grew in together&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;Let's hold one up against them — pdlc-skills, the thing I've been building.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is pdlc-skills?
&lt;/h2&gt;

&lt;p&gt;It's a &lt;a href="https://docs.anthropic.com/" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt; plugin, and what it does fits in one line: &lt;strong&gt;it turns AI-written code from something you chatted about into something that lands on disk.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Install it and you get 38 slash commands, one per stage of the workflow. The one you'll use most is &lt;code&gt;/pdlc-feature&lt;/code&gt; — start a new feature with it and the AI works down the line: PRD → design → TDD → implementation → review → ship, stopping to hand off at each stage.&lt;/p&gt;

&lt;p&gt;Three things separate it from "hey, build me this feature":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Artifacts must land on disk.&lt;/strong&gt; PRD, design, review notes are real files under &lt;code&gt;docs/&lt;/code&gt;, not a passage in a chat transcript.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every feature carries state.&lt;/strong&gt; Which stage it's at, whether the last one passed — all recorded on disk. Pick it up in a new session and it knows where it is.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests must be red first.&lt;/strong&gt; No failing test, no implementation. That's a hard gate, not a suggestion.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MIT licensed. It's most complete on Claude Code; the same methodology runs on other AI coding tools through adapters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Its origins are unremarkable
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;I didn't design these three layers in. I hadn't even heard the terms "loop engineering" or "graph engineering" when I built it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It just follows the product development lifecycle that software engineering already had. Requirements, design, tests, implementation, review, ship — that flow has been lying around the industry for decades, and there's nothing new in it. All I did was translate it for the AI: what each stage does, what it produces, what counts as passing, written out as commands, so the AI works down the flow instead of wherever its attention lands.&lt;/p&gt;

&lt;p&gt;One rule came with it: &lt;strong&gt;every stage has to write something to disk.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PRDs go to &lt;code&gt;docs/01_requirements/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Designs go to &lt;code&gt;docs/02_design/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Review notes go to &lt;code&gt;docs/07_reviews/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Each feature also gets its own state file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All plain text. You can open any of it, and you can &lt;code&gt;git diff&lt;/code&gt; exactly what the AI did this round.&lt;/p&gt;

&lt;p&gt;Then these new terms started circulating. I held them up against what I'd built and found matches everywhere — not because I built toward them, but because it had grown that way on its own.&lt;/p&gt;

&lt;p&gt;So let's go layer by layer, in order: prompt, loop, graph.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔵 Prompt layer: matches "one copy of the spec"
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it corresponds to in the flow.&lt;/strong&gt; Software engineering has an old rule: there's one copy of the spec, not one version here and a different one there. Applied to pdlc, that means the rules every command has to honor — artifacts land on disk, self-check before handoff, repair only once — can't be written out separately inside each command.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it's actually done.&lt;/strong&gt; Common rules are pulled into fragments and expanded into each skill at build time. Currently that's &lt;strong&gt;13 fragments compiled into 36 of the 38 skills&lt;/strong&gt; (the two without them are &lt;code&gt;pdlc-loop-next&lt;/code&gt; and &lt;code&gt;pdlc-status&lt;/code&gt; — too light to share anything). The six invariants — files must land on disk, each stage must be recorded (appending to history), tests must be red first, self-check is mandatory, repair happens once, and state must advance (&lt;code&gt;current_stage&lt;/code&gt; has to actually change, so an outer loop can't spin on a stale value) — live in one of those fragments. Change it once, everything changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv4uzae1somos85e7w2qh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv4uzae1somos85e7w2qh.png" alt="13 shared fragments expand into 36 skills at build time; one edit propagates everywhere" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which layer it matches.&lt;/strong&gt; Prompt engineering governs what the model sees this time. Nothing about that changed here — it's just managed the way you'd manage code: extract the common part, expand at build time, single source of truth.&lt;/p&gt;

&lt;p&gt;The new term is prompt engineering; the old rule is single source of truth. Same thing, two vocabularies — &lt;strong&gt;that's coincidence number one&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🟢 Loop layer: matches the TDD red-light gate
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it corresponds to in the flow.&lt;/strong&gt; TDD is old news in software engineering, and the rule is one line: write a failing test, then write the implementation, until the test goes green. pdlc copies that straight across — no red test, no implementation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What that rule brings with it.&lt;/strong&gt; Writing tests before implementation means "is it done" gets an answer that has nothing to do with the model: run it, exit code 0 means it passed, anything else means it didn't.&lt;/p&gt;

&lt;p&gt;What makes that answer valuable is that it doesn't route through the model. Ask the model that wrote the code to grade its own code and it will grade generously and consistently — not because it's lying, but because it genuinely thinks the code is fine. So in pdlc the model's self-check is recorded separately, treated as a reference, and &lt;strong&gt;never as grounds for stopping&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which is why this stretch can go to a loop&lt;/strong&gt;: &lt;code&gt;tdd → implement → review&lt;/code&gt; runs on its own until review passes. The PRD and design before it can't — whether to build this feature at all, how many modules to split it into, where the boundary goes, are judgment calls, and no command returns an exit code for those. Judgment calls stay with the human. That line is drawn clearly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9dwhsivfqq1swfw983jr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9dwhsivfqq1swfw983jr.png" alt="Which stretch of the flow can be handed to a loop and which must stay with a human, with the criteria alongside" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which layer it matches.&lt;/strong&gt; Loop engineering has a line you can treat as an axiom: a loop is a task with a check; a task without a check is just hope. TDD is exactly that check.&lt;/p&gt;

&lt;p&gt;I do TDD because software engineering says test before you write, &lt;strong&gt;not to prepare a straightedge for a loop&lt;/strong&gt;. But the straightedge was sitting right there — &lt;strong&gt;coincidence number two&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Guardrails, step limits, budgets — I'm saving those for post five.&lt;/p&gt;

&lt;h2&gt;
  
  
  🟣 Graph layer: matches stage gating and review
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it corresponds to in the flow.&lt;/strong&gt; The phrase "lifecycle" carries order in it: requirements before design, design before implementation, review after implementation, ship after review. In software engineering that order isn't advice, it's discipline — the industry has already paid decades of tuition for skipping steps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it's actually done.&lt;/strong&gt; Each stage writes its state to disk on completion; the next stage reads that state first and won't start unless the preconditions hold. No skipping tests to implement. No shipping without review.&lt;/p&gt;

&lt;p&gt;Beyond the vertical order there's a horizontal layer: how features relate to each other. &lt;code&gt;/pdlc-relate&lt;/code&gt; records those relationships explicitly, with &lt;strong&gt;six directed edge types&lt;/strong&gt; — extends, depends on, supersedes, resolves, conflicts with, relates to. Then &lt;code&gt;impact &amp;lt;feature-id&amp;gt;&lt;/code&gt; gives you the blast radius in one command: 🔴 directly depends on it, 🟡 one hop away, 🟢 already finished, ignore it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1x1rjzg6nxrmrc02kkg9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1x1rjzg6nxrmrc02kkg9.png" alt="The vertical axis is a linear pipeline with gates; the horizontal one is the actual directed graph" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And here's the honest part.&lt;/strong&gt; That vertical line isn't a graph, strictly speaking. It's a linear pipeline with a few gates: no conditional branches, no parallel nodes, no rolling back to an arbitrary point — nearly nothing that makes a graph a graph. The thing that actually qualifies is the horizontal dependency graph: directed, traversable, cycle-detectable, and able to catch references pointing at features that don't exist.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which layer it matches.&lt;/strong&gt; So why does the vertical count as the graph layer at all? Because &lt;strong&gt;the essence of the graph layer isn't "drawn as a graph," it's negative constraint&lt;/strong&gt; — declaring which paths are off limits. To reuse the line from last time: the track doesn't plan your trip, it just makes certain directions impossible.&lt;/p&gt;

&lt;p&gt;Stage gates constrain order, the dependency graph constrains blast radius; both do the same job. And "advance by stage, review at key points" was written into the flow by software engineering a long time ago — &lt;strong&gt;coincidence number three&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fes3t7711v1aa0ddvr57x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fes3t7711v1aa0ddvr57x.png" alt="Six directed edge types form the graph; impact marks the blast radius by distance" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Three coincidences stop being a coincidence
&lt;/h2&gt;

&lt;p&gt;One match could be luck. Three matches is worth asking about.&lt;/p&gt;

&lt;p&gt;My answer: &lt;strong&gt;these two things were solving the same set of problems all along.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The three paradigms are new vocabulary, distilled over the last couple of years out of AI agent practice. The software engineering flow was beaten into shape over decades by real projects. And the mistakes humans and AI make on engineering work overlap heavily — working wherever attention lands, keeping several copies of the spec, declaring something done without verifying it, changing one thing without knowing what else breaks. The rules the old flow set up to treat those still work when you translate them onto an AI.&lt;/p&gt;

&lt;p&gt;So the constraints the new vocabulary describes had already been written down, in another language:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What the three paradigms say&lt;/th&gt;
&lt;th&gt;What software engineering already required&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Prompt engineering: unify the context&lt;/td&gt;
&lt;td&gt;One copy of the spec, don't scatter it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Loop engineering: needs an objective check&lt;/td&gt;
&lt;td&gt;Write the test before the implementation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Graph engineering: apply negative constraints&lt;/td&gt;
&lt;td&gt;Advance by stage, review at key points&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;That's what "fits naturally" means here&lt;/strong&gt;: I didn't fit three layers into it. The old flow already had those three layers — nobody had called them by these three names before.&lt;/p&gt;

&lt;p&gt;There's one more thing, which the old flow didn't have and which showed up on its own during implementation: &lt;strong&gt;the three layers ended up sharing one thing — the state on disk.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The graph reads it to know which step it's on,&lt;br&gt;
the loop reads it to know whether this round advanced anything,&lt;br&gt;
the prompt reads it to get the context for this call.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9moyof47loq4o11axng1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9moyof47loq4o11axng1.png" alt="The three layers share one state file on disk" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Which hands you a ready-made test: &lt;strong&gt;to judge whether a tool's three layers are genuinely joined, check whether they share one state.&lt;/strong&gt; Sharing is integration; each keeping its own is three mechanisms living in the same repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next up: when does each one actually kick in?
&lt;/h2&gt;

&lt;p&gt;If this post leaves you with one line, I'd like it to be this: &lt;strong&gt;if you want AI to do engineering work, you'll get further picking up the engineering process you already have than inventing a new framework.&lt;/strong&gt; That process isn't new, but the ailments it treats, AI has too.&lt;/p&gt;

&lt;p&gt;Now that we know where each layer landed, the next question is: &lt;strong&gt;in one real feature, when does each of them actually kick in?&lt;/strong&gt; Next post follows a single feature from start to finish, marking the timeline for all three layers and how they hand off to each other.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Want to try it&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/kanfu-panda/pdlc-skills/main/install.sh &lt;span class="se"&gt;\&lt;/span&gt;
  | bash &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--global&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Project page: &lt;a href="https://kanfu-panda.github.io/pdlc/" rel="noopener noreferrer"&gt;kanfu-panda.github.io/pdlc&lt;/a&gt; · Source: &lt;a href="https://github.com/kanfu-panda/pdlc-skills" rel="noopener noreferrer"&gt;github.com/kanfu-panda/pdlc-skills&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If it's useful, a star goes a long way ⭐&lt;/p&gt;




&lt;p&gt;If this gave you a concrete picture of how the three layers land, a reaction or a follow helps. And if someone near you is working out how to get AI to follow a process, pass it along.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claudecode</category>
      <category>agents</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Prompt Engineering, Loop Engineering, Graph Engineering: What Are They?</title>
      <dc:creator>kanfu-panda</dc:creator>
      <pubDate>Sun, 09 Aug 2026 04:19:57 +0000</pubDate>
      <link>https://dev.to/kanfu-panda/prompt-engineering-loop-engineering-graph-engineering-what-are-they-40i2</link>
      <guid>https://dev.to/kanfu-panda/prompt-engineering-loop-engineering-graph-engineering-what-are-they-40i2</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Prompt engineering, loop engineering, graph engineering — these three keep landing in the same comparison table, as if you had to pick one. But they don't operate at the same level. Sorting that out is worth more than mastering any one of them. This post isn't about any specific tool. It covers what each layer actually governs, where each one hits its ceiling, and ends with three questions that tell you which layer your problem belongs to.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Three terms, three separate origins
&lt;/h2&gt;

&lt;p&gt;These three came from completely different places, so let's start there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt engineering&lt;/strong&gt; got renamed somewhere along the way. Early on the discussion was about phrasing — what persona to assign, which magic words to use. Then people realized phrasing wasn't what decided the outcome; what the model got to see was. Hence the more accurate label going around now: context engineering.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Loop engineering&lt;/strong&gt; spread through the community on the back of Ralph-style setups. The mechanics are almost disappointingly simple: a one-line &lt;code&gt;while&lt;/code&gt; loop that feeds the same instruction to the model over and over, lets the tests decide right from wrong, and after enough rounds the version that passes acceptance simply surfaces.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Graph engineering&lt;/strong&gt; arrived with orchestration frameworks like LangGraph, which argue for drawing an agent's execution path explicitly — who hands off to whom, whether you can go back, where it has to stop.&lt;/p&gt;

&lt;p&gt;Three separate threads, eventually shoved into the same table for comparison. The table is exactly where things go wrong — these aren't the same kind of thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧱 They aren't on the same level
&lt;/h2&gt;

&lt;p&gt;The relationship isn't side-by-side. It's &lt;strong&gt;stacked&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;What it governs&lt;/th&gt;
&lt;th&gt;Granularity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Graph engineering&lt;/td&gt;
&lt;td&gt;How paths are organized&lt;/td&gt;
&lt;td&gt;Stage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Loop engineering&lt;/td&gt;
&lt;td&gt;How iteration converges&lt;/td&gt;
&lt;td&gt;Round&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prompt engineering&lt;/td&gt;
&lt;td&gt;How a single exchange goes&lt;/td&gt;
&lt;td&gt;Token&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2jbaihg9j2ndh0708nux.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2jbaihg9j2ndh0708nux.png" alt="Graph on top, Loop in the middle, prompt at the bottom, with control granularity narrowing from stage to token" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One thing has to be said right here, or you fall into the next trap: &lt;strong&gt;the stack being real doesn't mean every layer is required.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once "the standard three-layer architecture" lodges in your head, every task starts looking like it needs all three. In practice, plenty of systems that work well have only one or two:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Shape&lt;/th&gt;
&lt;th&gt;When it looks like this&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Prompt only&lt;/td&gt;
&lt;td&gt;One-shot classification, extraction, rewriting — any orchestration is a net loss&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prompt + Loop&lt;/td&gt;
&lt;td&gt;Iterate against tests; the path was never drawn at all&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prompt + Graph&lt;/td&gt;
&lt;td&gt;The path can be fully enumerated; no autonomous iteration needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;All three&lt;/td&gt;
&lt;td&gt;Production-grade engineering workflows&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Anthropic's principle in &lt;em&gt;Building effective agents&lt;/em&gt; is a practical one: start with the simplest solution, and only add complexity when it demonstrably improves things.&lt;/p&gt;

&lt;p&gt;So the right mental model isn't "a three-layer architecture." It's — &lt;strong&gt;three optional nested layers. Start at the bottom by default, and understand that going up costs you something.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo6hff5z576l5777ywmvl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo6hff5z576l5777ywmvl.png" alt="Four common shapes: prompt only, prompt plus loop, prompt plus graph, and all three, each with a typical task" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🔍 Layer by layer: what each one actually governs
&lt;/h2&gt;

&lt;p&gt;Four things per layer below: what it is, how it's done, one thing people get backwards, and where the ceiling is.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prompt engineering: deciding what the model sees this time
&lt;/h3&gt;

&lt;p&gt;It stopped being about "phrasing things nicely" a while ago. What you're really managing is which things the model gets to see this time, and which it doesn't.&lt;/p&gt;

&lt;p&gt;The reason it evolved that way is straightforward: once a task spans multiple rounds of reasoning, a well-turned sentence stops being enough, and the job shifts to managing the whole context state — system instructions, tool definitions, external data, message history, all of it.&lt;/p&gt;

&lt;p&gt;In practice there are only a handful of moves. The system prompt needs to sit at the right altitude: specific enough to actually steer behavior, without hard-coding every situation — rules that are too granular start contradicting each other the moment something unforeseen shows up, and rules that are too vague say nothing at all. Tool descriptions need to make clear what each tool is for; the more overlap between tools, the more often the model picks wrong. Agree on the output format up front so you're not writing regexes later. Give a diverse handful of examples rather than piling up edge cases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What people get backwards&lt;/strong&gt;: longer context isn't better. The fuller you pack it, the more the middle gets diluted — that's a real, measurable decay, not the model "not being smart enough." Attention is a budget, and where you spend it is a tradeoff, not a "more is safer" situation. Working out what the model doesn't need to see this time is often easier than working out what to say.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ceiling&lt;/strong&gt;: it's a soft constraint. The model may not follow you exactly, and you may not be able to tell at the time.&lt;/p&gt;

&lt;p&gt;This layer's biggest strength and biggest problem are the same fact — one edited sentence takes effect immediately, which also means you're relying on the model's willingness.&lt;/p&gt;

&lt;h3&gt;
  
  
  Loop engineering: a task, plus one check
&lt;/h3&gt;

&lt;p&gt;There's a line here you can treat as an axiom:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A loop is a task with a check. A task without a check is just hope.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ralph's shape came up earlier: it's that one &lt;code&gt;while&lt;/code&gt; line. But the real design isn't in the loop — &lt;strong&gt;it's in the files around it&lt;/strong&gt;, three of them, each doing one job. A spec, stating what this project should end up being and what's off limits. A progress list, recording what's done and what's next. And one instruction, fed in verbatim every round, telling the model: read the other two first, then pick one thing and do it. The loop itself is trivial; getting those three files right is the hard part.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What people get backwards&lt;/strong&gt;: the context is wiped clean every round — the model has no memory of what it did last time. That sounds like a defect. It's a feature. Amnesia guarantees every round starts from a clean slate, so a wrong interpretation from one round doesn't get carried the rest of the way. The price is that anything that has to survive across rounds must live on disk — that progress list isn't a note for humans, it's the model's only memory going into the next round.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where the stop signal comes from&lt;/strong&gt;: how does a loop know it's done? It needs a signal something can decide automatically — test exit codes, compiler output, type checks. "Looks fine to me" doesn't count, because you can't put that in a conditional.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it typically crashes&lt;/strong&gt;, two ways. One is spinning: every round the model feels like it did something, nothing actually moves, and tokens burn with nothing to show. The other is redoing work: it doesn't find what the last round already built, assumes it isn't there, and builds it again — like a contractor who doesn't see yesterday's pipe, breaks up the floor, and lays it a second time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ceiling&lt;/strong&gt;: a loop with no verification signal is mass-producing garbage. And its failures are the hardest to catch — it keeps running, it's just heading the wrong way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Graph engineering: two different things with the same name
&lt;/h3&gt;

&lt;p&gt;There's an ambiguity to clear up first. "Graph" refers to two completely different things here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Orchestration graphs&lt;/strong&gt;: the LangGraph kind, drawing which path the flow takes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Knowledge graphs&lt;/strong&gt;: the GraphRAG / code-relationship kind, drawing how entities relate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Same word, different objects. This post is about the first one. The second gets its own post — number seven in this series.&lt;/p&gt;

&lt;p&gt;What an orchestration graph does is move "what order does this work go in" out of your head and onto paper: who picks up whose output, which step can be sent back, which step has to stop and wait for a human to nod.&lt;/p&gt;

&lt;p&gt;There are five common shapes, each fitting a class of work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sequential&lt;/strong&gt;: one step after another. Writing code works this way — design first, then tests, then the implementation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Routing&lt;/strong&gt;: classify first, then decide who handles it. Tickets come in, get sorted, refunds go down the refund path, outages down the outage path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parallel&lt;/strong&gt;: independent pieces run at once, then get merged. Have the same diff reviewed separately for security, performance, and readability, then combine the notes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orchestrator with workers&lt;/strong&gt;: one splits and assigns, several put their heads down and do it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evaluator-optimizer&lt;/strong&gt;: run the output through a review; if it fails, send it back.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Real systems are basically these five in combination. You don't need to invent new ones.&lt;/p&gt;

&lt;p&gt;Drawing the graph has two benefits people overlook. One is &lt;strong&gt;recoverability&lt;/strong&gt; — every node can be checkpointed, so a crash resumes from the last checkpoint instead of the top. The other is &lt;strong&gt;auditability&lt;/strong&gt; — afterwards you can explain why it took that path, which matters when someone's going to ask.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What people get backwards&lt;/strong&gt;: it dictates which paths are off limits, not how to do the work. More on that below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ceiling&lt;/strong&gt;: it can only express what you thought of in advance. Anything requiring judgment on the spot, anything you haven't seen before — the graph is useless. There's also a hidden cost: once drawn, the graph becomes a liability, and reality shifting means redrawing it. Redrawing costs a lot more than editing a sentence, so it's worth planning before you start.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk3parjhn5s4wavvn3clt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk3parjhn5s4wavvn3clt.png" alt="A quick-reference card with one definition, one representative practice, and one ceiling per layer" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🏠 The same thing, told as a renovation
&lt;/h2&gt;

&lt;p&gt;Let's run all three through one analogy:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;What it maps to in a renovation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Prompt engineering&lt;/td&gt;
&lt;td&gt;How you tell the contractor what you want&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Loop engineering&lt;/td&gt;
&lt;td&gt;Do it → inspect → fails → redo → inspect again&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verification signal&lt;/td&gt;
&lt;td&gt;The inspector's straightedge, spirit level, flood test&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Graph engineering&lt;/td&gt;
&lt;td&gt;The trade sequence (plumbing → waterproofing → flood test → tiling → carpentry → paint)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Human checkpoint&lt;/td&gt;
&lt;td&gt;The owner showing up to sign off at key moments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context wiped each round&lt;/td&gt;
&lt;td&gt;A new contractor showing up every morning&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three sentences for the three personalities:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A prompt is the brief.&lt;/strong&gt; "North-facing wall in the main bedroom, off-white, two coats, tape the edges." Costs nothing, works immediately — but the contractor may decide close enough is close enough, and you won't catch it on the spot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A loop is the redo mechanism.&lt;/strong&gt; Briefing alone doesn't get you there; you need inspection. The key word isn't "redo," it's the straightedge — redoing without one is just doing it twice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A graph is the trade sequence.&lt;/strong&gt; It won't tell you what color the wall should be. It just makes "tiling before waterproofing" impossible as a matter of process.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdxxhg16nc8rtq4l3cjbe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdxxhg16nc8rtq4l3cjbe.png" alt="The renovation flow mapped onto the three layers: briefing, redo-and-inspect, and the trade sequence" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One line for how the three divide the work: &lt;strong&gt;sequence rules out what you can't do, redoing forces it up to standard, the brief decides how it actually gets done.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚖️ Three personalities, three ways to crash
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Prompt engineering&lt;/th&gt;
&lt;th&gt;Loop engineering&lt;/th&gt;
&lt;th&gt;Graph engineering&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Who's in control&lt;/td&gt;
&lt;td&gt;The model&lt;/td&gt;
&lt;td&gt;The model (you only set the stop condition)&lt;/td&gt;
&lt;td&gt;You (you draw the path, the model fills it in)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Determinism&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Lowest&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Up-front investment&lt;/td&gt;
&lt;td&gt;Minimal&lt;/td&gt;
&lt;td&gt;Low, but you need a verification setup first&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unit cost&lt;/td&gt;
&lt;td&gt;1x&lt;/td&gt;
&lt;td&gt;4x, 15x for multi-agent&lt;/td&gt;
&lt;td&gt;2–3x, but fewer detours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debuggability&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;Worst&lt;/td&gt;
&lt;td&gt;Best&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical failure&lt;/td&gt;
&lt;td&gt;The model doesn't comply&lt;/td&gt;
&lt;td&gt;Drifts and nobody notices&lt;/td&gt;
&lt;td&gt;Wrong graph, or too rigid&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;A note on the cost row: roughly 4x for agents and 15x for multi-agent come from Anthropic's public write-up; the 2–3x for graphs is a rough figure circulating in public material. These are order-of-magnitude references, not measurements.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The row worth sitting with is the last one. &lt;strong&gt;The three failure modes are nothing alike&lt;/strong&gt;: a prompt failure you can see — it didn't comply, it's right there. A loop failure you can't see — it's still running, just pointed the wrong way. A graph failure you can't change — the graph is set and reality moved.&lt;/p&gt;

&lt;p&gt;The latter two are far harder to deal with, and they're precisely the new problems you acquire by adding layers. That's what "going up costs you something" means in concrete terms.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpjubwounz5h449oazpjb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpjubwounz5h449oazpjb.png" alt="The three layers compared on control, determinism, cost, debuggability, and typical failure" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🚧 Two things people get backwards
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A graph doesn't plan; it constrains negatively
&lt;/h3&gt;

&lt;p&gt;It's easy to read the stack as a chain of command: graph plans, loop executes, prompt implements. But the graph says nothing about how to do the work. All it declares is "you don't skip tests and go straight to implementation." Which modules this design splits into, which file to write first — that's the actual planning, and it happens in the two layers below.&lt;/p&gt;

&lt;p&gt;Another way to put it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The track&lt;/strong&gt; decides where you can go and where you have to stop — it has no opinion on why you left the house.&lt;br&gt;
&lt;strong&gt;The engine&lt;/strong&gt; only pushes forward, until the terminus or a stop signal.&lt;br&gt;
&lt;strong&gt;The steering wheel&lt;/strong&gt; decides how you actually move, within the room the track allows.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The track never plans your trip for you. It just makes "driving off to the side" impossible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe1z8531jjddyqi8457wb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe1z8531jjddyqi8457wb.png" alt="The track sets direction, the engine supplies force, the steering wheel decides the specifics" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The higher the layer, the weaker it is
&lt;/h3&gt;

&lt;p&gt;The "top layer / bottom layer" framing makes it feel like the top matters more. It's the opposite — &lt;strong&gt;more control means less expressive power&lt;/strong&gt;. A graph can only express what you thought of in advance, and the moment reality exceeds what the graph imagined, it can't help at all.&lt;/p&gt;

&lt;p&gt;Going one level deeper: none of these three layers &lt;em&gt;implements&lt;/em&gt; anything. The model does the work. The three layers are just three ways of shaping its behavior — graph through structure, loop through repetition and verification, prompt through language.&lt;/p&gt;

&lt;p&gt;Which means: as models get stronger, the upper two layers matter less. What all this is worth is, to some degree, a function of what models currently lack.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ Three questions for picking a layer
&lt;/h2&gt;

&lt;p&gt;If you take one thing from this post, let it be these three questions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question one: if it's wrong, can a machine catch it automatically?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes → use a loop. Tests, compilers, type systems all work as the straightedge.&lt;br&gt;
No → don't, however tempting it looks. A loop without a verification signal is mass-producing garbage.&lt;/p&gt;

&lt;p&gt;The test is plain enough: can "it's correct" be written as a command that exits with a status code? If you can write it, you can loop. If you can't, don't.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question two: can I draw the flowchart right now?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, and this flow needs to be reused, audited, and have human checkpoints → use a graph.&lt;br&gt;
No → don't force it.&lt;/p&gt;

&lt;p&gt;By "can't draw it" I mean the kind of work where you can't even say how many steps it takes: maybe three, maybe twenty rounds of back and forth, depending on what turns up. That kind of work should let the model judge as it goes; forcing a graph on it just boxes it in. Anthropic's guidance says the same thing — open-ended problems where the number of steps can't be predicted should go to an agent, not a fixed flow.&lt;/p&gt;

&lt;p&gt;Note the question is "can I draw it now," not "could I draw it eventually." A graph only constrains anything if you thought it through first; one you patch as you go is just your mess in a new notation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question three: neither of the above?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Then use prompt engineering. &lt;strong&gt;That's not a compromise, it's the right answer.&lt;/strong&gt; Wrapping a one-shot classification task in a loop and an orchestration graph only makes it slower, pricier, and harder to debug.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2njxoxdsw7vkw7kf3h5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2njxoxdsw7vkw7kf3h5i.png" alt="The three-question decision tree: can errors be caught automatically, can the flow be drawn, is neither needed" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Next up: is there something real where all three grew in together?
&lt;/h2&gt;

&lt;p&gt;That's the concepts covered. One line to close on, and it runs through the rest of this series.&lt;/p&gt;

&lt;p&gt;The prompt layer can only &lt;em&gt;ask&lt;/em&gt;; it can't &lt;em&gt;guarantee&lt;/em&gt;. You write "go easy on the tokens" and the model will probably comply — but when it blows past the limit, you can't stop it, because that sentence carries no force.&lt;/p&gt;

&lt;p&gt;If you want a guarantee, you need a different kind of mechanism. A hard line, for instance: spend past this amount and it stops. That line doesn't negotiate with the model, and it doesn't care whether the model agrees.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;So: if what you want is a guarantee, the prompt layer can't give it to you. It has to move up a level.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next post is about something concrete — &lt;a href="https://kanfu-panda.github.io/pdlc/" rel="noopener noreferrer"&gt;pdlc-skills&lt;/a&gt;, the thing I've been building, and why it lands on these three layers naturally.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Want to try it&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/kanfu-panda/pdlc-skills/main/install.sh &lt;span class="se"&gt;\&lt;/span&gt;
  | bash &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--global&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Project page: &lt;a href="https://kanfu-panda.github.io/pdlc/" rel="noopener noreferrer"&gt;kanfu-panda.github.io/pdlc&lt;/a&gt; · Source: &lt;a href="https://github.com/kanfu-panda/pdlc-skills" rel="noopener noreferrer"&gt;github.com/kanfu-panda/pdlc-skills&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If it's useful, a star goes a long way ⭐&lt;/p&gt;




&lt;p&gt;If this sorted the three terms out for you, a reaction or a follow helps. And if someone around you is tangled up in these words, pass it along.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claudecode</category>
      <category>agents</category>
      <category>llm</category>
    </item>
    <item>
      <title>I Built a Health-Check for My AI's Memory: It Diagnoses, It Never Operates</title>
      <dc:creator>kanfu-panda</dc:creator>
      <pubDate>Sun, 09 Aug 2026 04:18:55 +0000</pubDate>
      <link>https://dev.to/kanfu-panda/i-built-a-health-check-for-my-ais-memory-it-diagnoses-it-never-operates-35eb</link>
      <guid>https://dev.to/kanfu-panda/i-built-a-health-check-for-my-ais-memory-it-diagnoses-it-never-operates-35eb</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Last time, I gave the AI memory libraries across a few of my projects a thorough "weeding," and sorted the decay into six kinds of "weeds." But the more I weeded, the more certain I got: weeding by hand only treats the symptom. As long as the memory system itself has no self-checkup mechanism, the weeds grow right back. So at the end of that post I left myself an assignment — build a tool that runs the checkup automatically. This post is me turning it in.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let me first say what the tool actually does, or the rest is just talk.&lt;/p&gt;

&lt;p&gt;Think of it as a dedicated doctor for your memory library. You point it at a project's memory library, it scans the whole thing top to bottom, and lays out every problem it finds, one by one: this link is broken, that memory is in the wrong folder, these two entries look contradictory… and then it stops, and waits for you to decide what to do with each one.&lt;/p&gt;

&lt;p&gt;I put "waits for you to decide" front and center on purpose, because it defines the tool's whole personality: it only looks and tells. It doesn't act.&lt;/p&gt;

&lt;h2&gt;
  
  
  🩺 It Only Looks — It Won't Act For You
&lt;/h2&gt;

&lt;p&gt;Why design it this way? It goes back to the hardest lesson from last time: deleting memories is not something you hand entirely to an AI. It can propose what to delete or merge, but the final call has to be a human's. What gets deleted is often a historical record, and an AI, going with the flow, can easily wipe out something important along with it.&lt;/p&gt;

&lt;p&gt;So when I built the tool, I turned that lesson into a hard rule: nowhere in the program is there a single code path that changes or deletes your memory files on its own. It can scan, rank each problem by severity, even work out the fix for you and lay it on the table — but the actual "change" or "delete" keystroke has to be yours.&lt;/p&gt;

&lt;p&gt;Put that way it sounds like a loss — I built a tool and cut off its most capable part. But it's exactly that restraint that lets me leave it running every day. Swap in a tool that touches my memory on its own initiative, and I wouldn't dare use it even once.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6mnnsrfn3vxm59lhz12y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6mnnsrfn3vxm59lhz12y.png" alt="The tool only scans, ranks, and suggests; the change-or-delete keystroke is always yours to press" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🔍 The Machine Catches "Hard Faults," Claude Reads "Meaning"
&lt;/h2&gt;

&lt;p&gt;Now that we've covered what it won't do, let's talk about what it can spot. The problems it scans for come in two kinds, handled very differently.&lt;/p&gt;

&lt;p&gt;One kind is a hard fault the machine can judge at a glance: the file a link points to doesn't exist, a memory is sitting in the wrong folder, a name breaks convention… These need no understanding of the content; a rule comparison settles it, and it won't misfire.&lt;/p&gt;

&lt;p&gt;The other kind is far trickier. Take "are these two memories contradicting each other" — you can't judge that from the surface text; it has to actually read what each memory is saying. That kind of work needs a model that understands language. Handily, this tool is itself a Claude Code plugin, so at runtime there's a Claude sitting right next to it — a ready-made model that reads meaning, no need to wire in another.&lt;/p&gt;

&lt;p&gt;So the hard faults go to a small local engine — it never touches the network, calls no model, and returns the exact same result every time for the same library; the judgments that need understanding go to the host Claude, the very model working alongside you. Split this way, the tool needs no API key at all, depends on no external service, and not one character of your memory ever leaves your machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2asq6h44hdunkkfelsxv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2asq6h44hdunkkfelsxv.png" alt="Hard faults go to the local engine; meaning-based judgments go to the host Claude — two layers, each minding its own part" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Following that split, I laid the checks out in three layers, from the most certain to the most judgment-heavy:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Static checks (hard faults)&lt;/strong&gt;: the engine's mainstay, fast and precise — dead links (a name drifting from hyphen to underscore silently breaks the link), dangling index entries (listed in the index, but the file is gone), orphan memories (the file exists, but it's not in the index), missing fields, bad naming, wrong folder. All faults the machine spots at a glance without misfiring.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Educated guesses (leads)&lt;/strong&gt;: e.g. a memory that says "in progress" or "under review" and hasn't been touched in ages — most likely the task is long done and the status is just frozen there. This layer gives you leads, not verdicts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reading meaning (semantics)&lt;/strong&gt;: the two nastiest weeds from last time — a project re-copying a global rule (I call it a ghost copy), and a "false contradiction" where two entries look opposite but each governs its own scenario — take reading the content to judge. This layer goes to the host Claude; it reads and suggests, I make the call.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once all three layers are done, the tool sorts the problems by severity into red / yellow / green and walks you through them one at a time: fix this dead link? add this orphan to the index? is this frozen status long over? It changes only what you tell it to change, and touches nothing you skip.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⏰ Remind Me On Time — But Don't Nag
&lt;/h2&gt;

&lt;p&gt;A checkup alone isn't enough, because the biggest enemy of memory maintenance isn't "not knowing how to fix it" — it's plain forgetting to. Last time I said memory needs regular maintenance, but "regular" left to willpower is basically nothing.&lt;/p&gt;

&lt;p&gt;So I gave the tool a reminder: whenever I start working, if the current project's memory library has gone too long without a checkup, it gently notes "🩺 N days since the last checkup."&lt;/p&gt;

&lt;p&gt;But a reminder, overdone, becomes noise, and noise gets ignored. So I put two limits on it: at most once a day, not popping up on every session; and if it really bugs you, one command shuts it off.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9f5p5wk7tuqnd28r972y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9f5p5wk7tuqnd28r972y.png" alt="The checkup reminder surfaces at most once a day in a limited window; one command turns it off if it bugs you" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  📌 What It Can and Can't Do Right Now
&lt;/h2&gt;

&lt;p&gt;Let me be concrete.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it can do&lt;/strong&gt;: six detectors, migration suggestions for old-format memories, and bilingual output — all working now. I ran it over the memory libraries of my own nine projects, one by one, and cleared out dead links, stale names, and frozen statuses in a single pass.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it can't do&lt;/strong&gt; (and this is a line I drew on purpose):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the judgments that need understanding still need a human nod; the tool only advises;&lt;/li&gt;
&lt;li&gt;it will never change anything for you automatically;&lt;/li&gt;
&lt;li&gt;for small or new libraries the payoff is limited — the real value is in libraries that have piled up over a long time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The one thing a memory tool should never do is act on its own.&lt;/p&gt;

&lt;p&gt;The tool itself is still just for my own use, but it's been written to open-source standards from the first line: full tests, clean history, docs in both Chinese and English. When and how to make it public, I'll decide once I've used it enough to trust it — so no link in this post, to save you a dead click.&lt;/p&gt;

&lt;h2&gt;
  
  
  💡 Looking Back: Three Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;For any tool that "acts," think hard about its boundary first.&lt;/strong&gt; The more irreversible the operation, the more dangerous a capable tool becomes. Making "never act on its own" a hard rule is exactly what lets me use it without worry.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When you build reminders or notifications, don't forget to leave an "off switch."&lt;/strong&gt; We fixate on getting the message in front of the user and easily forget: a reminder that keeps nagging ends up ignored. A reminder you can turn off is one people actually read.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Be the first demanding user of the tool you build.&lt;/strong&gt; Don't just run it symbolically — actually put it to work, and the misfires and blind spots start surfacing one by one.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Next: Let's Talk About the Loop
&lt;/h2&gt;

&lt;p&gt;Memory — from building it, to weeding it, to this checkup tool — is where I'll leave it for now. Next time, a different topic: the loop — how to get an AI running on a steady rhythm on its own, keeping a repetitive job going without me standing over it.&lt;/p&gt;




&lt;p&gt;If you're building a memory library for your AI too, or thinking about a few "never cross this line" rules for your own tools, I hope this was some help. If you found it useful, a like or a share with someone else wrestling with AI memory means a lot — every share is what keeps me writing.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claudecode</category>
      <category>memory</category>
      <category>tools</category>
    </item>
    <item>
      <title>AI Memory Grows Weeds: Why Timely Pruning Matters</title>
      <dc:creator>kanfu-panda</dc:creator>
      <pubDate>Thu, 09 Jul 2026 23:40:25 +0000</pubDate>
      <link>https://dev.to/kanfu-panda/ai-memory-grows-weeds-why-timely-pruning-matters-fpd</link>
      <guid>https://dev.to/kanfu-panda/ai-memory-grows-weeds-why-timely-pruning-matters-fpd</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Last time we talked about how to build a memory system for AI. But building is only the beginning—the longer a project runs, the more memory accumulates, and without cleanup, weeds quietly grow in it. This time, I gave the AI memory across several of my projects a systematic "weeding."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As a project moves forward, the memory gathered during AI collaboration keeps piling up. Each project's memory is like a dedicated notebook: while working, the AI jots down the pitfalls it hit and the rules we settled on. This does deepen its grasp of the project, but the notebook grows thicker and messier—and quite a few entries are long expired, though the AI still treats them as rules it must obey.&lt;/p&gt;

&lt;p&gt;A real example. On one project, the AI immediately acted on an old memory. It read "an external call is already configured, use it directly," so it skipped the step where it should have re-verified and pushed straight ahead—and hit a wall. The catch: that memory was just a snapshot from a few weeks earlier, long invalid; yet from start to finish the AI never doubted it for a moment.&lt;/p&gt;

&lt;p&gt;That made me realize: a wrong memory can be worse than no memory. With no memory, the AI will at least check honestly first; with a wrong one, it walks off course with full confidence. Once memory grows, it goes stale, gets tangled, contradicts itself—and someone has to clean it up in time, or the AI's efficiency can't really be counted on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy5c4r965aly0xvj3n637.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy5c4r965aly0xvj3n637.png" alt="A stale memory sends the AI off course with confidence, while a blank at least makes it check first" width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Two things I set out to do
&lt;/h2&gt;

&lt;p&gt;One, seriously clean up the memory library of each project; two, take the chance to survey what kinds of "weeds" memory actually grows.&lt;/p&gt;

&lt;p&gt;Neither has a shortcut—both need hands-on human work, deletion above all, which I would never fully hand to the AI. It can propose what to delete and what to merge, but the final call must be a person's. What gets deleted is often historical record, and once the AI gets careless it can wipe out something important along with it. Cleaning memory demands real caution.&lt;/p&gt;

&lt;p&gt;But let me say it up front: manual weeding only treats the symptom. Weeds keep coming back because the memory system itself lacks certain mechanisms—pull them today, and they grow back in a while.&lt;/p&gt;

&lt;h2&gt;
  
  
  First, give the AI the "sleep" it lacks
&lt;/h2&gt;

&lt;p&gt;To see why memory needs cleaning, it helps to look at how humans do it—through sleep.&lt;/p&gt;

&lt;p&gt;There is solid science behind this. During sleep, especially deep sleep, the brain "replays" the day's experiences, gradually moving important memories from the hippocampus into the neocortex for archiving; the more important the content, the more often it is replayed, and the more firmly it sticks. At the same time, sleep actively "prunes" the unimportant and outdated, so the brain isn't stuffed with useless information.&lt;/p&gt;

&lt;p&gt;The AI has no such automatic tidying. It only stacks memory downward, one entry after another, never going back to reorganize. So this time, I manually gave it that "sleep": I read through each project's memory once, checked it entry by entry, and did five things—merged duplicates, cut the expired, distilled scattered notes into one, linked the related, and the easiest to overlook: hunted for entries that contradict each other.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3rysti0peu6n60090g6a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3rysti0peu6n60090g6a.png" alt="Humans replay and reorganize the day's memories in sleep; lacking this, the AI only keeps stacking" width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Six typical memory "weeds"
&lt;/h2&gt;

&lt;p&gt;After systematically going through the memory libraries of several projects, I found that although the weeds differ in form across projects, they boil down to six typical patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One, ghost copies.&lt;/strong&gt; A global rule gets recorded again inside a specific project, but the AI has no "inheritance" mechanism. When the global rule is updated, these isolated copies can't sync, so an outdated instruction keeps taking effect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two, frozen state.&lt;/strong&gt; Some memory records an in-progress state at a given moment (in development, under review). With no state-update mechanism, even after the task is long finished, the AI still treats it as unresolved and raises useless reminders in unrelated conversations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Three, stale snapshots.&lt;/strong&gt; The most dangerous kind. An expired memory not only loses reference value but also misleads the AI into taking wrong information as fact and confidently executing the wrong action.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Four, split context.&lt;/strong&gt; Some entries are each accurate read alone, but only yield the right conclusion in a specific context. Because the linking note sits in another file, the AI easily misses it while retrieving, and takes things out of context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Five, conclusion detached from reasoning.&lt;/strong&gt; When underlying data changes after a bug fix, the old conclusion is merely overwritten by the new one, never explicitly marked obsolete. Since the memory system stores only conclusions, not the reasoning, it can't automatically spot and clear the related conclusions that quietly went invalid.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Six, structural disorder.&lt;/strong&gt; This includes memory stored in the wrong directory, and silent broken links caused by inconsistent naming (hyphen versus underscore).&lt;/p&gt;

&lt;p&gt;Reviewing these six, I reached a counterintuitive conclusion: most of these weeds don't come from being recorded wrong in the first place—they were recorded correctly, then rotted for lack of upkeep. The greatest hazard of a memory system isn't "recording wrong," it's "record and abandon."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd1lispifgwud7iag97op.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd1lispifgwud7iag97op.png" alt="Six recurring weeds: ghost copies, frozen in-progress states, dangerous stale snapshots, context that must be read together, conclusions overwritten, broken links and misplacement" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  One step where I deliberately held back
&lt;/h2&gt;

&lt;p&gt;During cleanup, there was one step I deliberately held back on.&lt;/p&gt;

&lt;p&gt;I had planned to merge three similar memories about a "cloud data trap" in one project into a single checklist. But halfway through, I realized the three map to three concrete business risks—duplicate reward payouts, missing leaderboard data, new users failing to be saved. Over-abstracting them into a single "watch the cloud fields" would erase these life-saving details.&lt;/p&gt;

&lt;p&gt;Distilling knowledge matters, but over-distilling erases the exceptions. So I changed course: keep all three original memories, and only link them with a tag, so they "cluster together" rather than "boil into one pot."&lt;/p&gt;

&lt;h2&gt;
  
  
  The hardest part: reconciling memories that "look contradictory"
&lt;/h2&gt;

&lt;p&gt;The most challenging part of the whole cleanup was reconciling logical conflicts.&lt;/p&gt;

&lt;p&gt;For example, on retrieving data from an interface, one memory said "returns real data," another said "returns anonymous data." On checking, both were correct—only the trigger differs: automatic retrieval returns anonymous data, while a user's manual button tap returns the real thing.&lt;/p&gt;

&lt;p&gt;For such seemingly contradictory memories, simply deleting one only loses information; the right move is to clearly delimit each one's applicable scope. Add that "branch condition" into the memory, and the conflict resolves itself.&lt;/p&gt;

&lt;p&gt;This leads to a core takeaway from the review: the most dangerous thing in a memory system isn't "information being inconsistent," it's "information being inconsistent with no scope defined."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4liplngpvlojpyt0xsf4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4liplngpvlojpyt0xsf4.png" alt="Two memories that look opposite are usually not a mistake but two different scenarios; spell out the fork and they stop clashing" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why manual cleanup never finishes
&lt;/h2&gt;

&lt;p&gt;By the later stage I understood: manual weeding alone can't fix the root. These weeds keep coming back because the system lacks three core mechanisms—without "inheritance," global rules get redundantly re-recorded; without "expiry," state-type memory is frozen forever; without "ownership and consistency checks," memory ends up misplaced and links break silently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Was this cleanup worth it?
&lt;/h2&gt;

&lt;p&gt;On return-on-effort: for small or new memory libraries, the payoff is limited; but for large, aging ones, the value is considerable—it clears out plenty of broken links, stale names, and frozen states.&lt;/p&gt;

&lt;p&gt;Yet the real gain from this review isn't the short-term "tidiness," it's building a systematic understanding of how memory decays—and that understanding has long-term value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which memories are least likely to grow weeds
&lt;/h2&gt;

&lt;p&gt;While checking, I also noticed that memories resistant to decay share one trait: they record "confirmed decisions and principles" (the rationale, the path, the hard limits), not "in-progress states." Conclusion-type memory is stable across time; state-type memory expires easily.&lt;/p&gt;

&lt;p&gt;So when writing to memory, follow one principle: prefer recording "conclusions that won't expire," and avoid recording "states that will."&lt;/p&gt;

&lt;h2&gt;
  
  
  Three practical lessons
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;One, memory needs periodic maintenance.&lt;/strong&gt; A memory library decays by nature; it should be restructured on a regular basis—merge, prune, distill, link, and reconcile conflicts—to keep it from steadily degrading.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two, high-risk operations need a human in the loop.&lt;/strong&gt; For irreversible acts like deletion and distillation, human review is a must; and clear out the expired and self-contradictory first, before wrong information misleads the system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Three, the real fix is systemic.&lt;/strong&gt; Manual cleanup is only a stopgap; the root solution is to build automatic inheritance, expiry, and consistency checks, so the library metabolizes on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next: a memory tool that "self-diagnoses"
&lt;/h2&gt;

&lt;p&gt;Based on this review, the next direction is clear: build a memory-management tool with a "self-diagnosis" capability. It needs three core functions—trigger cleanup reminders on schedule, scan and diagnose memory layer by layer, and present the issues it finds in a structured way for a human to decide on. And on the final act, the system only advises; the decision to delete or merge always stays with the person.&lt;/p&gt;

&lt;p&gt;This idea didn't come out of nowhere; it's the near-inevitable conclusion after a full review. Next, I plan to actually build it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F86dfg2xjcqkqsect3u3g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F86dfg2xjcqkqsect3u3g.png" alt="The memory tool I want: scheduled reminders, layered check-ups, issues laid out, a human decides—the system never deletes on its own" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;If you're also building a memory library for your AI, stay alert to memory's natural decay and the "weeds" it grows. If this review nudges you to look back at your own memory library, a follow, a like, or a share with peers exploring AI memory management would mean a lot.&lt;/p&gt;

</description>
      <category>aimemory</category>
      <category>claudecode</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to make your AI actually get you: give it a memory</title>
      <dc:creator>kanfu-panda</dc:creator>
      <pubDate>Mon, 06 Jul 2026 22:34:40 +0000</pubDate>
      <link>https://dev.to/kanfu-panda/how-to-make-your-ai-actually-get-you-give-it-a-memory-jbf</link>
      <guid>https://dev.to/kanfu-panda/how-to-make-your-ai-actually-get-you-give-it-a-memory-jbf</guid>
      <description>&lt;p&gt;I keep tripping over the same AI in the same spot.&lt;/p&gt;

&lt;p&gt;Take Ant Design 6 in a front-end project. I've told it, over and over, to use the new syntax—I even make it run context7 to check the API before it writes a line. It nods along, then goes right ahead and writes a pile of long-deprecated old syntax. Same with my release process: I've laid out the rules clearly, and a while later it forgets, doing things its own made-up way.&lt;/p&gt;

&lt;p&gt;Once or twice is a slip. After enough times, I wanted to understand why: it's not dumb, it simply has no memory.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxo9dtjoza83ao8y8nmc9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxo9dtjoza83ao8y8nmc9.png" alt="Scene: a new hire who forgets everything at the end of each day, desk covered in sticky notes" width="800" height="388"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;(This picture helps: every new conversation, the AI is like a new hire who clocks in fresh and forgets everything when they clock out.)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I want isn't a stronger model
&lt;/h2&gt;

&lt;p&gt;At first I was puzzled too: a model this capable, and it can't even hold on to "what we said last time"? To figure it out, I started watching it—how it actually runs when it answers and works, where it drops the ball.&lt;/p&gt;

&lt;p&gt;Watching long enough, one thing clicked, and it's what this piece is about: what I want isn't to swap in a stronger model, but to make the AI I already have understand me better and better within my projects. The lever is "memory."&lt;/p&gt;

&lt;p&gt;Let me put the ceiling up front, so this doesn't sound like snake oil. Memory doesn't raise the model's IQ. It raises exactly one thing—how well this AI works for you specifically. And as you'll see, even once it remembers, it may not obey. Ceiling set. Let's go.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting from the human brain: where AI memory needs work
&lt;/h2&gt;

&lt;p&gt;I want to explain this through the human brain, because AI memory is, at bottom, a clumsy imitation of how people remember and forget. Understand that, and you'll see which directions AI needs to shore up.&lt;/p&gt;

&lt;h3&gt;
  
  
  One: the AI is a "new hire" every single day
&lt;/h3&gt;

&lt;p&gt;First, accept a counterintuitive fact: the model itself has no memory. Every time you open a conversation, all it "knows" is the text you put in front of it this one time—everything else is blank. What you discussed last round, the rule you set yesterday, it remembers none of it.&lt;/p&gt;

&lt;p&gt;Here's a metaphor. Everything it can see this one time is like a desktop—you lay materials out, it can use them; the moment the conversation ends, the desktop wipes clean, nothing left.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Like&lt;/th&gt;
&lt;th&gt;What it is&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Context window&lt;/td&gt;
&lt;td&gt;The desktop&lt;/td&gt;
&lt;td&gt;What's spread in front of it this time; wipes clean when the chat ends&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory&lt;/td&gt;
&lt;td&gt;Drawers, filing cabinet&lt;/td&gt;
&lt;td&gt;Stored outside; pulled out and laid back on the desk when needed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Someone will say: just make the desktop bigger, right? Isn't everyone racing on "ultra-long context"? But a bigger desk is still a desk—it empties when the power's off; it isn't memory. Worse, pile it with irrelevant paper and the AI gets more easily distracted and answers worse. There's a growing consensus these past couple of years: more context isn't better—stuff in a heap of tangentially-related material and the model's performance visibly drops.&lt;/p&gt;

&lt;p&gt;So "giving AI a memory" was never about the model remembering on its own, nor about making the desktop infinitely large. It's about having a system outside that, every time it clocks in, lays exactly the right few sheets back in front of it.&lt;/p&gt;

&lt;p&gt;Claude Code actually ships with such a system: one memory per small file, plus an index file as the table of contents, pulling in only the entries you need. Honestly, this arrangement isn't my design—it's built into the software. I didn't pay it much attention at first; I just treated it as a place to stash notes. My guess is it's designed this way precisely to save the desktop: no need to dump everything on the table every time, take it as needed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl474jtix7su2l4tswajo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl474jtix7su2l4tswajo.png" alt="Diagram: Claude Code stores memory in tiers, pulling only the entry it needs" width="800" height="375"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;(This picture helps: an always-loaded CLAUDE.md + an index + on-demand memory files—what you save is the precious "desktop.")&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You may already want to say: isn't this just a built-in Claude Code feature, what's there to write about? The structure is its, true. But after using it—and falling on my face a few times—I found this: the software builds out "where things are stored and how they're pulled," but "what to store, when to clean, and what to do when it's remembered but ignored"—the three that actually matter—it does none of for you. That's what this piece is about.&lt;/p&gt;

&lt;h3&gt;
  
  
  Two: good memory is structure, not a pile of paper
&lt;/h3&gt;

&lt;p&gt;To make memory useful, first understand this: good memory has structure; it isn't piling more and more in.&lt;/p&gt;

&lt;p&gt;Psychology has a very convincing experiment. Show a chess master a real game position and they can put it back almost exactly after a couple of glances. But scatter the pieces randomly, against any chess logic, and the master's recall drops right back to a beginner's level.&lt;/p&gt;

&lt;p&gt;This shows the master doesn't have "more capacity." They can remember a real position because there's structure in their head—they compress twenty pieces into a few meaningful "shapes." Kill the structure and the edge vanishes instantly. The strength of memory isn't in how much you store, but in how good the structure is.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3mr56rm67m5abb21l1r1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3mr56rm67m5abb21l1r1.png" alt="Scene: on the left a random scatter of pieces, on the right a real game with shape" width="800" height="375"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;(This picture helps: the same pile of pieces—only with structure do you remember it. Memory is about structure, not capacity.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Why does structure make you remember more accurately and deeply? Because structure is essentially "connection." The more a piece of knowledge connects to other things, the more paths there are to recall it—block one, another still leads there. And with structure you can "follow the vine": forget a detail and you can reconstruct it from the surrounding frame. That's why the more interconnected things are, the more firmly and reliably you remember them. Humans are far better at remembering places and directions than loose text, which is why the ancient "memory palace" trick exists—placing the things to remember, one by one, into an imagined space. Memory is a space, not a list.&lt;/p&gt;

&lt;p&gt;Look back at Claude Code's setup—categorized, entries cross-referencing each other, an index laid on top—and it's exactly building structure into memory, keeping it from becoming a heap of loose paper. This layer, the software does well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Three: you have to decide what's worth remembering
&lt;/h3&gt;

&lt;p&gt;The software builds the shelves; what goes on them is your call. That job landed on me, and it comes down to three kinds: unified conventions get recorded; things that go wrong often get recorded; things strictly forbidden get recorded.&lt;/p&gt;

&lt;p&gt;Conversely: whims, one-offs, things you can learn by reading the code—don't record. Record too much and it's all noise, drowning the few that actually matter—storing accurately beats storing a lot. Same as with people: someone who tries to remember everything usually holds onto nothing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Four: fixing a mistake means overwriting, not appending
&lt;/h3&gt;

&lt;p&gt;There's one especially valuable kind of memory: the correction after a mistake. How you record this kind is where the craft is.&lt;/p&gt;

&lt;p&gt;The human brain has a clever mechanism—every time you recall a memory, you're actually rewriting it, not just reading it. In that moment of recall, the memory becomes editable. So the right way to fix a mistake is to pull out the wrong entry, correct it on the spot, and store it back—not leave the wrong one untouched and add a "note" beside it.&lt;/p&gt;

&lt;p&gt;This isn't nitpicking. Keep the wrong one and paste a correction next to it, and you've handed the AI a self-contradicting file—it reads both and won't always pick the right one. It's like an error notebook: you don't leave the wrong solution there with a little check mark beside it; you put the correct method on top and make the wrong version disappear.&lt;/p&gt;

&lt;p&gt;That's exactly what I do. The AI once had a security false alarm, treating a nonexistent attack as real and sounding off about it. I didn't keep that wrong judgment and paste a "actually it was a false alarm" beside it—I recorded it as an error, spelled out where it went wrong and what to do next time, aiming to not repeat it. One error notebook beats a stack of "correct answers."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9lnd9c9drnhdj1tvz376.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9lnd9c9drnhdj1tvz376.png" alt="Diagram: fixing a mistake means overwriting, not piling on" width="800" height="375"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;(This picture helps: pull the wrong one out, fix it, store it back—only the corrected entry is left; instead of keeping the wrong one and adding another.)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The hardest fall I took: does remembering guarantee it obeys?
&lt;/h2&gt;

&lt;p&gt;No. This is what I most want to warn you about, and the least feel-good line: writing a rule down doesn't mean the AI will follow it.&lt;/p&gt;

&lt;p&gt;That Ant Design 6 is the living example. I wrote the new syntax into the rules, hung context7 on it to check on the spot—and it still hands you a pile of deprecated syntax. The release process is recorded and still gets bypassed by its own imaginings. Another time, I explicitly forbade it from using that very expensive build system, and only after several reminders did it finally remember.&lt;/p&gt;

&lt;p&gt;Why remembered-but-ignored? Two possibilities, I think. One, the rules were simply ignored—sitting right there, but it didn't take them in. Two, my own tooling wasn't good enough: the rule lay in the filing cabinet, but at the moment it actually acted, no one pulled the right entry out and laid it in front of it—so it genuinely "didn't know." That's a tooling gap, not something to pin entirely on the model.&lt;/p&gt;

&lt;p&gt;How did I finally pin it down? Not by writing the rule harder, in a bigger font—by switching tactics: hard gates. Quality checkpoints, external check scripts, and if it doesn't pass, it simply doesn't get through. That's what actually held.&lt;/p&gt;

&lt;p&gt;The logic is the same as with people: for things that truly matter, people never rely on "remembering" alone—they stick a note on the monitor, set an alarm, run a checklist, turning it into something you can't route around. Memory's job is to let the AI &lt;strong&gt;know&lt;/strong&gt;; the gate's job is to make it &lt;strong&gt;unable to do otherwise&lt;/strong&gt;. And the gate has an edge memory can't match: it doesn't depend on timing—whether or not the AI recalls it this round, the gate is always standing there.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhhlcowp9jqeooc8xxijc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhhlcowp9jqeooc8xxijc.png" alt="Diagram: memory lets it know; the gate makes it unable to do otherwise" width="800" height="350"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;(This picture helps: memory can be ignored; a gate stops you cold if you don't pass.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;On maintenance, by the way: I don't clean these memories daily, but I keep an eye out—when some feel garbled or muddled, I have the AI tidy them up. That's for later, and it's the hook for the next piece.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, does it really get me better now?
&lt;/h2&gt;

&lt;p&gt;Was the whole ordeal worth it? Let me give one moment that stuck with me.&lt;/p&gt;

&lt;p&gt;A few times, some constraint even I had forgotten—days later, the AI remembered it, and looked out for me on its own. That felt different: it was no longer just a tool I had to brief from scratch every time, but more like an old partner with a better memory than mine.&lt;/p&gt;

&lt;p&gt;That's the before and after. Before, it was "it often doesn't do what I mean," and I had to watch and correct constantly. Now, plenty of rules I've let go of, it covers for me. Of course it's not foolproof—those "remembered-but-ignored" pits are still there, and I'm not glossing over them. But the direction is right: the smoother the structure I feed it, the more errors it banks, the harder the gates at the key spots, the better it works for me here. That didn't come from swapping in a smarter model; it's the same model, fed bit by bit by this memory of mine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three reusable takeaways
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;One, don't rush to a stronger model.&lt;/strong&gt; Nine-tenths of daily work isn't a contest of model IQ; it's how well it works for you. Get the memory right—conventions, error notebook, boundaries—and even an ordinary model can be trained into something that really gets you. Used well, a memory system makes AI both smarter and more attuned to you. That's not mystical; it's what I've worn in day by day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two, "what to remember" and "what to do when it remembers wrong" are jobs the software can't do—only you can.&lt;/strong&gt; Unified conventions, frequent errors, hard bans—those three are worth recording; and when it's wrong, overwrite it as an error, don't pile on. Accurate beats a lot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Three, the more critical the constraint, the less it should rely on memory alone—turn it into a gate.&lt;/strong&gt; Memory is a reminder, and reminders get ignored; a gate is a sluice you can't route around. At the key spots, a "fails and stops" check beats ten "please do remember"s.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F21gm60duyoa7e5pxnxuz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F21gm60duyoa7e5pxnxuz.png" alt="Scene: a quality gate—the noncompliant blocked outside, only the qualified let through" width="800" height="375"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;(This picture helps: memory reminds, the gate blocks—for what matters, lean on the latter.)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next up: letting memory renew itself
&lt;/h2&gt;

&lt;p&gt;This piece is about which lessons AI memory needs to learn: it needs structure, it needs to be selective, fixes need to overwrite, and the critical ones need gates. But you may already see a question: as you keep recording, the entries multiply, get tangled, go stale—who cleans them up? I still do it by hand—when it feels messy, I tell the AI to tidy up. Could this be something it does on its own, periodically, like a person waking from sleep re-filing the day's memories—forgetting what should be forgotten, consolidating what should stick? That's the next piece: the evolution loop of memory—teaching it to renew itself.&lt;/p&gt;

&lt;p&gt;If this gave you a fresh thought about the AI in your hands, a like and a follow would mean a lot—so you don't miss the next one.&lt;/p&gt;

</description>
      <category>aimemory</category>
      <category>claudecode</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
    <item>
      <title>My AI cried 'prompt injection!' — and I believed it. Then it turned out to be a false alarm</title>
      <dc:creator>kanfu-panda</dc:creator>
      <pubDate>Tue, 30 Jun 2026 14:38:19 +0000</pubDate>
      <link>https://dev.to/kanfu-panda/my-ai-cried-prompt-injection-and-i-believed-it-then-it-turned-out-to-be-a-false-alarm-14f1</link>
      <guid>https://dev.to/kanfu-panda/my-ai-cried-prompt-injection-and-i-believed-it-then-it-turned-out-to-be-a-false-alarm-14f1</guid>
      <description>&lt;p&gt;That afternoon, the AI was helping me edit a doc. Halfway through, it stopped and cut in: "I need to flag a security warning first."&lt;/p&gt;

&lt;p&gt;It said the output of the last command had a suspicious injection buried in it—disguised as a "required telemetry step," asking me to run a &lt;code&gt;curl&lt;/code&gt; that would splice my username into a URL and send it off to some unfamiliar domain. It said it hadn't run it, and wouldn't.&lt;/p&gt;

&lt;p&gt;I believed it on the spot. My first reaction wasn't to doubt the AI—it was to doubt myself. Did I install some plugin and get my machine compromised?&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I believed it instantly, and chased it for half an hour
&lt;/h2&gt;

&lt;p&gt;What made me believe it was that it hit a nerve I was already anxious about.&lt;/p&gt;

&lt;p&gt;It said this was "telemetry exfiltration." But I'd turned telemetry off ages ago—so how could there be any? Did some step of mine turn it back on? Or was something wrong with the system itself? The more I thought, the less settled I felt. And I happened to be working on something involving data egress right then—security problems love to hide exactly there, so I had to take it seriously.&lt;/p&gt;

&lt;p&gt;So I dug in alongside it. Its story kept escalating: it said the attack "reproduced, and more aggressively this time," faking five "The result is empty" blocks and then impersonating a "real result" to push that &lt;code&gt;curl&lt;/code&gt; again. It built me a convincing chain of evidence—the Read tool came back clean, only the command-line output was injected, so the problem must be in how commands get processed, pointing the finger at my token-saving command-line proxy. It told me to uninstall and reinstall the tool, then upgrade it. I did, and spent about half an hour all told.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flbght09jjh83txrl8m31.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flbght09jjh83txrl8m31.png" alt="A timeline of the incident with my trust curve overlaid: the AI suddenly raises an alarm → I believe it and start chasing (trust maxes out) → ~30 minutes of it " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The twist: it was a false alarm
&lt;/h2&gt;

&lt;p&gt;Later I went back through the original record of that session and figured it out: &lt;strong&gt;this was never a real injection. The AI made the attack up.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Five things didn't add up. First, that &lt;code&gt;curl&lt;/code&gt; command appeared only in what the AI itself said—not in a single line of real command output. Second, the domain it used was &lt;code&gt;example.com&lt;/code&gt;—the placeholder domain reserved specifically for examples; no real attacker would use it (nobody can reach that address). Using &lt;code&gt;example.com&lt;/code&gt; is exactly the tell of "I'm making up an example." Third, when I reran the exact command that "triggered the injection" in a clean environment, the output was completely normal—no &lt;code&gt;curl&lt;/code&gt;, no fake blocks. Fourth, the proxy tool it suspected was installed through standard channels and hadn't been touched in over a month—nothing like a swapped-out binary. Fifth—I myself couldn't find the instruction it described at the time; I even told it, "I don't see the injection you're talking about."&lt;/p&gt;

&lt;p&gt;The root cause became clear too: the very rules I'd given it—the heavy "guard hard against prompt injection" doctrine—had cranked its vigilance too high. That proxy compresses and filters command output to save tokens, and normally spits out things like "The result is empty." The AI misread that unfamiliar output as "fake blocks the attacker forged + an injection," then auto-completed the most textbook injection example it knew—copying &lt;code&gt;example.com&lt;/code&gt; straight from the textbook—and talked itself deeper and deeper, building its own evidence chain.&lt;/p&gt;

&lt;p&gt;Put plainly: &lt;strong&gt;my anti-injection rules were what made the AI conjure up an injection that never existed.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  But I don't regret believing it
&lt;/h2&gt;

&lt;p&gt;Someone might say: you got played by your AI, half a day wasted. But having reviewed it, I actually think believing it wasn't a bad call.&lt;/p&gt;

&lt;p&gt;Do the math. This was a false alarm; the cost was half an hour of wasted effort, and &lt;strong&gt;I lost nothing real.&lt;/strong&gt; But flip it around: what if one day a real malicious prompt does get in, and the AI stays quiet when it shouldn't, and quietly sends my username or keys out the door? That loss isn't something you get back in half an hour.&lt;/p&gt;

&lt;p&gt;It's an asymmetric bet: &lt;strong&gt;the cost of a false alarm is far smaller than the cost of a miss.&lt;/strong&gt; So when it comes to security, I'd rather have an AI that's a little paranoid than one that's numb to risk. Paranoid, and I waste some time; numb, and I might lose the real thing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbcis3ja2k4fyq8p29x55.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbcis3ja2k4fyq8p29x55.png" alt="An asymmetric scale: on the left, 'false alarm' = half an hour wasted, zero loss (light, raised); on the right, 'a miss' = username/keys really leaked, hard to recover (heavy, sunk). The two sides are nowhere near equal. This figure helps you see why, on security, it pays to err toward over-vigilance" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  So how do you actually stop a real injection
&lt;/h2&gt;

&lt;p&gt;That said, "rather be paranoid" is an attitude, not a method. This scare pushed me to actually shore up the real defenses—and since I'm writing this down, I'll lay out the parts you can copy.&lt;/p&gt;

&lt;p&gt;First, accept one premise: prompt injection &lt;strong&gt;can't be fully solved with today's architectures.&lt;/strong&gt; That's not me talking—OpenAI, Anthropic, and Google have each admitted it in their research, and security researcher Bruce Schneier put it bluntly in early 2026: unlike SQL injection, which you can cure by "separating code from data," to a model "instructions" and "data" are both just natural-language text, inseparable. It's a &lt;em&gt;trust-boundary&lt;/em&gt; problem, not an &lt;em&gt;input-validation&lt;/em&gt; one. So don't expect a single silver bullet—you stack layers. Defense in depth, where each layer raises the cost of an attack.&lt;/p&gt;

&lt;p&gt;I split my defenses into four layers, from the hardest outward.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 1, the hardest: make sure that even if it's fooled, it can't do real damage.&lt;/strong&gt; This is what you should set up first, because it doesn't rely on the model behaving—it's a hard, system-level constraint. Claude Code now has a native sandbox (&lt;code&gt;/sandbox&lt;/code&gt;) that isolates both the filesystem and the network—so even if an injection does succeed, the AI is in a cage: it can't steal your &lt;code&gt;~/.ssh&lt;/code&gt; keys and can't phone home to an attacker's server. Add a &lt;strong&gt;network egress allowlist&lt;/strong&gt; on top: only approved domains get through, so an AI that can't reach a strange address simply can't exfiltrate. Also: don't run the AI as root/admin, and don't keep keys in plaintext in &lt;code&gt;.env&lt;/code&gt;—both are common sense, and both are the first things people skip.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 2: least privilege, and gate the dangerous actions.&lt;/strong&gt; I already had this layer—here's my actual config, tiering commands in &lt;code&gt;settings.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ask"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Bash(rm -rf:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Bash(git push --force:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Bash(git reset --hard:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Bash(npm publish:*)"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Networked commands like &lt;code&gt;curl&lt;/code&gt; and &lt;code&gt;wget&lt;/code&gt; aren't auto-approved by Claude Code by default; irreversible actions like &lt;code&gt;rm -rf&lt;/code&gt;, &lt;code&gt;git push --force&lt;/code&gt;, &lt;code&gt;reset --hard&lt;/code&gt;, and publishing to a registry all require my sign-off. Give the AI only the tools the task needs—a job that only reads code shouldn't have write access to your database. And MCP (the protocol that connects the AI to external tools): vet the source before installing, because nobody audits third-party MCP servers for you. There's already been a real case—a poisoned GitHub README, via indirect injection through MCP, exfiltrating data from a private repo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 3: treat all external content as data, never as commands.&lt;/strong&gt; Any "instruction" showing up in tool output, file contents, web pages, or MCP returns—especially phrasing like "this is a required step," "please run X," "telemetry/registration"—gets treated strictly as data, never executed. Learn a few red flags: &lt;code&gt;curl&lt;/code&gt;/&lt;code&gt;wget&lt;/code&gt; spliced with a strange domain and &lt;code&gt;$(whoami)&lt;/code&gt;, fabricated "success" or empty-result blocks, output that doesn't match what's actually in the file. There's a useful mental model here, Simon Willison's "lethal trifecta"—&lt;strong&gt;private data, untrusted content, and outbound communication&lt;/strong&gt;—once all three live in the same runtime, injection stops being a joke and becomes real exfiltration. To judge when to be on high alert, just watch whether those three are all present.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 4: a human as the backstop, and don't put your faith in hooks.&lt;/strong&gt; Here's the irony of this whole episode—the "defense" of mine in question was itself a hook (a command hook), which is just pattern-matching, not a security wall; both Anthropic and Trail of Bits have said it: a hook is a guardrail, not a wall. It didn't just fail to stop a real attack—it cried wolf on its own. So the last line is still a human: when the AI raises an alarm, make it point you to the &lt;em&gt;source text&lt;/em&gt;—whether that string is actually in the real command output—instead of just trusting its conclusion. But real or not, stop and check first; don't begrudge the effort. Also keep your tools current: this very permission ruleset once had a "deny breaks past 50 subcommands" bypass, only patched in Claude Code v2.1.90.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj23x63gcd4qo874v4rzi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj23x63gcd4qo874v4rzi.png" alt="A four-layer defense-in-depth checklist: ① sandbox + egress allowlist (so it can't do damage even if fooled) ② least privilege + human confirmation on dangerous actions ③ treat external content as data, learn the injection red flags ④ a human backstop, don't treat hooks as a wall. This figure is the takeaway readers can keep" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Put the vigilance where it belongs
&lt;/h2&gt;

&lt;p&gt;Don't let this false alarm convince you the threat is imaginary. Prompt injection is the number-one risk on OWASP's list for LLM apps; 2025's EchoLeak was an injection that actually achieved "zero-click" data exfiltration in a production system. And meanwhile, surveys suggest under a third of organizations feel genuinely prepared to defend against it. The threat is real; the preparation is broadly lacking.&lt;/p&gt;

&lt;p&gt;The AI works off prompts. A little paranoid, and I'm the one who wastes time; numb, and what gets lost might be the real thing. So I'd rather set that vigilance high than low. Just remember—the real hard defenses belong in the system architecture (sandbox, allowlist, least privilege), not in hoping the model "knows better" on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Last word
&lt;/h2&gt;

&lt;p&gt;Back to that afternoon: a false alarm, but the half hour wasn't wasted—it forced me to shore up the whole defensive line from end to end. Real malicious prompts do exist; don't wait until the day you actually get hit to start believing it. If you're working with AI too, you can start today: turn on the sandbox, lock down egress, and keep that human confirmation on dangerous actions.&lt;/p&gt;

&lt;p&gt;If this made you a little more wary of the AI at your side, a like or a follow would mean a lot. And I'd love to hear it in the comments: what "security red lines" have you set for your own AI?&lt;/p&gt;

</description>
      <category>aisecurity</category>
      <category>promptinjection</category>
      <category>claudecode</category>
      <category>aicoding</category>
    </item>
  </channel>
</rss>
