# CSharpRepl: a NuGet-installable C# REPL with IntelliSense and live process attach

> CSharpRepl is a cross-platform command line C# REPL distributed as a .NET 10 global tool. It gives you IntelliSense, NuGet installation from the prompt, and the ability to attach a Roslyn scripting engine to a running .NET process.

**waf/CSharpRepl** — A command line C# REPL with syntax highlighting – explore the language, libraries and nuget packages interactively.

- Repository: https://github.com/waf/CSharpRepl
- Website: https://fuqua.io/CSharpRepl/
- Stars: 3,352 · Forks: 125
- Language: C#
- License: MPL-2.0
- Published: 2026-09-24 · Updated: 2026-09-24 · Language: en
- Canonical page: https://hysenlabs.com/projects/waf-csharprepl

## What CSharpRepl solves, and who it is for

C# has a compiler and a test runner, but the loop between the two is slow when you only want to know what a method returns or how a library behaves. CSharpRepl is the answer to that gap: a read-eval-print loop where you type an expression and see the result. The README frames the project as being for "the rapid experimentation and exploration of C#", and the feature list backs that up with syntax highlighting, IntelliSense with documentation and overload navigation, automatic formatting of typed input, and NuGet package installation from the prompt.

The audience is narrow but real. Developers who already have the .NET SDK installed, who spend time in a terminal, and who want to check a library before adding it to a project. The `#r "nuget: PackageName"` directive means you can pull a package into the session and call it without editing a .csproj, restoring, and waiting for a build. People doing exploratory work on LINQ queries, date arithmetic, or serialization formats will get the most out of it. So will anyone who needs to poke at a live .NET application, which is the second half of the project's story.

## How the REPL evaluates your input

The core is a Roslyn scripting engine running inside the csharprepl process. Your input is parsed, and the README describes a specific rule for deciding when to run: if the statement is not a "complete statement", pressing Enter inserts a newline instead of evaluating. That is why `if (x == 5)` followed by Enter moves the caret down rather than failing. The same rule applies to semicolons. Expressions do not need one, statements do, and a statement missing its semicolon gets a newline instead of an error.

Output rendering is where the project has made a deliberate engineering choice. Rather than clearing the screen and redrawing, it uses what the README calls a "diff" algorithm to render only what changed, which is the stated reason for the flicker-free behaviour. Results are formatted with Spectre.Console, and Ctrl+Enter expands a value into a detailed property view. For a DateTime, the README shows the compact form on Enter and a multi-line dump of fields like InternalTicks and _dateData on Ctrl+Enter.

Underneath the surface there is more than one engine. The README mentions IL disassembly and "lowered" C# decompilation in both Debug and Release mode using ILSpy, and Source Link navigation to source. Those are inspection features layered on top of the evaluation loop, not part of it.

## Installing CSharpRepl as a dotnet global tool

CSharpRepl ships as a .NET 10 global tool, so the prerequisite is a .NET SDK that can run it, and the install command comes from NuGet. The README gives exactly one installation path:

```bash
dotnet tool install -g csharprepl
```

On macOS Catalina (10.15) or later the README says to follow any additional directions printed to the screen, and notes that you may need to update your PATH variable to use .NET global tools. Once installation finishes, run the tool by name:

```bash
csharprepl
```

Upgrades use the same global tool mechanism:

```bash
dotnet tool update -g csharprepl
```

For a first real use, start the REPL and type an expression. The README's own example is a Console.WriteLine call and a DateTime expression, both of which evaluate on Enter. A more useful first move is pulling in a package you have been meaning to try, using the `#r` directive with the nuget prefix:

```csharp
#r "nuget: PackageName, 13.0.5"
```

That form pins a specific version; leaving the version off installs the latest. After the reference resolves, the package's namespaces and types are available for the rest of the session. To end a session, type `exit` or press Ctrl+D.

## Referencing projects, solutions and scripts

The `#r` directive is not limited to packages. The README documents assembly references by name or path, project references by `.csproj` path, and solution references, including both `.sln` and `.slnx` files. That last one matters for anyone working in a repository with several projects, because it means the REPL can resolve against the same graph the build uses rather than a hand-maintained list of DLLs.

There is a second loading mechanism for session setup. The `#load` directive runs a C# script file, and the README notes that any references, namespaces and variables the script defines remain available afterwards. In practice this turns a `.csx` file into a reusable preamble: the usings you always want, the helper methods you keep retyping, the package references for a domain you work in often.

ASP.NET has its own path. The README says to launch the tool with the `--framework` parameter and the `Microsoft.AspNetCore.App` shared framework, then reference the application DLL with `#r`:

```console
csharprepl --framework  Microsoft.AspNetCore.App
```

That is the documented route to running ASP.NET types interactively. The README points to the Configuring CSharpRepl wiki page for the details it does not cover inline.

## Attaching to a running process, and why that is the risky part

The most distinctive feature is the connector. CSharpRepl can attach to another .NET application and evaluate expressions inside it, reading and writing live state such as statics and services resolved from dependency injection. The README is explicit about the mechanism: a real Roslyn scripting engine is injected into the target, so you are running unconstrained C# in that process. The target does not need source changes, but it must opt in by being launched from a shell with two special environment variables, which the README describes before the text is cut off.

The project's own warning is unambiguous. Connecting to a connector-enabled process is "equivalent to running arbitrary code inside it, with its privileges", and the README calls it a development and diagnostics tool, adding that the connector should never be enabled on a production process. Take that at face value. An attach endpoint that evaluates arbitrary C# is a remote code execution surface by design, and the only control is the opt-in environment variables on the target.

