惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
G
GRAHAM CLULEY
P
Privacy & Cybersecurity Law Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
宝玉的分享
宝玉的分享
P
Proofpoint News Feed
H
Help Net Security
V
Visual Studio Blog
阮一峰的网络日志
阮一峰的网络日志
C
Cisco Blogs
人人都是产品经理
人人都是产品经理
Know Your Adversary
Know Your Adversary
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Recorded Future
Recorded Future
I
Intezer
罗磊的独立博客
T
The Exploit Database - CXSecurity.com
Blog — PlanetScale
Blog — PlanetScale
Malwarebytes
Malwarebytes
Spread Privacy
Spread Privacy
T
Tor Project blog
V
Vulnerabilities – Threatpost
云风的 BLOG
云风的 BLOG
腾讯CDC
B
Blog RSS Feed
Stack Overflow Blog
Stack Overflow Blog
F
Future of Privacy Forum
MyScale Blog
MyScale Blog
Latest news
Latest news
IT之家
IT之家
MongoDB | Blog
MongoDB | Blog
The Hacker News
The Hacker News
S
Securelist
博客园 - 【当耐特】
C
CXSECURITY Database RSS Feed - CXSecurity.com
T
Threat Research - Cisco Blogs
Jina AI
Jina AI
Cisco Talos Blog
Cisco Talos Blog
B
Blog
博客园 - 三生石上(FineUI控件)
Last Week in AI
Last Week in AI
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
M
MIT News - Artificial intelligence
V
V2EX
D
Darknet – Hacking Tools, Hacker News & Cyber Security
The Cloudflare Blog
The GitHub Blog
The GitHub Blog
博客园 - 聂微东
F
Full Disclosure
C
CERT Recently Published Vulnerability Notes

DEV Community

