Shipping a Long-Stalled .NET Library with an AI Agent

When I used to work extensively in the Vue ecosystem, Nuxt Content was the one tool I reached for every time I needed to serve content. Once I transitioned back to the .NET world, I missed it desperately. Yet, every time I sat down to rebuild that concept in .NET, I would hit a wall. Worn down by the sheer volume of boilerplate and plumbing it takes to stand up even a simple .NET tool from scratch, I’d quietly give up.

The underlying concept is beautifully simple: you drop a Markdown file into a folder, and it automatically becomes a page. You call a query function, and your articles come back as clean data. No heavy CMS, no database configuration, no admin panels: just flat files and a fluent query API.

This isn't a typical "look at my new framework" post. This is the case study of an experiment: could agentic AI help me resurrect an idea I had abandoned multiple times and shepherd it into something genuinely production-ready? The result of this experiment is Anudwigna.StaticMarkdownEngine, a lightweight .NET library that transforms a folder of Markdown files into a fully routed .NET site with a LINQ-queryable content index. But the library itself is almost beside the point. The compelling part is how it got built.

With the rise of agentic AI engineering, I wanted to put the paradigm to a true stress test. While I had been using AI assistants for a long time, it was always within the safety rails of an existing codebase. For this project, I set a strict constraint: I wanted to follow a complete software lifecycle from initial concept to NuGet deployment without writing a single line of code myself.


The Experiment, Stated Plainly

I wasn't trying to prove that AI can generate code; that debate is settled. I wanted to answer a much narrower, more rigorous set of questions:

  • Could an agent help me think the idea through from scratch, rather than just typing out an architectural design I had already finalized in my head?
  • Could the footprint stay small, a tool I could easily hold in my head, instead of ballooning into an over-engineered mess?
  • Could it clear the quality bar I actually care about: a production-ready library, rather than a brittle weekend demo that collapses on its second edge case?

The objectives were clear, but the real test was my own readiness for agentic software engineering. Could I communicate effectively enough to extract the precise architecture I wanted?

As it turns out, maintaining your ground is the hardest part of working with an autonomous agent. It is incredibly easy to give in to the code the agent presents to you, or to throw your hands up when a prompt goes off the rails. I wanted to see if I could remain headstrong and steer the system to build the exact vision I had in mind.


Conceptualizing with an Agent

This phase was surprisingly enjoyable. I came to the table with a vague, high-level shape ("Nuxt Content, but make it .NET") and used the agent as an architectural sounding board to pin down the details I had historically glossed over.

The decision that unlocked the entire project was the content model. Before writing code, we debated several structural options and landed on a two-tier system. Giving them distinct definitions made everything else click into place:

Folder Purpose Analogy in Nuxt
input/ Standalone pages (e.g., About, Privacy) pages/ + content/
content/ Articles/Posts meant for listing and querying content/ + queryContent()

Both directories look for standard .md files with optional YAML front matter; the core difference lies in how they are processed. A file at input/about.md resolves directly to the /about route. Meanwhile, articles inside content/ are parsed and indexed in memory, allowing a home page or blog index to sort, filter, and paginate them using plain LINQ.

What caught me off guard was how much value came from the friction of our back-and-forth. An agent will frequently present a shiny, sophisticated solution that looks perfect on paper, but it requires human intuition to evaluate the trajectory it's taking.

For instance, the agent initially pushed hard for a single, unified folder where pages and blog posts were discriminated by metadata or nested subfolders. I dug my heels in. I wanted two explicit, top-level directories because, from a human UX perspective, it is infinitely easier for a developer to navigate a root directory with clear intent rather than digging through arbitrary configurations. Once we established that boundary, the agent adapted and didn't look back.


What the Engine Looks Like

To prove this isn't just a theoretical exercise, here is a look at the architecture we shipped. The feature set was intentionally kept lean and focused:

  • Markdown parsing via Markdig with advanced extensions enabled (tables, footnotes, task lists, auto-links).
  • YAML front matter parsing for title, description, date, and an open dictionary for custom metadata fields.
  • Strict file-based routing where your folder hierarchy mirrors your URL structure.
  • An in-memory, LINQ-queryable content index via contentRepo.Query().
  • Automatic internal markdown link rewriting (e.g., converting [About](/about) to /about).
  • Auto-generated content excerpts, a dynamic route transformer, a custom <markdown-content> tag helper, and a lightweight CLI.

Integrating the library looks exactly like the clean .NET code you would expect. First, you register the services in your dependency injection container:

builder.Services.AddMarkdownEngine(options =>
    options.OutputDirectory = Path.Combine(env.ContentRootPath, "output"));

