<?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: Ronak Parmar</title>
    <description>The latest articles on DEV Community by Ronak Parmar (@ronak_parmar_033c50d168b5).</description>
    <link>https://dev.to/ronak_parmar_033c50d168b5</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3826925%2Ffbae4883-d4ec-498b-8aeb-697540be41c1.jpg</url>
      <title>DEV Community: Ronak Parmar</title>
      <link>https://dev.to/ronak_parmar_033c50d168b5</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ronak_parmar_033c50d168b5"/>
    <language>en</language>
    <item>
      <title>Why I Reimplemented 22 Unix Tools in Go for AI Agents</title>
      <dc:creator>Ronak Parmar</dc:creator>
      <pubDate>Mon, 06 Apr 2026 14:12:20 +0000</pubDate>
      <link>https://dev.to/ronak_parmar_033c50d168b5/why-i-reimplemented-22-unix-tools-in-go-for-ai-agents-21f0</link>
      <guid>https://dev.to/ronak_parmar_033c50d168b5/why-i-reimplemented-22-unix-tools-in-go-for-ai-agents-21f0</guid>
      <description>&lt;p&gt;I spent three weeks rebuilding &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;cat&lt;/code&gt;, &lt;code&gt;find&lt;/code&gt;, &lt;code&gt;stat&lt;/code&gt;, &lt;code&gt;diff&lt;/code&gt;, and 16 other Unix coreutils in Go. Not because the originals are broken — they're masterpieces of systems programming that have survived decades of use. I rebuilt them because AI coding agents are terrible at reading their output.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem Nobody Talked About
&lt;/h2&gt;

&lt;p&gt;Every time an AI agent runs &lt;code&gt;ls src/&lt;/code&gt;, it receives something like this:&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="nt"&gt;-rw-r--r--&lt;/span&gt;  1 user  staff  2048 Apr  6 12:00 main.go
drwxr-xr-x  3 user  staff    96 Apr  6 11:00 internal
lrwxr-xr-x  1 user  staff    12 Apr  6 10:00 &lt;span class="nb"&gt;link&lt;/span&gt; -&amp;gt; main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent has to figure out which column is the filename. Which is the size. Whether that &lt;code&gt;d&lt;/code&gt; at the start means directory. Whether &lt;code&gt;Apr  6&lt;/code&gt; means this year or last year. It guesses. Sometimes it guesses wrong. And every wrong guess costs tokens, introduces errors, and degrades the quality of the code it writes.&lt;/p&gt;

&lt;p&gt;Now multiply that by every &lt;code&gt;grep&lt;/code&gt;, every &lt;code&gt;cat&lt;/code&gt;, every &lt;code&gt;find&lt;/code&gt; the agent runs in a single session. The token waste is staggering. The parsing fragility is a constant source of subtle bugs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Insight
&lt;/h2&gt;

&lt;p&gt;AI agents don't need pretty terminal output. They need structured data. They need to know that &lt;code&gt;main.go&lt;/code&gt; is 2048 bytes, was modified 3600 seconds ago, is written in Go, has MIME type &lt;code&gt;text/x-go&lt;/code&gt;, and is not a binary file. They need this information labeled, unambiguous, and machine-readable.&lt;/p&gt;

&lt;p&gt;So I asked: what if &lt;code&gt;ls&lt;/code&gt; returned XML?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ls&lt;/span&gt; &lt;span class="na"&gt;timestamp=&lt;/span&gt;&lt;span class="s"&gt;"1712404800"&lt;/span&gt; &lt;span class="na"&gt;total_entries=&lt;/span&gt;&lt;span class="s"&gt;"3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;file&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"main.go"&lt;/span&gt; &lt;span class="na"&gt;path=&lt;/span&gt;&lt;span class="s"&gt;"src/main.go"&lt;/span&gt; &lt;span class="na"&gt;absolute=&lt;/span&gt;&lt;span class="s"&gt;"/project/src/main.go"&lt;/span&gt;
        &lt;span class="na"&gt;size_bytes=&lt;/span&gt;&lt;span class="s"&gt;"2048"&lt;/span&gt; &lt;span class="na"&gt;size_human=&lt;/span&gt;&lt;span class="s"&gt;"2.0 KiB"&lt;/span&gt;
        &lt;span class="na"&gt;modified=&lt;/span&gt;&lt;span class="s"&gt;"1712404800"&lt;/span&gt; &lt;span class="na"&gt;modified_ago_s=&lt;/span&gt;&lt;span class="s"&gt;"3600"&lt;/span&gt;
        &lt;span class="na"&gt;language=&lt;/span&gt;&lt;span class="s"&gt;"go"&lt;/span&gt; &lt;span class="na"&gt;mime=&lt;/span&gt;&lt;span class="s"&gt;"text/x-go"&lt;/span&gt; &lt;span class="na"&gt;binary=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;directory&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"internal"&lt;/span&gt; &lt;span class="na"&gt;path=&lt;/span&gt;&lt;span class="s"&gt;"src/internal"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;symlink&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"link"&lt;/span&gt; &lt;span class="na"&gt;target=&lt;/span&gt;&lt;span class="s"&gt;"main.go"&lt;/span&gt; &lt;span class="na"&gt;broken=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ls&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Zero ambiguity. Zero parsing. The agent reads the attributes and knows exactly what it's looking at. No regex to extract filenames from column-aligned text. No heuristic to determine if something is a directory. No guesswork.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why XML and Not JSON?