I built a CLI that eliminates README reading forever Measuring AI Gateway Failover: 30 Days of Production Data The Folly of Global AI Platforms: Or How We Built a System That Actually Works in Cameroon Week 9 The 10-Minute Race: Scaling the "Cancel Order" Button to 100K+ Requests Per Second SQL Performance: Indexing, Query Tuning & Explain Plans (Developer Guide) Tutorial: This AI Now Tells You if a Meeting Could Be an Email Why I Got Tired of Class-Heavy UI Code and Started Building Around Attributes GitHub Is No Longer a Place for Serious Work Updates to developer experience on Setapp Node.Js Express CRUD template Lint Your Phishing Templates Like You Lint Your Code From Code to Cloud: 3 Labs for Deploying Your AI Agent I built Voice2Sub: a local AI subtitle generator for video and audio The OCR Rabbit Hole Built a 100k-Document RAG System by Hand. Hermes Read the Architecture in 47 Seconds. I tried monetizing my MCP server with x402 — production needs more than npm install Understanding Tracking Dimensions in Accounting Integrations I Ran My Local, NOT AI, AI Code Auditor on Its Own Source Code Agent Surface Map: Gemma 4 review before you install an MCP Stop Being Nice, Start Being Right": The Day My User Reconfigured My Reward Function Building a Database Performance Testing Tool With AI: The Honest Breakdown Hot To Run LLMs Locally Research blockchain with post-quantum Dilithium and custom zk-STARKs from scratch AI agents do not just need tool access. They need execution control. The CTO’s Blueprint for Governing Multi-Agent AI Systems in the Enterprise I audited our CMS and 86% of our articles were invisible. A Sanity gotcha. Upselling Explained Industry-Specific Tactics for EC Owners 2026 I Keep Hermes Agent's Self-Improvement OFF For the First 14 Days — Here's What Happens When I Don't I Built the Hermes + Claude Code Dual-Stack: Orchestrator Meets Coder — Here's the Full Architecture Stop Using .iterrows(). Here's What Actually Fast Looks Like I Built a SaaS to Stop the Awkward "Hey, Did You Get My Invoice?" Conversation I Renamed a Hot Postgres Table Without Dropping a Request How to Build a Self-Hosted AI Gateway With LiteLLM and Open WebUI What is a Webhook? A Complete Guide for Beginners Headless BI: How a Universal Semantic Layer Replaces Tool-Specific Models Beyond Translation: A Developer's Guide to App Localization (i18n & l10n) Aegis: Designing an Offline Ambient Co-Working Companion for High-Burnout Medical and STEM Grinds Local LLM Code Completion Showdown: Zed AI vs Continue vs Cursor (Honest 2026 Review) The Agentic Payment Protocol Wars Your No-Code AI Agent Has a Memory Problem The Agentic Payment Protocol Wars How to Bypass LinkedIn Commercial Use Limit in 2026 (Without Paying $150/mo) We built a statechart hosting platform where two actors in the same state can migrate to different versions — here's why that matters Playwright vs TWD: A Frontend Developer's Honest Comparison Claude Code's skillListingBudgetFraction: The Undocumented Setting Silently Killing Half Your Skills O GitHub pode mudar sua carreira mais do que você imagina Just redesigned and launched my developer portfolio 🚀 Would genuinely love some honest feedback from the dev community 👨‍💻 Data Virtualization and the Semantic Layer: Query Without Copying Launching opub: donated compute for open-source maintainers Four iteration rounds on a security scanner I run, all of them visible. Here is what the loop actually looks like. Why Good Abstractions Make Debugging Harder Found a Coordinated Inauthentic Network on GitHub: 24 Accounts, Fabricated History, and a Generator That Left Its PID in Three READMEs Cursor Just Released Composer 2.5. Here's What Actually Changed for AI Coding Agents. What Wrong Docs Cost Test Automation Teams Export Your DeepSeek Chats to Word, PDF, Google Docs, Markdown & Notion in One Click When the Docs Lie OpenShift Observability: Built-in vs. Bring-Your-Own If your AI initiative is pending for 6 months, the bottleneck is probably not technology Hermes Agent Under the Hood: The Open-Source Runtime for Autonomous AI Systems Expert Systems -The AI That Existed Before AI Was Cool AI-generated accessibility, an update — frontier models still fail, but skills change the game My HTML Learning Journey 🚀 The Day PayPal Failed and the Rust Rewrite Saved the Product Launch Google Sheets CRM: 4 Ways I've Actually Done It (with Apps Script Code) BrontoScope: AI-Powered Error Investigations The job of an AI engineer inside a 40-person company is not what most CEOs think it is Building a Clinical Speech-Therapy App With a Real SLP: 4 Lessons From PhoenixSteps 7 overlooked .Net features How Stripe Took 48 Hours and 3 API Calls to Break My Freelance Income Stream in Lagos Pretty normal Both Camps in the 'Left Behind' Argument Are Right About Each Other Flutter MCP Toolkit v3 Google Just Shipped Gemini 3.5 Flash. Here's What Developers Actually Need to Know. 🔐 Working with Private Symfony Recipes Rate limiting in web apps: what to protect before picking a library Rate limiting en aplicaciones web: qué proteger antes de elegir una librería What Are Lakehouse Catalogs? The Role of Catalogs in Apache Iceberg What It Really Takes to Become a Senior Software Engineer Microservices Were Never About Technology JS Crime Scene: The Misleading Array Project-as-code for a Directus v9 backend When the API literally burned your database after a typo COOKIES DPRK Hacking Trends 2026: AI‑Powered Supply Chain and Developer Environment Attacks Phone control for AI coding sessions is not a tiny terminal PayPal and Crypto Are Not Equals: How I Built a Gumroad Alternative for Restricted Countries Exploring Tech as a Content Writer I Raised Gemma 4's Token Cap. The Dense Model Stopped Refusing. React Server Components Don't Make Your App Fast by Default Multi-Stage Builds for a Next.js App — Reduce Image Size by 70% I Built a Chrome Extension That Teaches Vocabulary While You Browse Why I Walked Back from Next.js and RSC to a Plain SPA and a Separate Backend NeuralPocket: Private On-Device AI with Gemma 4 — Android & Web Github Speckit: Revolucionando o Desenvolvimento com SDD Cloud Cost Elasticity I Built a Payment System for Bangladesh—Heres Why Stripe Failed Us Polyglot Persistence in Microservices: Choosing the Right Database for Each Service Centralized Authentication for a Multi-Brand Laravel Ecosystem How I made a perfect recording button. Simple yet complex thing.
Build an AI-Powered Developer Portal with Backstage and .NET
Borys Genera · 2026-05-21 · via DEV Community

