LaunchKit.AspNetCore.Tools 1.0.0

dotnet tool install --global LaunchKit.AspNetCore.Tools --version 1.0.0
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local LaunchKit.AspNetCore.Tools --version 1.0.0
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=LaunchKit.AspNetCore.Tools&version=1.0.0
                    
nuke :add-package LaunchKit.AspNetCore.Tools --version 1.0.0
                    

LaunchKit.AspNetCore

One command turns an ASP.NET Core MVC app into a site that is ready to go live.

For ASP.NET Core MVC on .NET 8. Apache-2.0 licensed.


Every website needs the same unglamorous things before it can launch: a privacy policy, terms of use, a cookie policy, error pages that do not leak stack traces, a sitemap, and a robots file. Writing them takes an afternoon. Keeping the sitemap accurate takes forever.

LaunchKit does all of it in one command, and stays out of your way afterwards.

Features

  • Legal pages — substantial Privacy Policy, Terms of Use and Cookie Policy starter templates, not placeholders.
  • Custom error pages — polished, self-contained 404 and 500 pages that return the right HTTP status and never leak exception details.
  • Error handling wired up — LaunchKit reads your Program.cs with Roslyn and inserts only the middleware that is missing.
  • Route-aware sitemap — your MVC controllers are parsed, public GET routes are resolved, and sitemap.xml is generated from them.
  • robots.txt — created if absent, carefully merged if you already have one.
  • llms.txt — the llmstxt.org index, built from the same routes, so language models can find your pages.
  • Safe to re-run — anything you have edited is preserved. Only the generated indexes are refreshed.
  • No runtime dependency — the generated code depends on ASP.NET Core and nothing else.

Installation

Install-Package LaunchKit.AspNetCore

Or with the .NET CLI:

dotnet add package LaunchKit.AspNetCore

Quick start

In the Visual Studio Package Manager Console, with your web project selected as the Default Project:

Add-LaunchKit -BaseUrl "https://example.com"

If the command is not recognized yet, give the console a couple of seconds and try again. Visual Studio registers commands from NuGet packages in the background after the console banner appears, so the very first attempt can be a moment too early. If it still isn't there, load it directly — no restart needed:

Import-Module "$env:USERPROFILE\.nuget\packages\launchkit.aspnetcore\1.0.0\tools\LaunchKit.psd1"

Reopening the solution has the same effect. This is how NuGet exposes console commands to PackageReference projects; the older install-time hook is no longer supported.

Done. LaunchKit creates your legal pages, creates custom error pages, configures error handling, scans your public routes, and generates sitemap.xml, robots.txt and llms.txt.

LaunchKit.AspNetCore
────────────────────────────────────────────

Project
    MyWebsite.csproj

Legal
  ✓ Privacy Policy                  created
  ✓ Terms of Use                    created
  ✓ Cookie Policy                   created
  ✓ LaunchKitLegalController.cs     created
  ✓ wwwroot/css/launchkit.css       created

Errors
  ✓ 404 page                        created
  ✓ 500 page                        created
  ✓ LaunchKitErrorController.cs     created
  ↻ exception handler               UseExceptionHandler("/error/500")
  ↻ status code pages               UseStatusCodePagesWithReExecute("/error/{0}")
  ↻ Program.cs                      updated (backup: Program.cs.launchkit.bak)

SEO
    14 public routes discovered     6 controllers scanned
  ✓ wwwroot/sitemap.xml             17 URLs
  ✓ wwwroot/robots.txt              created
  ✓ wwwroot/llms.txt                created

LaunchKit setup completed successfully.

The Add-LaunchKit command

Add-LaunchKit
Parameter Purpose
-BaseUrl Public origin, e.g. https://example.com. Needed for sitemap.xml, robots.txt and llms.txt.
-CompanyName Legal entity named in the generated legal pages.
-WebsiteName Display name of the site used in the generated legal pages.
-ContactEmail Contact address printed in the legal pages.
-ProjectName Target a specific project instead of the console's Default Project.
-WhatIf Report every change without writing anything.

Nothing is mandatory. Anything LaunchKit can infer safely, it infers; anything it cannot, it says so.

