# Revit Command And Application

> Build Autodesk Revit add-in entry points with Nice3point.Revit.Toolkit base classes, not raw IExternalCommand/IExternalApplication interfaces. USE FOR: authoring an external command or application with a simplified Execute()/OnStartup() override, optional OnShutdown() override, ready context properties, and automatic dependency resolution. DO NOT USE FOR: dispatching API work from code that runs outside the Revit API context (use revit-external-events).

- Skill: `nice3point/revit-command-and-application` (Agent Skill)
- Install (CLI): `npx skillmds@latest add nice3point/revit-command-and-application`
- Raw SKILL.md: https://api.skillmd.com/api/skills/nice3point/revit-command-and-application/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- License: MIT
- Author: nice3point (https://skillmd.com/u/nice3point)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/nice3point/revit-command-and-application

---


# Revit Command and Application

Derive add-in entry points from the `Nice3point.Revit.Toolkit` base classes.
They replace the raw interface boilerplate (the full `Execute(commandData, ref message, elements)` signature, manual assembly resolution) with a simplified override and ready-made context properties.

## When to use

- Authoring an `IExternalCommand`, `IExternalApplication`, or `IExternalDBApplication` entry point.
- Reviewing an entry point that reimplements the raw interface by hand.

## When not to use

- Building the ribbon inside `OnStartup` — that is `revit-ribbon`.
- Invoking the API from a modeless window or background thread — that is `revit-external-events`.

## Workflow

### Step 1: Derive an external command

Override `Execute()`; reach the context through the inherited `Application`, not by unpacking `commandData`.

```csharp
[Transaction(TransactionMode.Manual)]
public class DeleteWallsCommand : ExternalCommand
{
    public override void Execute()
    {
        var document = Application.ActiveUIDocument.Document;
    }
}
```

`ExternalCommand` exposes high-level `Application`, `View`, `JournalData`, and `ElementSet` properties that IExternalCommand provides.
`Result` defaults to `Succeeded`; set `Result` and `ErrorMessage` only when the command must return a canceled or failed outcome.

### Step 2: Derive an external application

```csharp
public class Application : ExternalApplication
{
    public override void OnStartup()
    {
        var panel = Application.CreatePanel("Commands", "RevitAddin");
        panel.AddPushButton<DeleteWallsCommand>("Delete walls");
    }
}
```

Use `ExternalDBApplication` for a database-only application.
Override `OnShutdown()` only when the application has session cleanup to perform; it is optional.
The ribbon helpers (`CreatePanel`, `AddPushButton<T>`) come from `Nice3point.Revit.Extensions` — see `revit-ribbon`.

### Step 3: Use the async base classes for long-running work

Derive from `AsyncExternalCommand` and override `ExecuteAsync()`, or from `AsyncExternalApplication` and override `OnStartupAsync()`/`OnShutdownAsync()`.
The sealed base pumps the message loop on Revit's main thread; `await` keeps the UI responsive while the continuation still runs in the API context — no external event needed.

```csharp
public class Application : AsyncExternalApplication
{
    public override async Task OnStartupAsync()
    {
        var settings = await LoadSettingsAsync(); // long-running work; the UI stays responsive
        CreateRibbon(settings);
    }
}
```

### Step 4: Rely on automatic dependency resolution

The base classes open an assembly-resolve scope automatically; add-in dependencies load from the add-in folder without a manual `AssemblyResolve` handler.
For dependencies loaded outside an entry point, open a scope explicitly with `ResolveHelper.BeginAssemblyResolveScope`.

### Step 5: Verify

Test the observable model behavior on the Revit thread.
Leave the default successful result unless the command must cancel or fail.

## Validation

- [ ] The entry point derives from a Toolkit base class, not a hand-written interface implementation.
- [ ] Context comes from the inherited properties, not manual `commandData` unpacking.
- [ ] An application overrides `OnShutdown()` only when it has session cleanup to perform.
- [ ] Long-running UI work uses `AsyncExternalCommand`.
- [ ] The command has the expected observable behavior in Revit.
- [ ] `Result` and `ErrorMessage` are set only for a canceled or failed command.

## Common Pitfalls

| Pitfall                                                            | Correct approach                                                                               |
|--------------------------------------------------------------------|------------------------------------------------------------------------------------------------|
| Implementing `Execute(commandData, ref message, elements)` by hand | Derive from `ExternalCommand` and override `Execute()`.                                        |
| Manual `AppDomain.AssemblyResolve` for add-in dependencies         | The base classes resolve automatically; else open a `ResolveHelper.BeginAssemblyResolveScope`. |
| Blocking the UI in a long command                                  | Use `AsyncExternalCommand` and `ExecuteAsync()`.                                               |
| `ExternalCommand` not found                                        | The `Nice3point.Revit.Toolkit` package is not referenced.                                      |