It is also worth being precise about what this is not. The README states plainly that it is not a debugger: breakpoints, stepping and non-cooperative attach are not supported. If your problem is "why did this variable have the wrong value three frames up", this is the wrong tool. If your problem is "what does this service return right now, and can I call a method on it to find out", the connector answers it.

## Themes, terminal behaviour and the AI completion providers

Appearance is configurable in three documented ways. The default theme matches Visual Studio dark mode. Custom themes are JSON files, and the repository ships a Dracula theme at `CSharpRepl/themes/dracula.json` as a reference for the schema. The `--useTerminalPaletteTheme` command line option makes the REPL adopt your terminal's own colours, and setting the `NO_COLOR` environment variable disables colour entirely. That last option is the one to reach for in CI logs or a terminal whose ANSI handling is poor, though the syntax highlighting is a large part of the interactive experience.

AI code completion is listed as a feature with an unusually broad provider list: OpenAI, Anthropic, Gemini, Grok, DeepSeek, Mistral/Codestral, or any other OpenAI-compatible provider. The README's parenthetical is the important part: bring your own API key. There is no bundled model and no hosted service implied. If you work somewhere that forbids sending code to third-party APIs, this feature is simply off the table, and the rest of the REPL is unaffected by that.

One structural detail worth flagging: the repository root contains an `InjectedHook/` directory alongside `CSharpRepl/` and `CSharpRepl.Services/`. The README does not describe it, but its name is consistent with the process-attach mechanism, and it is a reminder that the connector is a separate component from the ordinary REPL rather than a mode of the same code path.

## How it compares to LINQPad and C# Interactive

LINQPad is the obvious comparison, and the difference is in the shape of the tool. LINQPad is a GUI application with a query-oriented workflow and its own dump mechanism for inspecting results; CSharpRepl is a terminal program with no window, and its equivalent of a dump is the Ctrl+Enter detailed view rendered through Spectre.Console. If your work happens in an editor and a shell, the terminal tool fits the surroundings. If you want a saved library of queries with a visual result grid, LINQPad's model is a better match, and the README does not claim to replace it.

C# Interactive, the scripting tool that ships with the .NET SDK, is the closer sibling. It also evaluates C# interactively, but the feature gap the README describes is wide: CSharpRepl adds IntelliSense with overload navigation, automatic formatting, NuGet installation from the prompt, project and solution references, IL disassembly and decompilation through ILSpy, and the process connector. Whether that gap justifies a separate global tool depends on how much you use the REPL. For occasional one-line checks, the SDK tool is already on disk.

The comparison that does not apply is to a Python or Lisp REPL. The loop concept is the same, but the interesting parts of CSharpRepl are specific to .NET: package resolution, project references, and attaching to a running CLR process.

## Licence, maintenance and upgrade cost

CSharpRepl is licensed under MPL-2.0, a file-level copyleft licence. The practical implication for most users is limited, because you install it as a global tool rather than linking it into your own assembly. If you modify CSharpRepl's own source files and distribute them, the MPL's source-availability terms attach to those files. This is not legal advice; check with your own counsel if you plan to ship a modified build.

The repository is not archived, and the last push was on 2026-09-21, three days before this writing. Releases are frequent: v0.9.0 on 2026-06-21, v0.9.1 on 2026-06-27, v0.9.2 on 2026-06-28. The version numbers are still in the 0.9 range, which is worth noting for anyone who needs API stability guarantees, though the surface most users touch is the prompt and the `#r` and `#load` directives rather than a library API.

Upgrade cost is one command, `dotnet tool update -g csharprepl`, because the tool is versioned through NuGet. The real cost is the .NET 10 requirement: the README describes CSharpRepl as a .NET 10 global tool, so an environment pinned to an older SDK cannot run it without change. Check that before you standardise on it across a team.

## Conclusion

Adopt CSharpRepl if you want a REPL that can install NuGet packages, reference local projects and solutions, and attach to a running .NET application for diagnostics. Do not adopt it as a debugger: the README states that breakpoints, stepping and non-cooperative attach are not supported, and the connector warning says never to enable it on a production process. Before relying on it, verify that your SDK satisfies the .NET 10 requirement implied by the global tool packaging, and check that your terminal renders its ANSI output and diff-based renderer acceptably.

## FAQ

### How do I install CSharpRepl?

It is a .NET 10 global tool distributed through NuGet. The README gives the install command as dotnet tool install -g csharprepl, after which you run csharprepl to begin.

### How do I add a NuGet package inside CSharpRepl?

Use the #r directive with the nuget prefix, for example #r "nuget: PackageName" for the latest version or #r "nuget: PackageName, 13.0.5" to pin a specific version. Once resolved, the package's types are available for the rest of the session.

### Can CSharpRepl attach to a running .NET application?

Yes. It injects a Roslyn scripting engine into the target, which must opt in through two special environment variables. The README warns that this is equivalent to running arbitrary code in that process and says never to enable the connector on a production process.

### Is CSharpRepl a debugger?

No. The README states that breakpoints, stepping and non-cooperative attach are not supported. It is a diagnostics tool for evaluating expressions against live application state, not a replacement for the debugger in your IDE.

## Sources

- [License: MPL-2.0](https://github.com/waf/CSharpRepl/blob/main/LICENSE)
- [Project website](https://fuqua.io/CSharpRepl/)
- [README](https://github.com/waf/CSharpRepl/blob/main/README.md)
- [Releases](https://github.com/waf/CSharpRepl/releases)
- [waf/CSharpRepl on GitHub](https://github.com/waf/CSharpRepl)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/waf-csharprepl