Build an AI-Powered Developer Portal with Backstage and .NET

Want to apply AI, not just read about it? Most tutorials stop at a "Hello World" chatbot. We are going to build something that actually solves a common engineering headache: stale documentation.

Who this is for

This guide is for platform engineers and .NET developers who need to organize a growing software landscape without forcing teams to manually write YAML files.

What you will build

You will build a dynamic developer portal using Backstage that automatically populates its service catalog. We will use a .NET CLI tool to scan source code and use local AI (Ollama) to generate summaries.

Have you ever needed to update a service, but forgot what it does? Or spent time trying to understand code you have not touched in months? We usually solve this with a README.md that nobody updates, or a wiki that rots.

An Internal Developer Portal (IDP) solves this by making the software landscape visible, but only if the data is fresh. Automation is the only way to avoid the "stale metadata" trap.

Tip:
Want to skip ahead? Check out the complete working demo on
GitHub
with all
the code ready to run!

Prerequisites

Before we start, make sure you have the following installed:

  • .NET SDK 8+
  • Node.js (includes npx and yarn)
  • Ollama with the llama3:8b model pulled
  • A GitHub account (for hosting and deployment)

Why Does an Internal Developer Portal Matter?

The term "Internal Developer Portal" (IDP) can be a little misleading, since it sounds like a tool exclusively for developers only. In reality, it functions as an internal organizational portal focused entirely on your software portfolio. Unlike a general-purpose SharePoint site where everything is dumped in one place and nothing is easy to find, an IDP is deliberately narrow in scope. It covers your software landscape and nothing else, which is exactly what makes it powerful.

An IDP becomes the single source of truth for your engineering organization. It answers critical questions across every role:

  • Engineers: Which services exist? Who owns them? What do they do? What are the APIs and how do I call them?
  • Team leads and architects: What is the team composition? Which squad owns which set of services? What architectural decisions have been made and why?
  • New joiners: How do I get up to speed on a codebase I have never seen before?
  • Platform and operations teams: What is running in production, who is responsible, and what is the lifecycle status?

Beyond just listing services, a mature IDP centralizes Architecture Decision Records (ADRs), arguably one of its most valuable features. ADRs capture why a decision was made, not just what was decided. Without a central place to surface them, they rot in forgotten wiki pages or git repositories that no one thinks to check.

The challenge is keeping all of this populated and accurate. If you rely on engineers to manually maintain metadata YAML files, the data grows stale within weeks. Automation is the only sustainable path.

Formulating the Architecture

Here's the plan to extract metadata from source code and present it visually:

  • Backstage: the UI layer where engineers browse and discover services, APIs, documentation, and team ownership
  • .NET Core: a CLI tool that scans project folders, extracts metadata, and generates Backstage-compatible YAML
  • Ollama: runs AI inference locally, so your source code never leaves your machine
  • Static hosting: deploy to Netlify, Azure Static Web Apps, or any provider of your choice

Info:
Why Ollama? Because it runs locally and you do not want to expose your code
to the AI agents over the public internet. You do not know what and how they
use it for, and it does not feel safe. If your employer finds out, you're
done.

Setting Up the Project Infrastructure

You can either follow along and build everything from scratch, or clone the demo repository to get started immediately.

To clone the demo:

git clone https://github.com/bgener/demo-backstage-catalog-generator.git
cd demo-backstage-catalog-generator

Enter fullscreen mode Exit fullscreen mode

To build from scratch, start by downloading and running the LLM model we will use in this guide:

ollama pull llama3:8b
ollama serve

Enter fullscreen mode Exit fullscreen mode

