Commands are normal projects
Tooling can use the normal .NET ecosystem instead of being trapped inside a purpose-built scripting language.
projects/reapershell
An experimental .NET shell built around one idea I liked from systems such as TempleOS: what if the environment you are using is also something you can keep changing while you use it?
.NET 10 · C# · command packs · live rebuild / reload · Git
The original inspiration was less "I need another shell" and more the idea of a programmable environment that can change while it is running. TempleOS takes that idea much further than ReaperShell does, but the part that stuck with me was the feeling that the environment itself should be hackable.
I wanted a shell where adding a new capability did not mean writing a throwaway script, restarting the host, or waiting for the feature to become part of some permanent built-in command set.
In ReaperShell, commands can live in external command packs as normal .NET projects. I can edit one, rebuild it, reload it, and keep using the same shell session.
I have never particularly liked scripting. For small automation it is convenient, but I wanted a richer environment with normal project structure, types, libraries, tooling, and room for a command to grow beyond a few lines without changing ecosystems.
A ReaperShell command pack is therefore made from ordinary SDK-style .NET projects rather than a custom script format. Commands implement a small host abstraction and compile into assemblies that the shell can load.
C# is the language I actually care about using, but the command-pack model also supports F# and VB.NET because once the boundary is a normal .NET project there is little reason to arbitrarily forbid them.
The live rebuild/reload loop is the part that makes ReaperShell interesting to me. A trusted command pack can be unloaded, rebuilt from its current source, and loaded again without restarting the shell.
That turns the shell into both the place where I use a tool and the place where I iterate on that tool. If a command is missing something, I can open its source, change it, rebuild the pack, reload it, and try the new behavior immediately.
The first thing I used ReaperShell for was a log viewer, before Mission Control existed. I had previously used a small PowerShell script for log searching, lost it, and rebuilt the idea as a C# command.
That became the iis-tools command pack and forced the shell
to solve problems that toy examples do not expose: loading external
commands, rebuilding quickly, proving which DLL is actually loaded,
switching branches, and surfacing enough diagnostics to understand what
the shell is doing.
That was the point where the plugin model stopped being a demo of a plugin model and started being shaped by something I actually wanted to use.
Once commands lived outside the shell, treating those command packs as normal Git repositories made the workflow much more convenient.
ReaperShell can register a local pack or clone a Git-backed one, mark it trusted, build it, load it, switch branches, pull updates, commit changes, and publish a local pack to GitHub. If I trust a command-pack repository, adding it is close to "clone this and now those commands exist in my shell."
Git operations stay explicit. Reloading a command pack does not silently fetch, pull, rebase, or switch branches. The shell also shows branch and commit information around builds so it is harder to wonder which version of the tool is actually running.
ReaperShell also has the ordinary things that make an interactive shell usable: file operations, history, aliases, environment overrides, command lookup, completion, profiles, hooks, scripts, and commands for inspecting where loaded commands came from.
Commands such as which, describe, and
source are especially useful in a system where behavior can
come from external packs. The point is not just to make commands
dynamic; it is to make that dynamism understandable.
ReaperShell command packs are trusted code. They run in-process with the same user privileges as the shell itself. There is no attempt to pretend an arbitrary command repository is safe merely because it has a manifest and a friendly command name.
The explicit trust step is therefore part of the design. The project is optimized for local developer tooling I control or deliberately choose to run, not for executing random plugins from the Internet in a secure sandbox.
Tooling can use the normal .NET ecosystem instead of being trapped inside a purpose-built scripting language.
Rebuilding code and changing source history are separate actions. Branch switches, pulls, and reloads stay explicit.
External command packs run with real user privileges, so loading them is treated as a deliberate trust decision.
A dynamic shell should make it easy to answer where a command came from, what is loaded, and which branch/commit is being rebuilt.
ReaperShell is an experimental developer-tooling project rather than something with a grand product roadmap. It grew out of a programming idea I wanted to explore, and it ended up useful enough that real command packs now shape how the shell evolves.
It may never need to become more ambitious than that. The interesting part is the loop: use the shell, find something missing, change the shell while it is running, and keep going.