&lt;/h2&gt;

&lt;p&gt;Good question. JSON is the lingua franca of APIs. But XML has a structural advantage that matters for AI context windows: &lt;strong&gt;attributes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Compare these two representations of the same file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;file&lt;/span&gt; &lt;span class="na"&gt;size_bytes=&lt;/span&gt;&lt;span class="s"&gt;"2048"&lt;/span&gt; &lt;span class="na"&gt;language=&lt;/span&gt;&lt;span class="s"&gt;"go"&lt;/span&gt; &lt;span class="na"&gt;mime=&lt;/span&gt;&lt;span class="s"&gt;"text/x-go"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"size_bytes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"language"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"go"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"mime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text/x-go"&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;The XML version is 40 characters. The JSON version is 60. That's a 33% difference. When you're listing 1,000 files, that's tens of thousands of tokens saved. AI context windows are expensive and limited. Every character counts.&lt;/p&gt;

&lt;p&gt;That said, &lt;code&gt;aict&lt;/code&gt; supports &lt;code&gt;--json&lt;/code&gt; for every tool. The schema is identical. Use whatever your pipeline prefers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Go?
&lt;/h2&gt;

&lt;p&gt;Three reasons:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Single binary.&lt;/strong&gt; Go compiles to a static binary with zero runtime dependencies. &lt;code&gt;aict&lt;/code&gt; is one file you drop on a system and it works. No &lt;code&gt;pip install&lt;/code&gt;, no &lt;code&gt;npm install&lt;/code&gt;, no shared libraries to manage. For a tool that's supposed to replace coreutils, this is non-negotiable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Standard library only.&lt;/strong&gt; Every feature — regex matching, MIME detection, filesystem walking, XML encoding — uses Go's standard library. Zero external dependencies means zero supply chain risk, zero version conflicts, and the ability to audit the entire codebase in an afternoon.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance is good enough.&lt;/strong&gt; Yes, &lt;code&gt;aict grep&lt;/code&gt; is slower than &lt;code&gt;ripgrep&lt;/code&gt;. Yes, &lt;code&gt;aict ls&lt;/code&gt; is slower than &lt;code&gt;eza&lt;/code&gt;. But we're talking 15ms vs 2ms for listing 1,000 files. The overhead comes from language detection, MIME sniffing, and structured output — features that are the entire point of the project. For normal codebases, the difference is imperceptible.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Twenty-two tools across five categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;File inspection&lt;/strong&gt;: &lt;code&gt;cat&lt;/code&gt;, &lt;code&gt;head&lt;/code&gt;, &lt;code&gt;tail&lt;/code&gt;, &lt;code&gt;file&lt;/code&gt;, &lt;code&gt;stat&lt;/code&gt;, &lt;code&gt;wc&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Directory &amp;amp; search&lt;/strong&gt;: &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;find&lt;/code&gt;, &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;diff&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Path utilities&lt;/strong&gt;: &lt;code&gt;realpath&lt;/code&gt;, &lt;code&gt;basename&lt;/code&gt;, &lt;code&gt;dirname&lt;/code&gt;, &lt;code&gt;pwd&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text processing&lt;/strong&gt;: &lt;code&gt;sort&lt;/code&gt;, &lt;code&gt;uniq&lt;/code&gt;, &lt;code&gt;cut&lt;/code&gt;, &lt;code&gt;tr&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;System &amp;amp; environment&lt;/strong&gt;: &lt;code&gt;env&lt;/code&gt;, &lt;code&gt;system&lt;/code&gt;, &lt;code&gt;ps&lt;/code&gt;, &lt;code&gt;df&lt;/code&gt;, &lt;code&gt;du&lt;/code&gt;, &lt;code&gt;checksums&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Plus a &lt;code&gt;git&lt;/code&gt; subcommand suite (&lt;code&gt;status&lt;/code&gt;, &lt;code&gt;diff&lt;/code&gt;, &lt;code&gt;log&lt;/code&gt;, &lt;code&gt;ls-files&lt;/code&gt;, &lt;code&gt;blame&lt;/code&gt;) and an MCP server that exposes every tool as a callable function to AI assistants like Claude and Cursor.&lt;/p&gt;

