RevitHarness.Cli
1.0.5
dotnet tool install --global RevitHarness.Cli --version 1.0.5
dotnet new tool-manifest
dotnet tool install --local RevitHarness.Cli --version 1.0.5
#tool dotnet:?package=RevitHarness.Cli&version=1.0.5
nuke :add-package RevitHarness.Cli --version 1.0.5
RevitHarness
A harness add-in for Revit 2024 that enables CLI and agent-driven test execution, command execution, and element inspection against a running Revit instance. Supports DLL hot-swapping without restarting Revit.
Features
- Named Pipe IPC — Fast JSON-based communication between CLI and Revit
- Shadow Copy + Byte Load — DLLs are shadow-copied and loaded from byte arrays, bypassing file locks and the .NET assembly cache for seamless iterative development
- Element Lookup — RevitLookup-style element inspection from the CLI
- Addin Manager UI — A Revit ribbon button that opens a GUI to browse DLLs, scan for commands, and execute them
- HarnessCommandBase — Write a single class that works both from the CLI (
IHarnessCommand) and as a Revit ribbon button (IExternalCommand)
Installation
CLI Tool
dotnet tool install -g RevitHarness.Cli
Deploying the Add-in
# Install
revit-harness install --revit-version 2024
# Reinstall (overwrite with --force)
revit-harness install --revit-version 2024 --force
# Check status
revit-harness status
# Uninstall
revit-harness uninstall --revit-version 2024
Close Revit before installing or uninstalling. Restart Revit after installation to load the add-in.
Installation Path
%APPDATA%\Autodesk\Revit\Addins\2024\
├── RevitHarness.addin # Manifest
└── RevitHarness\
├── RevitHarness.Addin.dll
├── RevitHarness.Contracts.dll
├── RevitHarness.Lookup.dll
├── LookupEngine.dll
├── Newtonsoft.Json.dll
└── ...
CLI Commands
ping — Health Check
revit-harness ping
Returns Revit version, process ID, and active document name.
run-tests — Execute Tests
revit-harness run-tests --dll "path/to/tests.dll" --type "Company.Tests.EntryPoint" [--filter "Smoke"] [--timeout 300000]
Executes an ITestEntryPoint implementation from the specified DLL. The exit code is determined by the passed field in the result JSON.
run-command — Execute a Command
revit-harness run-command --dll "path/to/command.dll" --type "Company.MyCommand" [--args '{"key":"value"}'] [--timeout 300000]
Executes a type implementing IHarnessCommand or IExternalCommand.
post-command — Post a Registered Revit Command
revit-harness post-command --id "CustomCtrl_%CustomCtrl_%Add-Ins%Addin%Command"
Triggers a registered Revit ribbon command by its command ID.
lookup — Element Inspection
revit-harness lookup --id 12345 [--depth 1] [--max-members 200] [--include-fields] [--include-private] [--include-static] [--filter "Name"]
RevitLookup-style element inspection from the CLI. Outputs property and method return values as JSON.
shutdown — Stop the IPC Server
revit-harness shutdown
Stops the IPC server. Revit continues running.
Other
revit-harness version # Show version
revit-harness help # Show help
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Failure (ok=false or passed=false) |
| 2 | Connection / infrastructure error |
Addin Manager UI
After launching Revit, access it from the RevitHarness ribbon tab → Addin Manager button.
- Browse to select a DLL
- Scan to list types implementing
IHarnessCommand/IExternalCommand - Select a type and click Execute
- Results are displayed in the text area at the bottom
Implementing Tests and Commands
Contracts Package
dotnet add package RevitHarness.Contracts
ITestEntryPoint — For Tests
using RevitHarness.Contracts;
public class MyTestEntryPoint : ITestEntryPoint
{
public string Run(UIApplication uiapp, IDictionary<string, object> args)
{
var doc = uiapp.ActiveUIDocument.Document;
// Test logic
return JsonConvert.SerializeObject(new { passed = true, summary = "All tests passed" });
}
}
IHarnessCommand — For Commands (CLI Only)
using RevitHarness.Contracts;
public class MyCommand : IHarnessCommand
{
public string Execute(UIApplication uiapp, IDictionary<string, object> args)
{
// Command logic
return JsonConvert.SerializeObject(new { result = "done" });
}
}
HarnessCommandBase — CLI + Ribbon Dual Use
Use this when you want a single class that can be executed both from the CLI (revit-harness run-command) and as a Revit ribbon button (IExternalCommand).
using RevitHarness.Contracts;
[Transaction(TransactionMode.Manual)]
public class MyDualCommand : HarnessCommandBase
{
public override string Execute(UIApplication uiapp, IDictionary<string, object> args)
{
var doc = uiapp.ActiveUIDocument.Document;
// Works from both CLI and ribbon
return JsonConvert.SerializeObject(new { result = "done" });
}
}
IPC Protocol
JSON messages over Named Pipe \\.\pipe\RevitHarness2024 with length-prefix framing (int32 LE).
| Operation | Description |
|---|---|
ping |
Health check |
runTests |
Execute ITestEntryPoint |
runCommand |
Execute IHarnessCommand / IExternalCommand |
postCommand |
Post a registered Revit command |
lookupElement |
Element inspection |
shutdown |
Stop the IPC server |
Development
Build
# Entire solution
dotnet build revit-cli-harness.sln -c Debug
# Generate NuGet packages
dotnet pack src/RevitHarness.Contracts -c Release
dotnet pack src/RevitHarness.Cli -c Release
Project Structure
revit-cli-harness/
├── src/
│ ├── RevitHarness.Contracts/ # Shared interfaces (NuGet: RevitHarness.Contracts)
│ │ ├── ITestEntryPoint.cs
│ │ ├── IHarnessCommand.cs
│ │ └── HarnessCommandBase.cs
│ ├── RevitHarness.Addin/ # Revit add-in
│ │ ├── App.cs # IExternalApplication + ribbon setup
│ │ ├── Commands/
│ │ │ ├── CommandExecutor.cs # Shadow copy + reflection execution engine
│ │ │ ├── AssemblyScanner.cs # Discovers command types in a DLL
│ │ │ └── OpenAddinManagerCommand.cs # IExternalCommand for the ribbon button
│ │ ├── Ipc/
│ │ │ ├── IpcMessages.cs
│ │ │ ├── IpcServer.cs
│ │ │ ├── HarnessEventHandler.cs
│ │ │ └── ShadowCopier.cs
│ │ └── UI/
│ │ ├── AddinManagerWindow.xaml
│ │ └── AddinManagerWindow.xaml.cs
│ ├── RevitHarness.Lookup/ # Element inspection
│ └── RevitHarness.Cli/ # CLI tool (NuGet: RevitHarness.Cli)
├── lib/LookupEngine/ # LookupEngine library
├── Directory.Build.props # Common build settings & version
└── Directory.Packages.props # Centralized package versions
Logs
%LOCALAPPDATA%\RevitHarness\logs\harness_{date}.log
Shadow Copy Directory
%LOCALAPPDATA%\RevitHarness\shadow\{timestamp}\
Old directories are automatically cleaned up (max 10 generations, deleted after 1 day).
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.