Command-Line Interface
The Demeanor CLI is a cross-platform .NET global tool.
demeanor [options] <assembly>
demeanor <command> [options]
| Command | Description |
|---|
| (default) | Obfuscate an assembly |
deobfuscate | Decode an obfuscated stack trace against an obfuscation report — see Decoding Stack Traces |
inspector | Separate tool — see Metadata Inspector |
license | Decode and display license key information |
Obfuscate Command
Input / Output
| Option | Description | Default |
|---|
<assembly> | Path to the .NET assembly to obfuscate | (required) |
--out <dir> | Output directory | ./Demeanor/ |
--dry-run | Run the full pipeline (including the report) but write the obfuscated assembly to a discardable temp directory instead of --out. Preview the rename map and statistics without touching the real output. Mirrors the MCP tool's dry_run: true parameter. | false |
Scope
| Option | Description | Default | Tier |
|---|
--include-publics | Also obfuscate public/protected symbols. Use for executables not referenced by other assemblies. | off | Enterprise |
--include-deps | Also obfuscate co-located private dependency assemblies. | off | Enterprise |
Naming
| Option | Description | Default | Tier |
|---|
--names <mode> | Alpha (a, b, c) or Unicode | Alpha | Unicode: Enterprise |
--prefix <ns> | Namespace prefix for obfuscated type names | (none) | Community |
--rename <off|on|aggressive> | How hard renaming is applied, weakest first. At aggressive, renamed members additionally share one name through privatescope and leave their type’s namespace, property and event metadata is stripped, compiler-emitted hints are removed, and default parameter values are stripped. | aggressive | Community |
--virtual-rename <off|on> | Renaming of overrides of external methods — ToString, Equals, GetHashCode, interface implementations — through injected MethodImpl rows. The runtime dispatches correctly to the renamed methods; the decompiled output cannot be recompiled. | on | Enterprise |
--enum-deletion <off|on> | Deletion of enum member fields, so decompilers see an enum with no symbolic names or values. Reaches only enums that were renamed, and only those whose names the program is not observed to read. Sits inside --rename-enums: turning that off turns this off too. | on | Enterprise |
Protection Features
All protection features are enabled by default at Enterprise tier. At Community tier, only renaming is active.
| Option | Description | Default |
|---|
--string-encryption <off|on> | Encryption of literal strings, with a decryptor injected into the assembly. | on |
--constant-encryption <off|on> | Encryption of integer constants, replaced by inline arithmetic. | on |
--resource-encryption <off|on> | Encryption of embedded resources. Applies to a raw resource this assembly reads by name; one whose only reader is another assembly is left in plaintext and named in a warning, because only the assembly that owns a resource holds the key. .resources files are never encrypted. | on |
--call-hiding <off|on> | Relay methods that hide intra-assembly call targets, so a decompiler cannot resolve which method calls which. | on |
--proxy-threshold <N> | Minimum method body size for call hiding, in bytes. | 16 |
--cfg <none|reorder|predicates|flatten> | Control-flow obfuscation strength, weakest first. | flatten |
--hinder-reflection <off|on> | Metadata constructs that make reflection-based tools less reliable, and suppression of ildasm disassembly. | on |
--anti-tamper <off|on> | A module initializer that hashes the assembly file and terminates the application if it has been modified since the build. It verifies a file on disk, so under NativeAOT or single-file publishing there is nothing to verify and the check passes without doing anything. | on |
--anti-debug <off|on> | Debugger detection scattered across method entry points; the application exits when a managed or native debugger attaches at runtime. NativeAOT-compatible. | on |
--baml <off|on> | Patching of compiled XAML so it tracks renamed types and properties. Turning it off freezes everything the BAML references from renaming instead, so the unpatched XAML still resolves. | on |
Exclusions
| Option | Description |
|---|
--exclude <name> | Exclude a type or member by fully-qualified name. Repeatable. |
--xr <pattern> | Exclude by regex pattern. Repeatable. |
--xa <assembly> | Exclude an assembly (with --include-deps). Repeatable. |
--add-assembly <name> | Include a dynamically referenced assembly. Repeatable. |
Renaming Categories
Each of these sits inside --rename: --rename off turns all of them off, whatever they are set to individually. A member-level [Obfuscation(Feature="rename", Exclude=false)] or [Obfuscation(Feature="rename-propagate", Exclude=false)] opts the marked symbol back in.
| Option | Description | Default |
|---|
--rename-types <off|on> | Type names. Enumerations sit inside this: turning it off turns off enum renaming, and with it enum member deletion. | on |
--rename-enums <off|on> | Enumeration type names. Enum member deletion reaches only enums that were renamed, so turning this off turns that off too. | on |
--rename-methods <off|on> | Method names. | on |
--rename-fields <off|on> | Field names. | on |
--rename-properties <off|on> | Property names. Data-bound and serialized properties are protected automatically whatever this is set to. | on |
--rename-events <off|on> | Event names. | on |
--rename-parameters <off|on> | Parameter names. | on |
--rename-resource-names <off|on> | Managed resource names. A *.resources entry named after a type follows that type when it is renamed, which is what keeps a ResourceManager built from typeof(T) resolving. Turn it off when a lookup names the resource by a literal string instead. | on |
--no-serializable | Exclude serializable types and their serializable fields from renaming. | (off) |
Reporting & Incremental (Enterprise)
| Option | Description |
|---|
--report [<path>] | Generate a JSON report mapping original to obfuscated names. Optionally pass a filename; without one, the report is written next to the obfuscated assembly. |
--prior-report <path> | Prior report for incremental obfuscation |
--satellite-assemblies | Update resource names in satellite assemblies |
--sa-cultures <culture> | Restrict satellite processing to specific cultures |
Project Rules & Decisions
| Option | Description |
|---|
--project <dir> | Project root holding .demeanor/ — your project rules and resolved decisions. Defaults to the nearest ancestor of the input assembly containing a .demeanor directory. The MSBuild integration always passes this explicitly. |
--fail-on-pending-decisions | Exit non-zero if a needs-decision rule matched a symbol nobody has resolved. Those symbols are left unrenamed and listed either way; this makes it a build failure. Off by default. |
Strong Name Re-signing
| Option | Description |
|---|
--keyfile <path> | Strong name key file (.snk) |
--keycontainer <name> | Strong name key container |
Output Control
| Option | Description | Default |
|---|
--license <key> | License key (also reads DEMEANOR_LICENSE env var) | |
--verbose | Verbose obfuscation statistics | off |
--quiet | Suppress all non-error output | off |
--debug | Preserve debug data (PDB) | off |
--no-logo | Suppress the startup banner | off |
--no-bootstrap | Skip the first-run bootstrap. On its first invocation demeanor installs the companion inspector tool if it is not on PATH, writes the /obfuscate skill into ~/.claude/skills/, and registers itself as an MCP server in ~/.claude.json. The MSBuild integration passes this on every build, so compiling a project never changes anything outside it. DEMEANOR_NO_BOOTSTRAP=1 does the same. | off |
--version | Print the version and exit | |
--help, -h, -? | Print the full option list and exit. Every option is listed with the levels it accepts and its default, so this page and the tool cannot disagree about what exists. A subcommand takes it too — demeanor audit --help. | |
Metadata Inspector
The metadata inspector is a standalone CLI tool that installs alongside Demeanor. The Community edition (REPL, table dumps, IL disassembly, type drill-down, find, filter, dependencies) requires no license key. Enterprise capabilities (--query, --diff, --mcp, --json) unlock with a Demeanor Enterprise license key in DEMEANOR_LICENSE. See the full Inspector documentation.
inspector <assembly> [options]
audit Command
Pre-obfuscation risk analysis, and the right place to start on any codebase. It reads the compiled assembly, matches it against the built-in rules plus your project rules, and prints what obfuscates cleanly, what needs a decision from you, and what is worth knowing about — before a single byte changes.
demeanor audit MyApp.dll
demeanor audit MyApp.dll --json
| Option | Description |
|---|
--json | Emit the findings as JSON instead of a terminal table |
--include-deps | Also audit co-located private dependency assemblies |
Other Commands
| Command | What it does |
|---|
demeanor report <file> | Read a generated JSON report in human-readable form. --section and --filter narrow the output. See Reports. |
demeanor deobfuscate <file> | Map an obfuscated stack trace back to original names, using --report. See Deobfuscating stack traces. |
demeanor check <assembly> | Report whether an assembly has already been obfuscated, and with which protections. |
demeanor validate-exclusions <assembly> | Show exactly which symbols your exclusion rules match, without obfuscating anything. See Exclusions. |
demeanor init <assembly> | Interactive setup wizard — wires MSBuild integration into the nearest project. |
demeanor license <key> | Decode and display license key information. Reads DEMEANOR_LICENSE when no argument is given. |
demeanor --mcp | Start the MCP server on stdio, so an MCP-capable assistant can drive the audit, obfuscation, reports and decisions. See Decisions & CI. |