&lt;p&gt;Every tool supports three output modes: XML, JSON, and plain text. Every error is structured data in stdout, never stderr. Every path is absolute. Every timestamp is a Unix epoch integer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The MCP Server
&lt;/h2&gt;

&lt;p&gt;This is where it gets interesting. &lt;code&gt;aict&lt;/code&gt; ships with an MCP (Model Context Protocol) server binary called &lt;code&gt;aict-mcp&lt;/code&gt;. You configure it in Claude Desktop or Cursor, and suddenly every tool becomes a typed, callable function.&lt;/p&gt;

&lt;p&gt;The AI agent doesn't shell out to run &lt;code&gt;aict ls src/&lt;/code&gt;. It calls the &lt;code&gt;ls&lt;/code&gt; function with &lt;code&gt;{path: "src/"}&lt;/code&gt; and receives structured JSON. No shell spawning. No output parsing. No ambiguity.&lt;/p&gt;

&lt;p&gt;This is the future of how AI agents interact with filesystems. Not by typing commands into a terminal and reading the output like a human would. By calling typed functions and receiving typed responses.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Didn't Build
&lt;/h2&gt;

&lt;p&gt;I intentionally excluded write operations: &lt;code&gt;cp&lt;/code&gt;, &lt;code&gt;mv&lt;/code&gt;, &lt;code&gt;rm&lt;/code&gt;, &lt;code&gt;mkdir&lt;/code&gt;, &lt;code&gt;chmod&lt;/code&gt;, &lt;code&gt;chown&lt;/code&gt;. These are dangerous when called by AI agents without human confirmation. &lt;code&gt;aict&lt;/code&gt; is a read-only tool. It observes, it doesn't modify.&lt;/p&gt;

&lt;p&gt;I also didn't try to match GNU coreutils flag-for-flag. Where a flag made sense for the AI use case, I added it. Where it didn't, I skipped it. The goal is not compatibility — it's utility for AI agents.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Honest Benchmark
&lt;/h2&gt;

&lt;p&gt;I benchmarked &lt;code&gt;aict&lt;/code&gt; against GNU coreutils. Here are the results:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;GNU&lt;/th&gt;
&lt;th&gt;aict&lt;/th&gt;
&lt;th&gt;Ratio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;ls&lt;/code&gt; (1,000 files)&lt;/td&gt;
&lt;td&gt;~2ms&lt;/td&gt;
&lt;td&gt;~15ms&lt;/td&gt;
&lt;td&gt;7×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;grep&lt;/code&gt; (100k lines)&lt;/td&gt;
&lt;td&gt;~1ms&lt;/td&gt;
&lt;td&gt;~100ms&lt;/td&gt;
&lt;td&gt;100×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;find&lt;/code&gt; (deep tree)&lt;/td&gt;
&lt;td&gt;~2ms&lt;/td&gt;
&lt;td&gt;~9ms&lt;/td&gt;
&lt;td&gt;5×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;cat&lt;/code&gt; (100k lines)&lt;/td&gt;
&lt;td&gt;~1ms&lt;/td&gt;
&lt;td&gt;~23ms&lt;/td&gt;
&lt;td&gt;17×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;diff&lt;/code&gt; (1,000 lines)&lt;/td&gt;
&lt;td&gt;~1ms&lt;/td&gt;
&lt;td&gt;~10ms&lt;/td&gt;
&lt;td&gt;10×&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;grep&lt;/code&gt; and &lt;code&gt;cat&lt;/code&gt; are slow because every file is MIME-typed and language-detected. Use &lt;code&gt;--plain&lt;/code&gt; to skip enrichment when you only need content. The trade-off is intentional: more tokens spent on parsing vs. more semantic information returned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is This Actually Useful?
&lt;/h2&gt;

&lt;p&gt;I've been using &lt;code&gt;aict&lt;/code&gt; with Claude and Cursor for two months. The difference is noticeable. The agent makes fewer mistakes about file types. It doesn't confuse directories with files. It correctly identifies binary files before trying to read them. It understands the structure of a codebase faster.&lt;/p&gt;

