I Won’t Use AI Without This Tool
Chapters6
The chapter discusses common AI coding issues like duplicated, dead, and overly large code, and argues that while AI struggles with these problems, a free ESLint-like tool designed for agent workflows can help fix them in both handcoded and vibecoded projects.
Kyle from Web Dev Simplified shows how the free tool Fallow finds AI-generated code problems and fits into editor workflows, CI, and agentics.
Summary
Kyle demonstrates a pragmatic way to tame AI-generated code with Fallow, a free CLI tool that behaves similarly to ESLint but targets AI-specific issues. He emphasizes how AI often produces duplications, dead code, and overly large, unreadable files, and he uses Fallow to detect and fix these problems. The tour covers automatic plugin detection for frameworks like Vit, Next.js, and TanStack, plus how Tailwind and other tools influence preconfigurations. He walks through real examples of dead code, unused exports, and unused dependencies, showing how Fallow surfaces these issues in a readable report. The video then dives into code duplication, revealing exact lines that are duplicated across sections and how to refactor them for maintainability. Kyle explains the importance of complexity metrics—cyclomatic complexity, cognitive load, and the CRAP score—to prioritize refactoring efforts. He also demonstrates a VS Code extension integration, making findings visible directly in the editor with underlines and warnings. Finally, he explains how to hook Fallow into agent workflows and CI pipelines (GitHub Actions) so AI-assisted changes are audited before merging, including an option to export results in JSON for AI agents. The takeaway is that Fallow isn’t just for AI projects; it’s a robust workflow tool to improve code health, with configurable ignore rules and a path to automated fixes. Kyle frames this as a practical addition to any developer’s toolkit, especially when pairing AI helpers with a rigorous review process.
Key Takeaways
- Fallow automatically detects plugins for common frameworks (Vit, Next.js, TanStack) and configures presettings based on those plugins.
- Dead code, unused exports, and unused dependencies are surfaced, helping you prune code that AI leaves behind.
- Code duplication is highlighted with exact line ranges, making refactoring targets clear and actionable.
- Complexity metrics (cyclomatic complexity, cognitive load) and the CRAP score reveal maintainability and test coverage gaps.
- The VS Code extension visualizes findings in-editor, showing unused files, exports, and duplicates with warnings and underlines.
- Fallow can be run via npx fallow, and you can fix issues automatically with npx fallow fix.
- CI integration and GitHub Actions allow automated audits on PRs, ensuring AI-generated changes pass checks before merging.
Who Is This For?
Essential viewing for frontend developers using AI-assisted coding who want maintainable, auditable AI output. Also valuable for teams adopting agent-based workflows and CI/CD checks to validate AI-generated changes.
Notable Quotes
"One huge problem with AI is it tends to write code that's not very maintainable."
—Sets up the core problem the video addresses.
"It's a completely free command line tool that works very similar to ESLint, but it's built in a way that can be useful for your agents to be able to help fix particular problems."
—Describes what Fallow does and its intended use.
"The tool is absolutely amazing."
—Expresses strong enthusiasm for Fallow.
"This is a great example of code that often gets exported. This is very common for AI to do, and you don't want that to be exported."
—Illustrates unused exports issue.
"You can run fix and it'll autofix some of these things that are easier to fix."
—Mentions automated fixes with the fix command.
Questions This Video Answers
- How does Fallow detect and fix AI-generated code duplication?
- What are CRAP score, cognitive load, and cyclomatic complexity, and how should I use them to prioritize refactoring?
- Can Fallow be integrated into GitHub Actions for CI checks on PRs?
FallowWeb Dev SimplifiedAI-assisted refactoringdead codeduplicate codecyclomatic complexitycognitive loadCRAP scoreVS Code extensionCI/CD integration
Full Transcript
One huge problem with AI is it tends to write code that's not very maintainable. One really common example is it likes to duplicate the exact same code between multiple different places. You can see this code is identical, but it's in two different places of the same file. And this happens all over the place. You can see here again this massive section of identical code between different places. On top of that, it also loves to create massive files. You can see this file is hundreds of lines long. And the functions in this file are actually quite complicated and difficult to parse for anyone that's trying to read what's going on.
On top of that, it's very common when you're changing around things for entire files to be completely unused because you change how the code is working and the AI just leaves the old code behind or it'll create a bunch of different exports for various different things. But these things never actually get exported or used anywhere else. So you have tons of dead code, duplicated code, and difficult to read code. And the problem is AI is really bad at actually finding and solving these problems, which is why the tool is absolutely amazing. It's a completely free command line tool that works very similar to ESLint, but it's built in a way that can be useful for your agents to be able to help fix particular problems and is really built to solve the problems that AI coding has.
But it's not just useful on AI projects. I'm going to show you how to use this on both an entirely handcoded project and an entirely vibecoded project. so you can see the pros and cons of using it in both scenarios and see how this is a perfect fit for any agentic workflow that you're using. Welcome back to WebDev Simplified. My name is Kyle and my job is to simplify the web for you. And to get started, we're going to be using. And to use inside of a project, all you need to do is just run npxallow.
And that'll get you started with a baseline of everything that you can see that this tool does. And then I'll show you how we can configure it and use it in a little bit more fine-tuned approach. You'll also notice that what we're focusing on here is the static intelligence. That's honestly the thing I think is most important about this tool and it's entirely free. But if you wanted some runtime related intelligence, you can pay for that optionally. But really the main thing you're going to be getting from this is that static intelligence. And again, it's entirely free, which is really nice.
And this isn't like a sponsored video or anything. I just really think this is a super useful tool. So any project that you want, we're going to go inside this project that's entirely vibe coded to show you what it looks like in like an agentic workflow. You can just type npx fow and then you're going to just say you want to install that and it's going to run through and it's actually going to give you a bunch of information. If we just scroll to the very top of where this is run, you can see a ton of information and I'll kind of explain exactly what everything inside this section is doing.
So the first thing that I think is really useful is that will automatically detect plugins. That essentially means like if you're using vit or nexjs or tanstack or various different frameworks or languages that are very common, it'll detect those plugins and automatically try to set up preconfiguration things based on those plugins you're using. So since this is a Tanstack project with Vit and I'm using Tailwind and so on, it'll have all those different plugins for me. The next thing here you can see is just some basic metrics about like dead code and so on. But really the important stuff is everything that comes below here.
So you can see we have an entire section on dead code and you can see it talks about like different files that are never even used. So I have a few shad sand components and then an entire file right here from a feature that used to be in the application but was removed but it looks like some of the code got left behind. Again, very common for AI to do this. You can also see unused exports. This means, for example, if I were to go into this particular file and I scroll to wherever that particular location was that the export was inside of this section down here, it's essentially saying that I am exporting this extract all audio function.
So, let's just go ahead and search for that. You can see that this has an export on it, but I'm never actually importing this code anywhere. So, really, it should not be exported at all. So, this is a great example of code that often gets exported. This is very common for AI to do, and you don't want that to be exported. So, you can go through here and fix all those particular problems. And again, it has its own fix command. You can just run fix like this and that'll autofix some of these things that are easier to fix.
Same thing here. If you have types that are being exported and not used, it's going to tell you about those. And for example, if we have some unused dependencies, you can see that they show up inside this list. And some dependencies you may only be using for testing. So you can use those and move them out of your production environment. So this is just a really great way to essentially say, hey, what is some code that you're not using? That's what this whole dead code section is useful for. The next section is duplication. And I find this to be the most important section.
And this just tells you all the places where you have duplicated code in your project. You can see it's not showing them all. It's only showing a few of them. But you can see if I were to click to go to this particular section. You can see that essentially all the code inside of this section is being duplicated with the code down in this section right here. It's exactly the same code for both of these. And it tells me exactly which lines. You can see right here, these are the exact lines being duplicated. It's about 100 lines of duplicated code.
So that's what the duplicate section is. If we keep going a little bit further, you can see some things about clone families. But again, that's just mostly all about duplication. And then we get to this complexity section, which is kind of like the health section of your application. And it determines how difficult are different things to understand. For example, here, this just shows us all of our functions that are very large. So you can see we have a function that's nearly 1500 lines. This one's 450. This one's 350. These are definitely bad functions if you have them that long.
So this is definitely code that we want to be able to clean up and make much easier to work with. So this gives me a good rough place for where all my largest functions are. You can also see this section on high complexity functions. This may look really complicated at first, but essentially it determines how difficult your function is to parse for you as well as how difficult it is to test. So cyclatic function complexity that just means how many different branches are there in your code. Every time you have like an if statement or a turnary or a switch statement, those are different branches for your code and every single place you have one is going to add to this cyclomatic complexity.
So you can see this has 115 branches in this one function. That is massive. Next we have the cognitive load that has a value of 133. And this is like how difficult is the code to read. For example, if you have nested if statements or nested loops, for example, those can be very difficult to parse and understand. So if you have nested things like that that are difficult to read, that's going to increase this score right here. And then finally, we have this crap score. This score essentially calculates not only how complex your function is, but how much of it is tested.
For example, if you have a function that's very complex, but it has a lot of test, it won't have quite as high of a crap score here. But if you have a function that doesn't have any test, that'll drastically increase this crap score here. So it's a great way of determining, okay, do I have my complex code being tested properly or maybe my somewhat complex code is not tested? Those will kind of show up and be flagged right here. Next, if we scroll by all of that, you can see in this there's a ton a ton of different functions that are quite complex.
We'll just keep going. You can see we finally get down to this file health score section. The way that this is calculated is essentially determines not only how complex the code is, it also determines how much of the code is dead code that's not being used at all and it also determines how many different code places are being imported and being exported. So for example, how many different files are importing this code and how many different files is this code importing. This will determine essentially what your file health is as well as it'll help correspond to what this risk is right here.
And that risk is just this crap score right there. So it's going to take all that information as well as maybe how large the function is and determine what the score is. Obviously, the higher the number, the better. So, you can see here, this is the lowest scoring section in Haiti here. And it's mostly because this code is 100% dead. But you can see some other code here that is quite difficult or complex to maintain. And essentially, this just determines how easy is your code to maintain. The lower your score, the more difficult the code is to maintain for various different reasons.
Finally, at the very bottom, we get this hotspot section, and this essentially tells us what places on the code are changing the most and maybe will cause the most potential problems. So this is going to take into account your git commit history and which files are changing the most frequently. So the more a file changes the more likely it is to occur in this section and if that file is also quite complex and difficult to work with it'll rank rather highly in this section as well. So this is an easy way to determine okay which files are changing a lot and which one of those files are quite complex because if you have a complex file that changes all the time that is obviously a huge problem and it'll be ranked very high here.
So the higher the number in this category the worse off you are. Finally, this thing I really like is just our refactoring targets. It determines, hey, what are the best places for me to refactor my code based on what's going to be the easiest and give me the most amount of return. So, you can see here, these are the places it's identified that I should change my code by either removing dead code or reducing complexity in some of my more complex functions. And this is going to give me essentially the most amount of bang for my buck.
And it kind of rates these just like this. Now, finally, at the bottom, I kind of get an overall score. And the nice thing is is if I want to be able to just compare, for example, what my dead code looks like or what my health looks like, that's really quite easy. I can run npm follow and I can just come in here and I can say dead code and that's going to run just the dead code portion. So you can see here now it's only showing me the things that are not being used or not being worked properly.
I can also do the same thing here with health. And that's going to give me all those health metrics that we were looking at just a little bit ago. And I can do this for all the different metrics that I want to be able to determine. And I can even narrow down exactly what metrics I want from each one, which is really nice. But this is just running the tool from the command line, which is great for getting an overview, but it's not that great if you want to be able to see this inside your editor.
So if you're actually working on a handcoded website or you want to just be able to see these errors in your editor and you're using VS Code, they have an extension that you can install. So, if I go to the extensions tab and search for you can see right here, it's by the company. I can just click install on that, that's going to install the extension and that's going to give me this little sidebar over here that essentially shows me everything that I get from running the command, but it's going to show it to me in a sidebar with a visual indicator inside my code.
So, if I wanted to look, for example, what files are unused? I can come in here and you can see I get a nice warning at the top. File is not reachable from any entry point. Essentially, nowhere is this code being imported from anywhere. I can also see, for example, which exports are not being used. So if I come into here, you can see that this function right here does not have any exports. You can see it's being unused. So I can just remove the export tag from here. Give that a save and that's going to solve that particular problem.
Now I get all my different unused and dead code sections at the very top here. And then at the bottom below all of this, I have a section for my duplicates. So here you can see I can click and I can click again. And you can see that this code has the exact same duplicate sections. You can see right here, just like that. Now, normally these repeated sections would have underlines squiggled under them to make it easy to know what's going on. I currently have that muted, but if you just search for and we want to unmute everything that's going on.
So if we just search, you can see here this show all findings clear mute. If we click on that, that's essentially going to get rid of that muting. So now you can see I get that underline for those different sections. And when I click around, you can see it's underlining all that duplicated code for me. So I know exactly which sections are duplicated, which makes it easy for me to configure what's going on. Now, more than likely, you're going to be using with some type of AI agent. So now I want to show you how you can set that up because it's actually incredibly easy.
The nice thing is is that has a skill you can use with any agent that supports skills. So to be able to use this skill, we just need to type npx skills addow- rs/fallow skills. We hit enter on that. That's going to go through the installation process for this skill. So let's just give that a second to download. We're just going to keep the defaults for everything. So we're going to click enter and I'm going to install this in my project directory and I'm going to say yes, I'm okay with installing that. And now if we look in this agents folder, you can see we have this skills file and we have a reference for all these different skills as well.
So we can see everything we want related to the skills that were being installed. And now our agent has access to those different skills. So we can for example open up an agent and we can just give it that skill by saying /fallow. That's going to give us the fow skill that we want. And this is quite small. So let me zoom this in and bring this way over for you so you can actually see what's going on. And then I could just for example say tell me which five files need to be refactored first.
Something like that. so it actually has access to what I'm trying to do inside of this project and it'll go through it'll run that fow command and the really nice thing about this command. I'll just get my zoom level back to normal is that we can sayow-json that's npx and we want this to be the format just like that and that's going to actually give us a JSON format back and that's essentially what these AIs are using. You can see we get JSON for everything and it gives a little bit more information on like what actions can be taken and how to solve this particular problem.
Now I'm just going to allow this command to run. So, it's going to go through and run everything that it needs to be able to set up and run and it's going to eventually give me the exact result that I want. So, once that finished running, you can see it gave me essentially a result with all the different things coming directly from that report, which is somewhat useful. But really, the more useful way to use this is you can tell your AI to implement a feature. And then you can say at the end to use to review itself essentially to fix any problems that come up with the code that it just created.
So, this is a really easy way for you to be able to say, "Hey, implement this feature AI and now run to check the code that you created to make sure it's not going against any of these policies I have set up." And hopefully, it can autocorrect itself to a degree. And if it doesn't, this you can run inside of CI and CD to make sure you actually check your code before it gets pushed into your main branch and deployed into your production environment. And that's because full CI integration with pretty much any CI tool you would want to use.
For example, I'll just bring this over. And if we look down here a little ways, you can see that in GitHub actions, all I need to do is just copy this code. And I have automatically set up GitHub actions. Every time I try to make a push or a pull request, it's going to run this particular code inside of just to make sure that everything is working properly. And it's going to give me nice markdown output in the comments telling me exactly what's wrong. And you can configure this however you want to like leave in code comments and so on.
But this is just a great way to force to run inside of your CI pipeline. So that way no matter what happens, this is always getting run before your code gets merged into your main branch. Now, the next thing I want to show you is how you actually use to be able to configure it properly. For example, this project is a fully handwritten project and there's a lot of things in here that I want to ignore. For example, if I run and I just run the dead code version, you're going to see that I get a lot of false positives essentially.
So, if I give that a second and I pull this up and I look inside this section a little bit higher, so I actually get to the point where I have the dead code showing up. And actually, I think what I want is the duplicated code section. So, I'll just run dupes here. that's going to run that duplicated code section. And this is actually where we're going to see a lot of really interesting things. First of all, I have some test files with a lot of duplicated code inside of them. That is perfectly okay. It's most of your tests are going to be duplicated code.
And you'll also see here, this is like a card game that I created. So, if we look, the definitions for a lot of the cards are very similar. You can see that they have a lot of similar code inside of them just because that's kind of the nature of creating cards. Each one is unique, but they have a lot of overlap between them. So, I kind of want to ignore all the files in this section. And also I have tons of different tests where all of the code is nearly the same. It's just a few different values that are changing between each one.
And that's okay because your test code should be super verbose and it's okay to duplicate your test code. So again, I want to skip that. And I have some files that are being purely generated from different TypeScript stuff. You can see this file was automatically generated. I probably want to skip those as well. So we can set up a configuration file to configure what we want to skip and ignore and so on. So I can just say npx fallow init. And honestly, if you're using in your project, we should probably install it. So I'm going to actually install it as a dev dependency.
So we're going to say npmi-dallow. That way this is inside the project. So anyone else that uses this project will automatically get installed for them. And now we can just run an enitpx init. And that's going to essentially create an initialization JSON file for us. So if we come in here, follow JSON. And now we can modify exactly what we want inside of here to make sure that we can maybe ignore those different test files and so on. So if we look inside of here, this ignore section is exactly what we want. So inside this section for ignore, let's make sure we put our comma there.
We can get rid of these comments cuz we don't need them. So let's just get rid of all these comments. And all we want to do is make sure we just ignore those sections I just talked about. So inside of our source folder, we have this data/public info. That's where all of these different card definitions are going. You can see card definitions, encounter sets, and so on. That's the stuff that we want to ignore. So I can just come inside of here. I can say dot slashsource slashdata oops slash productinfo and that should hopefully ignore all of those different sections of our code.
So let's try to rerun this dupe section again. And let's see if now those are properly ignored. And we can see here it looks like they're not quite being ignored like I would expect. They're still showing up inside my list. That may be because I just typed that in wrong. Maybe no dot slash at the start. And there we go. That looks like it did remove them. And if we scroll through this section, you can see there's very few things showing up. Next, I have my tests showing up. So, let's make sure that we ignore anything that has that test folder.
So, we can say starst star tests star just like that. And now all those test sections should be removed as well. And now you can see no tests are showing up in my dupes. And I was able to remove all those different things that didn't make sense to show up in this duplicated section. Now, let's say I wanted to modify how my duplicate code was actually checked. We can come into this duplicate section. And if we actually search for mode, this determines what mode we want to use. By default, it uses the mild mode. But if you wanted to be a little bit more strict, you could actually change to semantic mode.
And the semantic mode is not only going to check for duplicates where all the variables are the same name, but also, let's say, for example, you rename a variable to something else and then duplicate all the rest of the code. It'll check those scenarios as well. So, this is just essentially a slightly more strict version where it'll check even more sections of your code. And I'd recommend changing to semantic once you kind of get the mild version configured in your codebase to make sure all your duplicates are found. Swatch this over to semantic and that'll help find all those different errors in your code as well that have just variable renaming or string renaming.
Now sometimes you may run into an issue where for example this code right here that's being marked as duplicated. I actually don't think that this is duplicated. I don't want to change it and I want to essentially ignore this entire duplicated section. So to do that, I can just come up here and I can add a comment at the very top of my file. And this is going to sayow ignore file. And then if I want to, I can add what type I'm actually ignoring. And we're going to ignore code duplication. Just like that. If I give that a save, you can see that warning has gone away down here.
And if I actually run this code, this adjust damage section right here should completely disappear. And you can see it has been removed. And there are now less things showing up inside this list. I could also fix the same thing like if I had an export that was no longer being used. So for example, let's say I exported this erroneously. You're going to see I will get an error on this. Export is unused. I could just come in here. I can add a ignore next line. And then I could also give it a type specifically if I wanted, which I would generally recommend.
So I can just put unused export. And that'll make sure that it's allowing me to put this export in there even though I, you know, shouldn't do it. So this is just a way to override specific scenarios if you know that there are one-off scenarios where it should be overridden. But for the most part, if you actually want to override what's going on, you should just do that directly inside this configuration file here. Now, another nice thing about is it lets you fix all your issues. So, you can just run npxallow fix and it's going to go through and automatically fix all the issues for you.
I already ran this a little bit ago, but it did fix 20 issues. This is mostly things like auto export and import changes and dead code like that. But, it's really nice that you can automatically fix those for yourself. Also, a really nice thing about is it since it works really well with Git, you can actually really easily compare between like the main branch and whatever branch you're currently on to only see the issues that are changing in your current PR. For example, I just swapped over to a complete branch that has some additional changes on it.
And if I run and I just put audit at the end of it, what that's going to do is it's only going to compare the code that has changed between what I'm currently running on my branch and the main branch. And you can tell it to use other MA branches than the main branch. But this now lets me look at all the things that are bad just with the new code that I've created. And this is great. Once you actually get set up and working in your code, you can then use this to essentially say, hey, now what has become bad because of the changes I have made.
And this is a great thing to run in all of your different poll requests inside of your CI. And this is essentially what runs when you set up that CI command in GitHub actions or whatever. It runs this audit to determine what has changed between this poll request and the main code you're trying to merge directly into. And you can see there's a lot of stuff going on in this code that I definitely need to fix. And if you enjoyed this video where I was showing you how to set up for AI, you're going to love this video right over here where I show you how to set up your own local AI you can run entirely for free that can honestly compete with something like Claude Sonnet.
And again, it's entirely free and this is a master class on how to set up local AI. That video is going to be right over here. I highly recommend you check it out. With that said, thank you very much for watching and have a good
More from Web Dev Simplified
Get daily recaps from
Web Dev Simplified
AI-powered summaries delivered to your inbox. Save hours every week while staying fully informed.



