Skip to content

Repository files navigation

MTC — Modular Template CLI

Scaffolding for .NET that understands the project you're already in.

dotnet new creates projects from scratch. MTC does that too, but its real job starts afterwards: run mtc add feature Product anywhere inside your solution and MTC detects whether you're in Clean Architecture, MVC or Vertical Slice, then writes each generated file into the layer where it belongs.

cd MyShop                       # a Clean Architecture solution
mtc add feature Product --fields "Name:string Price:decimal"

# → MyShop.Domain/Entities/Product.cs
# → MyShop.Application/Features/Products/Commands/CreateProduct/...
# → MyShop.API/Controllers/ProductsController.cs

No config file, no flags telling it what your architecture is. It looks at your solution and figures it out.


Install

Pick whichever fits your setup.

Method Command
.NET tool (any OS) dotnet tool install -g MTC
Arch Linux (AUR) yay -S mtc-bin
Debian / Ubuntu download the .deb from Releases, then sudo dpkg -i mtc_<version>_amd64.deb
Manual binary download the .tar.gz for your OS from Releases

Manual install details

  • Linux / macOS — extract the archive, move the mtc binary somewhere on your PATH (/usr/local/bin works), and keep the templates/ folder next to it.
  • Windows — extract the archive (Windows 10/11 handles .tar.gz natively) and add the extracted folder to your PATH.

Requires the .NET 10 SDK if you install as a .NET tool. The standalone binaries are self-contained and need nothing.


Quick start

Create a project, then grow it.

# 1. Make a folder and scaffold the solution into it
mkdir MyShop && cd MyShop
mtc new CleanArch MyShop

# 2. Add a feature — MTC places the files for you
mtc add feature Product --fields "Name:string Price:decimal Stock:int"

That's the whole loop. Step 2 is the one you'll run over and over.

mtc new writes into the current directory (or --output), it does not create a containing folder for you. Make the folder first, as above.


Commands

mtc new <template> [name]

Creates a new project from a template.

mtc new ConsoleApp    MyApp
mtc new MvcMonolith   MyWebApp
mtc new CleanArch     MyShop
mtc new VerticalSlice MyApi
Option Description
[name] Project name. Defaults to the output directory name.
-o, --output Where to create it. Defaults to the current directory.
-n, --name Same as the positional [name]. Takes precedence if both are given.
--force Overwrite files that already exist.

mtc add feature <name> [--fields "..."]

Generates a full feature — entity, commands/queries, and controller — placed according to the detected architecture.

mtc add feature Product --fields "Name:string Price:decimal Stock:int"
Architecture Where the files land
Clean Architecture split across *.Domain, *.Application and *.API
Vertical Slice a new folder under Features/
MVC Monolith Controllers/, Models/ and Views/

mtc add value-object <name> [--fields "..."]

mtc add value-object Money --fields "Amount:decimal Currency:string"

Goes to *.Domain/ValueObjects in Clean Architecture, Models/ValueObjects in MVC, and ./ValueObjects otherwise.

mtc add dto <name> [--fields "..."]

mtc add dto UserDto --fields "Username:string Email:string Age:int"

Goes to *.Application/DTOs in Clean Architecture, Models/DTOs in MVC, and ./DTOs otherwise.

mtc list

Lists every available template with its description, author and version.

mtc config <set|get|list>

Persists preferences in ~/.mtc/config.json.

mtc config set Author "Your Name"
mtc config get Author
mtc config list

mtc debug-context

Shows what MTC detected — solution path and architecture. Run this first whenever a generate command says it can't figure out your project.

mtc debug-context

MTC never overwrites your work

Every generate command checks its targets first. If a file it would write already exists, MTC writes nothing at all and tells you what got in the way:

$ mtc add feature Product --fields "Name:string Price:decimal"
Error: 4 file(s) already exist and would be overwritten:
  MyShop.Domain/Entities/Product.cs
  MyShop.Application/Features/Products/Queries/GetProducts/GetProductsQuery.cs
  MyShop.Application/Features/Products/Commands/CreateProduct/CreateProductCommand.cs
  MyShop.API/Controllers/ProductsController.cs
Nothing was written. Re-run with --force to replace them.

It exits with code 1, so scripts and CI notice. Pass --force when you do want the files regenerated. Generation is all-or-nothing — a conflict never leaves you with a half-written feature.

Field types

--fields takes a space-separated list of Name:type pairs:

--fields "Name:string Price:decimal IsActive:bool CreatedAt:datetime Id:guid"
Alias Generates
string string
int, long, short, byte int, long, short, byte
float, double, decimal float, double, decimal
bool bool
char char
datetime DateTime
dateonly DateOnly
timeonly TimeOnly
guid Guid

Anything else is passed through unchanged, so Status:OrderStatus works if that type exists in your project.

Reference-typed properties are generated with the required modifier, so the code MTC writes compiles clean under <Nullable>enable</Nullable>.


How detection works

MTC walks up from your current directory until it finds a .sln, then inspects the projects around it:

  • projects ending in .Domain, .Application, .Infrastructure and .APIClean Architecture
  • a Features/ folder → Vertical Slice
  • a project holding Controllers/, Views/ and Models/MVC Monolith

If none match, MTC stops and tells you rather than guessing. mtc debug-context shows exactly what it saw.


Development

dotnet build
dotnet test

Integration tests drive the compiled binary, so build before testing.

Maintainer scripts: ./publish.sh (cross-platform binaries), ./publish_aur.sh, ./publish_deb.sh.


License

MIT — see LICENSE.

About

No description or website provided.

Topics

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages