Getting started
As a global tool:
dotnet tool install -g Nullean.Curb
Ships as a native-AOT binary for linux-x64, linux-arm64, win-x64, win-arm64 and osx-arm64,
with a portable fallback for everything else. About 10 ms to start. Installing requires the .NET 10 SDK.
To have your build do the formatting instead — which is usually what you want — see the build integration.
curb format ./src
curb check ./src
- rewrite files in place
- exit non-zero if anything would change
Out of the box Curb uses Roslyn's defaults, which are the same defaults Visual Studio and Rider
use. On a repository that is already IDE0055-clean, curb format should change nothing.
Reflow is opt-in. Add max_line_length = 120 to your .editorconfig and Curb wraps long
lines; omit it and line lengths are never changed. The first run on an existing repository is a large
commit. See Reflow for what the key does, what each mode costs, and
which ReSharper wrapping keys need a width.
There is no second config file to learn. Curb reads your .editorconfig:
[*.cs]
indent_style = tab
max_line_length = 120
csharp_new_line_before_open_brace = all
csharp_space_after_cast = false
csharp_preserve_single_line_blocks = true
csharp_prefer_braces = true
csharp_style_namespace_declarations = file_scoped
- omit, or set
off, for no reflow and preserved line breaks
All 39 IDE0055 formatting options are supported, plus the 8 core EditorConfig keys, plus a set of syntax-level code style and wrapping options — around 90 keys in total.
Unrecognised or not-yet-implemented keys are reported, not silently ignored, with a "did you mean" suggestion for likely typos. Semantic code style keys are passed over deliberately, because they belong to a tool that loads a compilation.
When output surprises you, this is the first thing to run:
curb print-config Program.cs
It prints every resolved option for that specific file, the value in force, and any diagnostics — so you
can see what your .editorconfig cascade actually produced rather than what you expected. Options are
resolved per file, not per directory, because a section can discriminate on filename.
| Command | What it does |
|---|---|
curb format <path> |
Format files in place. |
curb check <path> |
Exit non-zero if anything would change. Writes nothing. |
curb print-config <file> |
Show every resolved option for a file, and any diagnostics. |
curb doc-tree <file> |
Dump the internal document IR. A debugging aid. |
curb --version |
| Flag | Applies to | What it does |
|---|---|---|
-f, --files <path> |
format, check |
Work on only these files, instead of walking a directory. Repeatable. |
--msbuild-list-file <path> |
format, check |
Work on the paths listed in this file, one per line, instead of walking a directory. What the build integration passes, since a compile set can be too long for a command line. |
-c, --cache <path> |
format, check |
Skip files a previous run watched format to themselves. The caller names the path — there is no ambient cache. The build integration uses obj/curb.cache; a pre-commit hook uses .git/curb.cache. Ignored with --coverage. |
--coverage |
check |
Report which syntax kinds are still emitted verbatim, and how often. |
--no-verify |
format, check |
Skip re-parsing the output to prove the token stream is unchanged. Not recommended — see Safety. |
obj/ and bin/ are skipped automatically.
| Code | Meaning |
|---|---|
0 |
Success. |
1 |
check found files that would change. |
2 |
Unknown command. |
3 |
A file failed verification, or a named path did not exist. |
Only 1 means "your code needs formatting". Anything else means Curb did not do its job, which
is why the build integration treats them differently.
- Why Curb — why it's fast, why it doesn't fight
dotnet format, and why running inside the build matters. - The two passes — what Curb will and will not touch.
- Integrations — the argument for putting this in your build rather than in your agent's instructions.