Tip:
We use llama3:8b specifically. It is significantly faster for local
inference than the full-size model and produces more consistent, concise
output for our use case. If you have a powerful GPU, feel free to use llama3
instead.

Next, scaffold the baseline .NET services. We’ll create one Web API and one MVC project:

mkdir Backstage-Dev-Portal
cd Backstage-Dev-Portal

dotnet new webapi -n ServiceA
dotnet new mvc -n ServiceB

dotnet new sln -n Backstage-Dev-Portal
dotnet sln add ServiceA/ServiceA.csproj
dotnet sln add ServiceB/ServiceB.csproj

Enter fullscreen mode Exit fullscreen mode

You can replace the default controllers with real logic later. These raw services represent the uncataloged microservices in your organization.

Building a Smart Catalog Generator in .NET

We will build a .NET CLI tool using OllamaSharp. It scans each project, sends relevant files to the local AI model, and generates a single catalog-info.yaml file containing all services, ready for Backstage to consume.

Create the tool and add the required package:

dotnet new console -n ProjectSummarizer
cd ProjectSummarizer
dotnet add package OllamaSharp

Enter fullscreen mode Exit fullscreen mode

Instead of sending every file to the AI, we take a smarter approach to avoid token limits and save compute time. We will send only *.csproj, Program.cs, and the folder structure. This is all the context the AI needs to understand the project structure and purpose.

Replace Program.cs with the implementation below. The full version is in the demo repository. Here we focus on the key parts.

First, set up the Ollama client and configure the system prompt. This is the most fragile part of the chain: the system prompt has to force the model into a YAML-safe format without it hallucinating markdown backticks:

var ollamaApiClient = new OllamaApiClient(
    new Uri("http://localhost:11434")) { SelectedModel = "llama3:8b" };

var chat = new Chat(ollamaApiClient, systemPrompt:
    "You are a technical documentation assistant. " +
    "You produce concise, YAML-safe summaries of .NET projects. " +
    "Output only plain text, no markdown, no bullet points, no quotes, no colons, no newlines.");

Enter fullscreen mode Exit fullscreen mode

Instead of sending every file to the AI, we only send *.csproj, Program.cs, and the folder structure. This is all the context the model needs.

Warning:
Prompt sanitization is critical. If your Program.cs contains complex
string literals or nested colons, the AI might pass them through to your YAML,
breaking the Backstage parser. Always sanitize the output before writing the
file.

var sb = new StringBuilder();
sb.AppendLine($"Project: {projectName}");
sb.AppendLine("Folder structure:");
AppendFolderStructure(projectDir, sb, "");
sb.AppendLine(File.ReadAllText(csprojPath));

var programPath = Directory.GetFiles(projectDir, "Program.cs", SearchOption.AllDirectories)
    .FirstOrDefault();
if (programPath != null)
    sb.AppendLine(File.ReadAllText(programPath));

Enter fullscreen mode Exit fullscreen mode

The prompt itself uses few-shot examples to guide the model toward the output format we want:

var prompt = "Summarize the project in 1-2 sentences based on the files provided. " +
             "Do not output anything else. " +
             "Examples of good output: " +
             "REST API service providing weather forecasts with temperature data\n" +
             "ASP.NET MVC application with React frontend for managing todo items\n\n"
             + sb.ToString();

await foreach (var token in chat.SendAsync(prompt, cts.Token))
    summaryBuilder.Append(token);

Enter fullscreen mode Exit fullscreen mode

Finally, each summary is sanitized and assembled into a Backstage-compatible YAML entry:

var summary = summaryBuilder.ToString().Trim()
    .Replace("\n", " ").Replace(":", " -").Replace("\"", "'");

var yamlEntry = $@"
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: {projectName.ToLowerInvariant()}
  description: ""{summary}""
spec:
  type: service
  lifecycle: production
  owner: group:default/engineering";

Enter fullscreen mode Exit fullscreen mode

Run the generator against the target directory (use . if you are already in the project root):

dotnet run --project ProjectSummarizer -- .

Enter fullscreen mode Exit fullscreen mode