Add-LaunchKit `
    -BaseUrl "https://example.com" `
    -CompanyName "Acme Inc." `
    -ContactEmail "hello@example.com"

Your answers are stored in launchkit.json next to the project file and reused on every later run:

{
  "baseUrl": "https://example.com",
  "companyName": "Acme Inc.",
  "websiteName": "Acme",
  "contactEmail": "hello@example.com",
  "effectiveDate": "2026-09-09",
  "launchKitVersion": "1.0.0"
}

No secrets are ever written to it. Commit it.

Base URL

https://example.com and https://example.com/ are normalised to the same canonical origin. A URL without a scheme is assumed to be https. Anything that is not a valid absolute http/https URL is rejected with an explanation rather than written into your sitemap.

sitemap.xml requires absolute URLs, so the first run without a -BaseUrl does everything except the three SEO files and tells you exactly how to finish:

SEO
  ! sitemap.xml                     skipped - no BaseUrl configured
  ! robots.txt                      skipped - no BaseUrl configured
  ! llms.txt                        skipped - no BaseUrl configured

What gets generated

Controllers/
    LaunchKitLegalController.cs      /privacy, /terms, /cookies
    LaunchKitErrorController.cs      /error/404, /error/500

Views/
    LaunchKitLegal/
        Privacy.cshtml
        Terms.cshtml
        Cookies.cshtml
    LaunchKitError/
        NotFound.cshtml
        ServerError.cshtml

wwwroot/
    css/launchkit.css
    sitemap.xml
    robots.txt
    llms.txt

launchkit.json

The legal pages use your existing layout and a small stylesheet whose classes are all prefixed lk-, so they cannot collide with your own CSS, Bootstrap or Tailwind. No JavaScript, no CDN, no frontend framework.

The error views are deliberately different: they set Layout = null and inline their own CSS. An error page that depends on the rest of the application can fail for the same reason the request failed.

Routes it adds

URL Serves Controller
/privacy Privacy Policy LaunchKitLegalController.Privacy
/terms Terms of Use LaunchKitLegalController.Terms
/cookies Cookie Policy LaunchKitLegalController.Cookies
/error/404 Not-found page, HTTP 404 LaunchKitErrorController.NotFoundPage
/error/500 Server-error page, HTTP 500 LaunchKitErrorController.ServerError
/error/{code} Any other 4xx/5xx LaunchKitErrorController.Status

If your project already serves one of these URLs, LaunchKit leaves it to you and does not create a competing route.

After the first run

Three things are worth doing once, by hand. LaunchKit deliberately does not touch your layout or your navigation.

1. Check what went into Program.cs

LaunchKit inserts the two pieces below. This is the full shape it aims for in a default .NET 8 MVC Program.cs — the lines it adds are marked:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/error/500");   // <- added by LaunchKit when you have no handler
    app.UseHsts();
}

app.UseStatusCodePagesWithReExecute("/error/{0}");   // <- added by LaunchKit

app.UseHttpsRedirection();
app.UseStaticFiles();          // required: serves sitemap.xml, robots.txt, llms.txt and the CSS

app.UseRouting();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

Two things to check:

  • app.UseStaticFiles() must be present. Without it /sitemap.xml, /robots.txt, /llms.txt and /css/launchkit.css will all return 404. Every MVC template includes it; minimal hand-written pipelines sometimes do not. On .NET 9+ templates the equivalent call is app.MapStaticAssets().
  • UseStatusCodePagesWithReExecute must come before UseRouting. LaunchKit places it there; if you move things around later, keep that order.

If LaunchKit could not edit the file safely it changes nothing, tells you why, and prints exactly what to paste. Either way the original is saved as Program.cs.launchkit.bak.

2. Point the exception handler at LaunchKit's 500 page

The default MVC template ships with its own handler, and LaunchKit will not overwrite your code. If you want the generated 500 page, change this one line yourself:

app.UseExceptionHandler("/Home/Error");   // before
app.UseExceptionHandler("/error/500");    // after

You can then delete Views/Shared/Error.cshtml, Models/ErrorViewModel.cs and the Error action on HomeController if you have no other use for them.

Nothing links to the legal pages until you do. Add them to the footer in Views/Shared/_Layout.cshtml:

<footer class="border-top footer text-muted">
    <div class="container">
        &copy; @DateTime.Now.Year - My Company
        &middot; <a asp-controller="LaunchKitLegal" asp-action="Privacy">Privacy</a>
        &middot; <a asp-controller="LaunchKitLegal" asp-action="Terms">Terms</a>
        &middot; <a asp-controller="LaunchKitLegal" asp-action="Cookies">Cookies</a>
    </div>
</footer>

Plain anchors work just as well if you are not using tag helpers:

<a href="/privacy">Privacy</a>
<a href="/terms">Terms</a>
<a href="/cookies">Cookies</a>

The default template's footer links to asp-action="Privacy" on HomeController. Repoint it at LaunchKitLegal as above, or delete that action and its view so there is one privacy page rather than two.

Error handling behaviour

LaunchKit parses Program.cs with Roslyn, finds your request pipeline, and adds only what is missing:

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/error/500");
}

app.UseStatusCodePagesWithReExecute("/error/{0}");
  • Existing error handling always wins. If you already call UseExceptionHandler, LaunchKit leaves it alone and tells you so — including the one in the default MVC template, which points at /Home/Error. Switching to LaunchKit's 500 page is a one-line change it prints for you.
  • Middleware is never duplicated, and running the command again changes nothing.
  • Comments, spacing and top-level statements are preserved; only new lines are inserted.
  • Program.cs is copied to Program.cs.launchkit.bak before it is touched.
  • If the pipeline cannot be located confidently, LaunchKit changes nothing and prints the snippet for you to paste.

The generated LaunchKitErrorController sets the status code explicitly, so /error/404 really answers 404 and /error/500 really answers 500. The 500 page shows the ASP.NET Core trace identifier and nothing else: no exception message, no stack trace, no paths, no configuration.

Sitemap generation

Routes are discovered by parsing your controllers, not by running your app. Attribute routes, controller-level routes, [controller]/[action] tokens, areas and conventional {controller=Home}/{action=Index} routes are all understood.

Included by default: concrete public GET pages — home, about, contact, pricing, features, your own content routes, and the generated /privacy, /terms and /cookies.

Excluded by default:

Excluded Why
POST, PUT, PATCH, DELETE Not pages.
[ApiController] and /api/* Not pages.
/admin, /manage, /internal, _* Not public.
/error, /404, /500, /Home/Error Error pages do not belong in a sitemap.
/account, /login, /register Authentication endpoints.
/swagger, /health, /metrics Tooling endpoints.
[Authorize] without [AllowAnonymous] Not reachable by a crawler.
/products/{id}, /users/{username} LaunchKit cannot invent real values for these.
Conventional actions taking parameters Same reason.

LaunchKit is deliberately conservative. A missing URL is easy to add; a sitemap full of broken ones is not.

The output is plain, valid sitemap XML — deduplicated, deterministically ordered, correctly escaped, with no invented lastmod, changefreq or priority values:

<?xml version="1.0" encoding="utf-8"?>

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://example.com/</loc>
  </url>
  <url>
    <loc>https://example.com/about</loc>
  </url>
</urlset>

Excluding a route

using LaunchKit.AspNetCore;

[HttpGet("internal-dashboard")]
[LaunchKitSitemapIgnore]
public IActionResult Dashboard() => View();

[LaunchKitSitemapIgnore] works on an action or a whole controller. Its counterpart, [LaunchKitSitemapInclude], forces a route in that LaunchKit would otherwise filter out — though it will still never emit a route with unresolved parameters.

Both attributes are read from source. They cost nothing at runtime.

llms.txt

LaunchKit also writes wwwroot/llms.txt, served at /llms.txt. It is the markdown index described at llmstxt.org: a short, machine-readable map of the site for language models and AI crawlers, built from the same routes as the sitemap.



# Acme

> One sentence describing this site. Replace this line - LaunchKit does not invent one.

## Pages

- [Home](https://example.com/)
- [About](https://example.com/about)
- [Getting Started](https://example.com/getting-started)

## Legal

- [Privacy Policy](https://example.com/privacy)
- [Terms of Use](https://example.com/terms)
- [Cookie Policy](https://example.com/cookies)

Two deliberate choices:

  • Titles come from the URL, never from guesswork: /getting-started becomes "Getting Started".
  • The summary line is left blank on purpose. LaunchKit cannot know what your site does, and a wrong description is worse than an obvious placeholder. Write one sentence and it is kept forever — later runs refresh the page list around it and never overwrite your text.

If you write your own llms.txt from scratch, delete the generated comment on the first line. LaunchKit then treats the file as yours and never touches it again.

Running Add-LaunchKit again

Added a new controller six months later? Run it again.

Add-LaunchKit
Project
    MyWebsite.csproj
    existing LaunchKit setup detected

Legal
  · Privacy Policy                  existing file preserved
  · Terms of Use                    existing file preserved
  · Cookie Policy                   existing file preserved

Errors
  · 404 page                        existing file preserved
  · 500 page                        existing file preserved
  · Program.cs                      already configured

SEO
    16 public routes discovered     8 controllers scanned
  ↻ wwwroot/sitemap.xml             19 URLs

  Sitemap changes:
    + /partners
    - /old-products

  · wwwroot/robots.txt              unchanged
  ↻ wwwroot/llms.txt                page list refreshed

LaunchKit is up to date.

LaunchKit rescans your routes and refreshes the sitemap without overwriting your customised legal and error pages.

Existing-file safety

The rule is simple: your code always wins.

File Ownership
Legal pages, error views Yours after the first run. Never overwritten.
Generated controllers Yours after the first run. Never overwritten.
launchkit.css Yours after the first run. Never overwritten.
Program.cs Yours. Minimal insertions only, backed up first, existing config kept.
sitemap.xml LaunchKit-managed. Regenerated on every run.
robots.txt LaunchKit-managed only if it created it; otherwise merged conservatively.
llms.txt LaunchKit-managed only if it created it. Your summary line is always kept.
Your layout, nav, footer Yours. Never touched — see "After the first run" above.

Route collisions are handled the same way. If your project already serves /privacy, LaunchKit generates the page but not a conflicting route:

  · Privacy Policy                  existing file preserved
  ·   route /privacy                your own route already serves this

The same applies to /terms, /cookies, /error/404 and /error/500. LaunchKit also never writes outside your project directory, and never executes any of your code — it only parses it.

Outside Visual Studio

Add-LaunchKit needs the Visual Studio Package Manager Console. On macOS, Linux, VS Code or Rider, install the cross-platform CLI, which runs the same engine:

dotnet tool install --global LaunchKit.AspNetCore.Tools
launchkit --base-url "https://example.com"

Run launchkit --help for the full option list. Add the LaunchKit.AspNetCore package too if you want the [LaunchKitSitemapIgnore] attribute.

The generated Privacy Policy, Terms of Use and Cookie Policy are starter templates, not legal advice. They do not make your site compliant with the GDPR, UK GDPR, CCPA/CPRA, PIPEDA, LGPD or any other law, and no such compliance is claimed or implied.

Every generated page carries a developer-facing comment listing what must be reviewed. Read it, adapt the text to the data you actually collect and the jurisdiction you actually operate in, and have the result reviewed by a qualified lawyer before you publish.

Supported versions

Target framework .NET 8.0
Project type ASP.NET Core MVC (SDK-style, Microsoft.NET.Sdk.Web)
Requires .NET 8 SDK or newer on PATH
Visual Studio 2022 17.8 or newer, for the Package Manager Console command

Razor Pages, Minimal APIs and dynamic sitemap providers are not supported in v1. The route analyzer is written so they can be added without reshaping anything.

Support and feedback

Found a bug, hit an edge case LaunchKit handled badly, or want a feature? Email me and I will get back to you:

engr.mrehmantahir@gmail.com

Useful things to include: your .NET version, the LaunchKit output you saw, and your Program.cs if the problem was with error-handling configuration.

License

Apache License 2.0. Copyright © 2026 Muhammad Rehman Tahir. The full licence text ships in the package.

Author

Muhammad Rehman Tahir — engr.mrehmantahir@gmail.com

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last Updated
1.0.0 109 9/10/2026

Initial release. Add-LaunchKit scaffolds legal pages, custom error pages, ASP.NET Core error handling, sitemap.xml and robots.txt, and is safe to re-run.