&lt;p&gt;The token savings are real. A directory listing that used to cost 2,000 tokens in plain text now costs 800 in XML with three times the information density. Over a typical coding session with dozens of tool calls, that adds up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open Source
&lt;/h2&gt;

&lt;p&gt;The project is MIT licensed and on GitHub. It's written in Go with zero external dependencies. You can audit the entire codebase in an afternoon. I'd love contributions — new tools, performance improvements, bug fixes.&lt;/p&gt;

&lt;p&gt;If you build AI agents that interact with codebases, give it a try. Your agent will thank you. And if it doesn't work for your use case, that's fine too. GNU coreutils aren't going anywhere.&lt;/p&gt;

&lt;p&gt;The repo is at &lt;a href="https://github.com/synseqack/aict" rel="noopener noreferrer"&gt;github.com/synseqack/aict&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>agentaichallenge</category>
      <category>claude</category>
    </item>
    <item>
      <title>I got tired of configuring the same stack over and over, so I built a modular project assembler</title>
      <dc:creator>Ronak Parmar</dc:creator>
      <pubDate>Wed, 25 Mar 2026 13:26:48 +0000</pubDate>
      <link>https://dev.to/ronak_parmar_033c50d168b5/i-got-tired-of-configuring-the-same-stack-over-and-over-so-i-built-a-modular-project-assembler-e1m</link>
      <guid>https://dev.to/ronak_parmar_033c50d168b5/i-got-tired-of-configuring-the-same-stack-over-and-over-so-i-built-a-modular-project-assembler-e1m</guid>
      <description>&lt;p&gt;Every side project I started followed the same ritual.&lt;/p&gt;

&lt;p&gt;Find a starter. Clone it. Realize it doesn't have the exact &lt;br&gt;
combination I need — say, Next.js with Express as a separate &lt;br&gt;
backend, PostgreSQL, JWT auth, and Tailwind. Start adding things. &lt;br&gt;
Watch the tsconfig break. Spend 45 minutes on Stack Overflow. &lt;br&gt;
Finally start actually building at 11pm, mentally exhausted.&lt;/p&gt;

&lt;p&gt;I did this enough times that I started keeping a folder of &lt;br&gt;
"my personal starters." Which worked until I had six of them and &lt;br&gt;
they were all slightly different and none of them had the latest &lt;br&gt;
versions of anything.&lt;/p&gt;

&lt;p&gt;So I built Foundation CLI instead.&lt;/p&gt;


&lt;h2&gt;
  
  
  What it is
&lt;/h2&gt;

&lt;p&gt;Foundation CLI is a dependency-aware project assembler. You describe &lt;br&gt;
your stack — frontend, backend, database, auth, UI, deployment — and &lt;br&gt;
instead of copying static template files, it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Resolves the full module dependency graph&lt;/li&gt;
&lt;li&gt;Detects and handles conflicts automatically&lt;/li&gt;
&lt;li&gt;Merges configs intelligently (deep merge for package.json, 
key-dedup for .env, semver intersection for requirements.txt)&lt;/li&gt;
&lt;li&gt;Commits everything atomically — or not at all&lt;/li&gt;
&lt;/ol&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%2Fraw.githubusercontent.com%2Fronak-create%2FFoundation-Cli%2Fmain%2Fpublic%2Fdemo.gif" 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%2Fraw.githubusercontent.com%2Fronak-create%2FFoundation-Cli%2Fmain%2Fpublic%2Fdemo.gif" alt="Demo" width="400" height="225"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @systemlabs/foundation-cli create
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The part that was interesting to build
&lt;/h2&gt;

&lt;p&gt;The dependency resolver was the core challenge. Modules don't &lt;br&gt;
conflict by name — they conflict by capability. "Auth JWT" and &lt;br&gt;
"Auth OAuth" are different implementations of the same capability. &lt;br&gt;
The resolver uses capability tokens, not module IDs, to detect this.&lt;/p&gt;

&lt;p&gt;Then it runs Kahn's algorithm to build a topological sort of the &lt;br&gt;
module execution order — because if Tailwind needs to run after &lt;br&gt;
Next.js (to patch the config correctly), that dependency needs to be &lt;br&gt;
explicit and enforced.&lt;/p&gt;