You should see the AI streaming its summaries in real time:

CLI output showing AI-generated project summaries

Most of the real work here is figuring out the prompt. Even a tiny change can produce a completely different output. I encourage you to experiment with the system prompt and the user prompt to see how it affects quality. That is the real learning here.

Integrating the AI Catalog with Backstage

With the catalog-info.yaml ready, we can integrate it into a Backstage instance. Install Backstage:

npx @backstage/create-app

Enter fullscreen mode Exit fullscreen mode

Follow the prompts to name it dev-portal.

Now point Backstage to your generated catalog file. Open app-config.yaml in the dev-portal directory and add the following under the catalog section:

catalog:
  locations:
    - type: file
      target: ../Backstage-Dev-Portal/catalog-info.yaml
      rules:
        - allow: [Component]

Enter fullscreen mode Exit fullscreen mode

This tells Backstage where to find the AI-generated service metadata. The target path is relative to the Backstage root directory. Adjust it to point to wherever your generator wrote the catalog-info.yaml.

To run it locally:

cd dev-portal
yarn dev

Enter fullscreen mode Exit fullscreen mode

Open http://localhost:3000 in your browser. You should see all your services listed in the Software Catalog with AI-generated summaries visible in the description column.

Backstage service catalog showing AI-generated service descriptions

Deploying the Portal

To host this, build your portal as a static site:

yarn build:static

Enter fullscreen mode Exit fullscreen mode

Push the output to GitHub and deploy to any static hosting provider: Netlify, Azure Static Web Apps, Vercel, or even self-hosted on Kubernetes. Set the build command to yarn build:static and the publish directory to dist.

Info:
A static Backstage build is great for read-only catalogs. If you need dynamic
features like authentication, real-time plugin backends, or write
operations
, you will need to deploy the full Backstage backend as a Node.js
service instead.

Automating with CI/CD

The real value comes from running the catalog generator automatically. Here is a GitHub Actions workflow that regenerates summaries on every push to main:

name: Update Backstage Catalog
on:
  push:
    branches: [main]

jobs:
  generate-catalog:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: ‘8.0.x’

      - name: Install and start Ollama
        run: |
          curl -fsSL https://ollama.com/install.sh | sh
          ollama serve &
          sleep 5
          ollama pull llama3:8b

      - name: Generate catalog
        run: dotnet run --project ProjectSummarizer -- "$GITHUB_WORKSPACE"

      - name: Commit updated catalog
        run: |
          git config user.name "github-actions"
          git config user.email "github-actions@github.com"
          git add catalog-info.yaml
          git diff --cached --quiet || git commit -m "chore: regenerate AI catalog summaries"
          git push

Enter fullscreen mode Exit fullscreen mode

Warning:
CI Performance: Running Ollama in CI uses CPU-only inference by default. A
llama3:8b summary takes about 20-30 seconds per project on a standard GitHub
runner. For a large monorepo, your CI bill will spike. Consider using a
persistent self-hosted runner with a GPU if you scale this.

Final thoughts

The practical rule is simple: automate the metadata generation where the code lives, but keep the UI (Backstage) as a thin, static client. This prevents the "stale documentation" problem without adding a heavy runtime dependency to your production environment.

  • Use narrow context: Don't send the whole repo to the AI. Files like Program.cs and *.csproj are usually enough.
  • Sanitize strictly: AI output is non-deterministic. Always strip colons and newlines before writing to YAML.
  • Start static: A read-only static portal is 10x easier to maintain than a dynamic one.

FAQ

Can I use OpenAI instead of Ollama?
Yes, but you will be sending your source code (or at least your Program.cs) to a third party. Use a local model if security is a concern.

Does this replace README files?
No. It replaces the "Service Directory" that usually lives in a spreadsheet. It points engineers to the README they actually need.

How do I handle project renames?
The generator uses the folder or .csproj name. If you rename them, Backstage will see it as a new component unless you map the identity stable-ly.


I help teams build exactly this kind of internal tooling, from developer portals to platform engineering. See my work or get in touch.