builder.Services.AddContentRepository(options =>
{
    options.ContentDirectory = Path.Combine(env.ContentRootPath, "content");
    options.OutputDirectory  = Path.Combine(env.ContentRootPath, "output");
});

From there, the engine compiles your assets at startup, maps the file-based routes, and exposes your content as a standard collection:

var latestArticles = contentRepo.Query()
    .OrderByDescending(p => p.FrontMatter.Date)
    .Skip((page - 1) * pageSize)
    .Take(pageSize)
    .ToList();

That fluent Query() call was the moment the project finally felt like Nuxt Content. Because it returns standard collections, it leverages native LINQ, meaning neither I nor the agent had to invent a proprietary querying language.

This design was critical for making the library feel native to a .NET developer. However, getting there exposed some interesting systemic flaws. When selecting a Markdown parser, the agent repeatedly recommended obscure, half-baked, or abandoned open-source repositories instead of well-established libraries like Markdig.

Vetting these internals was a massive hurdle. The foundational dependencies you introduce dictate the security, performance, and longevity of your software. In an era where AI can effortlessly hallucinate packages or pulled-from-github fragments, human-driven supply chain security is non-negotiable.


Putting It to Work

The most satisfying validation did not come from the test suite; it came when the engine quietly slipped into my actual workflow at work. I run an internal issue-reporting system, and I have wired the engine straight into my agentic setup. The moment I finish working on an issue, the agent writes up a report.md and drops it into a designated folder. I restart the application, and the report is instantly live as a clean, routed webpage. There is no copy-pasting into a wiki and no fiddling with formatting, just Markdown in and a published page out.

It has quietly turned documentation, the chore I usually avoid, into something that happens almost for free.

šŸ’¬ My Take: This is the part I did not see coming. I set out to build a blog engine and accidentally built a reporting pipeline. That is usually a good sign that an abstraction is the right size: it ends up solving a problem you never explicitly aimed at.

What Comes Next

There is one obvious rough edge in that loop: the restart. The engine currently reads and renders everything once, at startup, so a freshly written report.md only appears after I bounce the application. The next milestone I want is automatic change detection: watch the content folder, and when a file is added or edited, re-render just that article on the fly. .NET hands me most of this for free through FileSystemWatcher, and the render pipeline is deliberately small, so as long as I can add it without turning a simple flat-file tool into a stateful, cache-invalidating mess, live content reloading feels like the natural next step.


What Agentic AI Was Good and Bad At

šŸ’¬ My Take: The honest ledger. The agent saved me hours of uninspired labor by handling the boilerplate, the configuration plumbing, and the repetitive wiring that usually makes me walk away from a project. However, my judgment remained entirely non-negotiable when it came to establishing sensible naming conventions, enforcing a tight project scope, and knowing exactly when a feature was "done."

Evaluating the agent's performance reveals a clear dichotomy between raw execution speed and critical restraint:

🟢 Where the Agent Excelled

  • Boilerplate Elimination: It generated multi-targeting project files, dynamic route transformers, and tag helpers instantly.
  • Edge-Case Scaffolding: It rapidly built out testing frameworks and verified obscure Markdown formatting variations that I would have been too lazy to manually test.
  • Momentum Maintenance: It completely eliminated the "activation energy" barrier. I never sat staring at a blank file wondering where to start.

šŸ”“ Where the Agent Stumbled

  • Scope Creep: The agent has no innate concept of enough. If left unchecked, it would have added caching layers, database syncs, and configuration parameters that completely violated the "simple flat-file" ethos.
  • Dependency Blindness: It struggled to differentiate between a highly trusted ecosystem standard and an unvetted, insecure GitHub repository.
  • Contextual Elegance: It fell back on overly verbose naming patterns and complex abstractions where a simple C# language feature would suffice.

Closing Thoughts

The library itself is a great souvenir, but the experiment was the real reward. I have wanted this specific Markdown engine for years, but I never built it, not because the logic was too complex, but because the boring, logistical middle-ground of setting up a new .NET project was enough to drain my enthusiasm every single time.

šŸ’¬ My Take: The ultimate takeaway for developers is that agents are an incredible tool for removing the friction of execution, but they are a terrible substitute for intent. Use agents to automate the plumbing and eliminate the cognitive tax of boilerplate. But never outsource your taste, your architectural boundaries, or your responsibility to safeguard your dependencies. Your job is shifting from writer to editor, and your judgment is your most valuable asset.

Agentic AI didn't magically turn me into a better software engineer. Instead, it did something much better: it took care of the chores, allowing me to spend 100% of my mental energy on the architectural decisions that actually mattered.


The engine is available on NuGet. In fact, this very blog is powered by it.