&lt;p&gt;Conflicts come in two tiers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hard conflicts&lt;/strong&gt; — two auth modules, two frontends. Block the 
entire scaffold.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Advisory conflicts&lt;/strong&gt; — Express + Cloudflare Workers (Express 
doesn't run on the edge). Warn, but don't block.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The config merge problem
&lt;/h2&gt;

&lt;p&gt;This is the part that template copiers get wrong. When you add &lt;br&gt;
Tailwind to a Next.js + Express project, three different files need &lt;br&gt;
to change:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;package.json&lt;/code&gt; — new devDependencies&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tailwind.config.js&lt;/code&gt; — new file&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;globals.css&lt;/code&gt; — Tailwind directives&lt;/li&gt;
&lt;li&gt;Possibly &lt;code&gt;next.config.mjs&lt;/code&gt; — PostCSS config&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A static template can't do this. You either have a template per &lt;br&gt;
combination (exponential), or you have a module system that knows &lt;br&gt;
how to merge.&lt;/p&gt;

&lt;p&gt;Foundation CLI's merge engine handles this per file type. JSON files &lt;br&gt;
get deep-merged with conflict detection. &lt;code&gt;.env&lt;/code&gt; files get &lt;br&gt;
key-deduplicated. &lt;code&gt;docker-compose.yml&lt;/code&gt; gets service-merged. &lt;br&gt;
&lt;code&gt;requirements.txt&lt;/code&gt; gets semver-intersected.&lt;/p&gt;




&lt;h2&gt;
  
  
  Zero partial scaffolds
&lt;/h2&gt;

&lt;p&gt;Every write goes through a FileTransaction. Files are staged to a &lt;br&gt;
temp directory. If anything fails — a template render error, a &lt;br&gt;
missing dependency, a hook failure — the temp dir is deleted and &lt;br&gt;
the output directory is left completely untouched.&lt;/p&gt;

&lt;p&gt;You either get a complete, working project or you get nothing. No &lt;br&gt;
mystery half-generated directories.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's in it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;28 built-in modules across 7 categories&lt;/li&gt;
&lt;li&gt;8 project archetypes (SaaS, AI App, E-commerce, API Backend, etc.) 
with pre-filled smart defaults&lt;/li&gt;
&lt;li&gt;Plugin SDK — third-party modules publish to npm with 
&lt;code&gt;foundation-plugin&lt;/code&gt; keyword&lt;/li&gt;
&lt;li&gt;TypeScript throughout, strict mode, all generated projects 
pass &lt;code&gt;tsc --noEmit&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @systemlabs/foundation-cli create
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repo: &lt;a href="https://github.com/ronak-create/Foundation-Cli" rel="noopener noreferrer"&gt;https://github.com/ronak-create/Foundation-Cli&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'd love feedback — especially if you've built something similar &lt;br&gt;
and solved the config merge problem differently. The current &lt;br&gt;
approach works but I'm not convinced it's the best design.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>typescript</category>
      <category>node</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Open-sourcing Foundation CLI — a dependency-aware project scaffolding tool</title>
      <dc:creator>Ronak Parmar</dc:creator>
      <pubDate>Mon, 16 Mar 2026 10:06:11 +0000</pubDate>
      <link>https://dev.to/ronak_parmar_033c50d168b5/open-sourcing-foundation-cli-a-dependency-aware-project-scaffolding-tool-pan</link>
      <guid>https://dev.to/ronak_parmar_033c50d168b5/open-sourcing-foundation-cli-a-dependency-aware-project-scaffolding-tool-pan</guid>
      <description>&lt;p&gt;I’ve been experimenting with a CLI tool for my own workflow that tries to simplify starting new projects.&lt;/p&gt;

&lt;p&gt;The idea is that instead of manually wiring frameworks, databases, auth, etc., you describe the stack you want and the CLI generates the project structure.&lt;/p&gt;

&lt;p&gt;For example something like:&lt;/p&gt;

&lt;p&gt;"I want a SaaS with Next.js, Express, PostgreSQL and JWT auth"&lt;/p&gt;

&lt;p&gt;The tool resolves dependencies, merges configs, and sets up the integration code automatically.&lt;/p&gt;

&lt;p&gt;I'm curious if people here actually find tools like this useful, or if most devs prefer starting projects manually.&lt;/p&gt;

&lt;p&gt;Would love to hear how others approach bootstrapping new projects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ronak-create/Foundation-Cli" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;br&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.amazonaws.com%2Fuploads%2Farticles%2Fj5ey69ttzx3jdd1uyzyl.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.amazonaws.com%2Fuploads%2Farticles%2Fj5ey69ttzx3jdd1uyzyl.png" alt="Tool Preview" width="800" height="744"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>devops</category>
      <category>discuss</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
