Agent skill

Revit Toolkit Internals

by Nice3point in Nice3point/RevitToolkit

Uphold the design contract of the Nice3point.Revit.Toolkit runtime library, that wraps the raw Revit add-in API.

MITAuto-check passedDevelopment

Install Revit Toolkit Internals

skills CLI
$ npx skills add Nice3point/RevitToolkit --skill revit-toolkit-internals -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install Nice3point/RevitToolkit revit-toolkit-internals --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/Nice3point/RevitToolkit.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/revit-toolkit-internals .claude/skills/revit-toolkit-internals && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
revit-toolkit-internals
GitHub stars
176
Token cost
~2.5k tokens
SKILL.md length
893 words
Files
1
Skills in repo
3
Repo updated
First seen
Licence
MIT

At a glance

Uphold the design contract of the Nice3point.Revit.Toolkit runtime library, that wraps the raw Revit add-in API.

  • Works in 7 steps: Choose instance base class or static… → Model temporary state as a disposable… → Keep shared state thread-safe → …
  • Changing a runtime type in the External
  • SKILL.md covers When to use, When not to use, Workflow and Validation, plus 1 more section
  • Calls dotnet

What it does

Revit Toolkit Internals is an agent skill from Nice3point/RevitToolkit. Uphold the design contract of the Nice3point.Revit.Toolkit runtime library, that wraps the raw Revit add-in API. USE FOR: adding or changing a runtime type in the External, External/Events, Options, Helpers, or Internal folders, or the static RevitApiContext/RevitContext; deciding where boilerplate lives and how a scope, handler, or context is shaped. DO NOT USE FOR: authoring the bundled Roslyn analyzers, code fixers, or the source generator, which are a separate compiler tooling contract.

Its SKILL.md is about 2.5k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Development, covering Project scaffolding. It works with .NET. The repository describes itself as: Toolkit for Revit plugin development. The licence is MIT.

When your agent uses it

  • Changing a runtime type in the External
  • External/Events
  • Internal folders
  • The static RevitApiContext/RevitContext

Example prompts

  • “/revit-toolkit-internals”

Workflow steps

7 steps, taken from the step headings in SKILL.md.

  1. Choose instance base class or static context
  2. Model temporary state as a disposable Begin...Scope()
  3. Keep shared state thread-safe
  4. Marshal cross-thread Revit work through an external event
  5. Pump messages with DispatcherFrame for async
  6. Confine native and reflection interop to Internal/
  7. Attribute the surface, gate the versions, then verify

What it can do on your machine

Read from SKILL.md and the folder at commit b5abec5. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • dotnet

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Revit Toolkit Internals loads about 2.5k tokens when it runs. Until then it costs about 130 tokens; SKILL.md has 893 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~130
When it runs · the whole SKILL.md, loaded when a task matches
~2.5k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from Nice3point/RevitToolkit at commit b5abec5, republished under its MIT licence (© Nice3point). 893 words, ~2,511 tokens.

Download SKILL.mdSave it as .claude/skills/revit-toolkit-internals/SKILL.md (or your agent's skills folder).
name
revit-toolkit-internals
description
Uphold the design contract of the Nice3point.Revit.Toolkit runtime library, that wraps the raw Revit add-in API. USE FOR: adding or changing a runtime type in the External, External/Events, Options, Helpers, or Internal folders, or the static RevitApiContext/RevitContext; deciding where boilerplate lives and how a scope, handler, or context is shaped. DO NOT USE FOR: authoring the bundled Roslyn analyzers, code fixers, or the source generator, which are a separate compiler tooling contract.
license
MIT

Revit Toolkit Internals

Nice3point.Revit.Toolkit removes add-in boilerplate by wrapping the awkward parts of the Revit API behind clean instance and static types. The library adds ergonomics and lifecycle management, never new Revit behavior. This skill is the design contract a maintainer upholds when adding or changing a runtime type.

When to use

  • Adding or changing a base class under External/Commands or External/Applications, an event type under External/Events, an option handler under Options, a helper under Helpers, or an accessor under Internal.
  • Changing the static RevitApiContext or RevitContext, a Begin...Scope() operation, or a cross-thread handler.

When not to use

  • Authoring the bundled Roslyn analyzers, code fixers, or the [ExternalEvent] source generator. That is the compiler tooling contract with its own RVTTK#### ids and dual-Roslyn packaging.

Workflow

Step 1: Choose instance base class or static context

Model an add-in entry point as an instance base class the consumer inherits; model a global service as a static class. A base class implements the Revit interface, marks the Revit-facing method [EditorBrowsable(EditorBrowsableState.Never)], does the setup, and exposes a single abstract override; the consumer writes no plumbing.

csharp
[PublicAPI]
public abstract class ExternalCommand : IExternalCommand
{
    public UIApplication Application { get; private set; } = null!;
    public Result Result { get; set; } = Result.Succeeded;

    [EditorBrowsable(EditorBrowsableState.Never)]
    public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
    {
        Application = commandData.Application;
        using (ResolveHelper.BeginAssemblyResolveScope(GetType()))
        {
            Execute();
        }
        return Result;
    }

    public abstract void Execute();
}

RevitApiContext (DB-level Application) and its subclass RevitContext (UI-level) are static, and their static constructors reflect against Revit internals. Keep every consumer-visible entry point's boilerplate in the base class, never in the override.

Step 2: Model temporary state as a disposable Begin...Scope()

A temporary state change (dialog suppression, failure suppression, assembly resolution, the API context) is a factory named Begin...Scope() that acquires the resource and returns an IDisposable reversing it. Reference-count nested scopes under a Lock, and guard Dispose with Interlocked.Exchange; a double dispose is a no-op.

csharp
private static readonly Lock FailureLock = new();
private static int _failureScopeCount;

public static IDisposable BeginFailureSuppressionScope(bool resolveErrors = true)
{
    lock (FailureLock)
    {
        _suppressFailureErrors = resolveErrors;
        if (_failureScopeCount++ == 0)
        {
            Application.FailuresProcessing += ResolveFailures;
        }
    }

    return new FailureSuppressionScope();
}

private sealed class FailureSuppressionScope : IDisposable
{
    private int _disposed;

    public void Dispose()
    {
        if (Interlocked.Exchange(ref _disposed, 1) != 0) return;

        lock (FailureLock)
        {
            if (--_failureScopeCount == 0)
            {
                Application.FailuresProcessing -= ResolveFailures;
            }
        }
    }
}

Name the factory for the action it begins (BeginFailureSuppressionScope, not SuppressFailures), and always unsubscribe from the Revit event when the last scope closes.

Step 3: Keep shared state thread-safe

Every static context is reachable from any thread; all shared state is synchronized. Use the Lock type for shared fields, keep lock sections minimal, track nested scopes with a counter mutated under the lock, and guard dispose flags with Interlocked.Exchange. Read a shared value under the lock into a local before acting on it, as the failure and dialog resolvers do; do not touch the field outside the lock.

Step 4: Marshal cross-thread Revit work through an external event

The Revit API may only be modified from the API context. Wrap Autodesk.Revit.UI.ExternalEvent; a handler raised from any thread runs in the API context. Take a fast path that invokes the handler directly when already in API mode.

csharp
public override ExternalEventRequest Raise()
{
    if ((_options & ExternalEventOptions.AllowDirectInvocation) != 0 && RevitContext.IsRevitInApiMode)
    {
        Execute(RevitContext.UiApplication);
        return ExternalEventRequest.Accepted;
    }

    return base.Raise();
}

Await completion with a TaskCompletionSource (see AsyncExternalEvent.RaiseAsync), and queue cross-thread work with a thread-safe structure such as ConcurrentQueue when a handler batches multiple actions. The base ExternalEventHandler constructor creates the underlying Revit event inside RevitContext.BeginApiContextScope(); construction is valid off the API context.

Step 5: Pump messages with DispatcherFrame for async

async/await inside a synchronous Revit command works by pumping a DispatcherFrame. Complete the frame from a continuation scheduled on TaskScheduler.Default, not the UI synchronization context, or the continuation deadlocks against PushFrame.

csharp
public sealed override void Execute()
{
    var task = ExecuteAsync();
    if (task.IsCompleted)
    {
        task.GetAwaiter().GetResult();
        return;
    }

    var frame = new DispatcherFrame();
    task.ContinueWith(_ => frame.Continue = false, TaskScheduler.Default);
    Dispatcher.PushFrame(frame);
    task.GetAwaiter().GetResult();
}
Step 6: Confine native and reflection interop to Internal/

Reflection into Revit internals and native function-pointer marshaling stay non-public and never leak. On modern runtimes the accessors use [UnsafeAccessor] (gated #if NET8_0_OR_GREATER, with a reflection fallback for the older target); function-pointer interop lives inside a private nested scope type.

csharp
internal static class UnsafeAccessors
{
    [UnsafeAccessor(UnsafeAccessorKind.Constructor)]
    internal static extern Application CreateApplication(object proxy);
}

Never surface a pointer, delegate, or reflected member from Internal/; the API-context scope allocates and frees its native memory inside its own Dispose.

Show full SKILL.md (327 more words)Show less
Step 7: Attribute the surface, gate the versions, then verify

Mark every public class [PublicAPI], every member Revit invokes but consumers must not call [EditorBrowsable(EditorBrowsableState.Never)], and every read-only method [Pure]. Wrap an option callback interface with ergonomic constructors, like FamilyLoadOptions : IFamilyLoadOptions and DuplicateTypeNamesHandler : IDuplicateTypeNamesHandler; keep the Revit-invoked method non-browsable. Every type must compile under every declared Debug.R20..R27 / Release.R20..R27; gate version-specific Revit APIs with #if REVIT2024_OR_GREATER-style directives and runtime features (AssemblyLoadContext, UnsafeAccessor) with #if NET or #if NET8_0_OR_GREATER. Ship a test for the changed custom logic in tests/Nice3point.Revit.Toolkit.Tests, then build.

shell
dotnet test -c Debug.R27

Validation

  • Entry points are instance base classes with one abstract override; global contexts are static classes; boilerplate lives in the base, not the override.
  • A temporary state change is a Begin...Scope() returning IDisposable, reference-counted under a Lock, with an Interlocked.Exchange dispose guard.
  • All shared static state is synchronized; the Revit event is unsubscribed when the last scope closes.
  • Cross-thread Revit work is marshaled through the external event with the API-mode fast path; async pumps a DispatcherFrame with a TaskScheduler.Default continuation.
  • Reflection and native interop stay in Internal/ and are never surfaced.
  • Public classes carry [PublicAPI], Revit callbacks [EditorBrowsable(Never)], read-only methods [Pure]; every type compiles under every Debug.RNN/Release.RNN.
  • A test covers the changed custom logic.

Common Pitfalls

PitfallCorrect approach
Putting Revit plumbing in the consumer's overrideKeep setup in the base class; expose one abstract method.
A scope that forgets to reverse or double-reversesCount under a Lock and guard Dispose with Interlocked.Exchange.
Touching a shared field outside the lockRead it under the lock into a local, then act.
Calling the Revit API off the API contextMarshal through the external event; fast-path only when IsRevitInApiMode.
Completing the async frame on the UI contextContinue on TaskScheduler.Default; the UI context deadlocks against PushFrame.
Exposing a reflected member or native pointerKeep it internal in Internal/; expose only the wrapped type.
A version-specific API without a compilation gateGate with #if REVIT####_OR_GREATER / #if NET* so every configuration compiles.

© Nice3point, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .agents/skills/revit-toolkit-internals of Nice3point/RevitToolkit.

Open the folder on GitHubat commit b5abec5

Compare with similar skills

Revit Toolkit Internals next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Revit Toolkit Internals compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Revit Toolkit Internals this skillNice3point/RevitToolkit176—~2.5kAutomated safety check: PassMIT
Scaffoldcodewithmukesh/dotnet-claude-kit751—~1.7kAutomated safety check: PassMIT
Corvus Benchmarkscorvus-dotnet/Corvus.JsonSchema199—~1.2kAutomated safety check: PassApache-2.0
Create Migrationfullstackhero/dotnet-starter-kit6.8k—~757Automated safety check: PassMIT
Improve Skill Qualitydotnet/skills5.6k1 repos~3.6kAutomated safety check: PassMIT
Create Blazor Projectdotnet/skills5.6k1 repos~3kAutomated safety check: PassMIT

Similar skills

  • Scaffold

    codewithmukesh/dotnet-claude-kit

    Architecture-aware feature scaffolding for .NET 10 projects.

    751 GitHub stars~1.7k tokensUpdated 2 mo ago
    DevelopmentAuto-check passed
  • Corvus Benchmarks

    corvus-dotnet/Corvus.JsonSchema

    Run, interpret, and maintain BenchmarkDotNet benchmarks for JSON Schema validation and query languages.

    199 GitHub stars~1.2k tokensUpdated today
    DevelopmentAuto-check passed
  • Create Migration

    fullstackhero/dotnet-starter-kit

    Create and apply an EF Core migration for a module's DbContext the FSH way (central Migrations project, per-module folder, correct --context).

    6.8k GitHub stars~757 tokensUpdated 7 days ago
    DevelopmentAuto-check passed
  • Official

    Diagnoses and fixes skills in the dotnet/skills repository that lose to their own baseline, fail to activate, time out, or return "no credible improvement".

    5.6k GitHub starsUsed in 1 repo~3.6k tokens
    DevelopmentAuto-check passed
  • Official

    Create a new ASP.NET Core web application or web site using Blazor.

    5.6k GitHub starsUsed in 1 repo~3k tokens
    DevelopmentAuto-check passed
  • Official

    Generate or scaffold ASP.NET Core code — Razor Pages, Blazor components, MVC controllers, views, and Minimal API endpoints — without using ASP.NET Core CLI scaffolding/code-generation tools.

    5.6k GitHub starsUsed in 1 repo~3.2k tokens
    DevelopmentAuto-check passed

More from Nice3point/RevitToolkit

  • Revit Toolkit Analyzers

    Nice3point/RevitToolkit

    Author and extend the Roslyn tooling bundled in the Nice3point.Revit.Toolkit package: the incremental source generator that emits external-event boilerplate, the analyzers and code fixers that…

    176 GitHub stars~3.8k tokensUpdated today
    Auto-check passed
  • Revit Toolkit Backward Compat

    Nice3point/RevitToolkit

    Evolve the public surface of Nice3point.Revit.Toolkit without breaking downstream consumers: deprecate a renamed or replaced member with [Obsolete] with a JetBrains [CodeTemplate] auto-conversion…

    176 GitHub stars~2k tokensUpdated today
    Auto-check passed

Works with

Categories

Questions about Revit Toolkit Internals

What does Revit Toolkit Internals do?

Uphold the design contract of the Nice3point.Revit.Toolkit runtime library, that wraps the raw Revit add-in API. Revit Toolkit Internals is an agent skill from Nice3point/RevitToolkit.Toolkit runtime library, that wraps the raw Revit add-in API.

When should I use Revit Toolkit Internals?

Revit Toolkit Internals fits situations like: changing a runtime type in the External; external/Events; internal folders; the static RevitApiContext/RevitContext.

How do I install Revit Toolkit Internals in Claude Code?

Run `npx skills add Nice3point/RevitToolkit --skill revit-toolkit-internals -a claude-code`. Or copy the skill folder (.agents/skills/revit-toolkit-internals in Nice3point/RevitToolkit) into .claude/skills/revit-toolkit-internals in your project. Claude Code loads it when a task matches its description.

How do I install Revit Toolkit Internals in Codex?

Run `npx skills add Nice3point/RevitToolkit --skill revit-toolkit-internals -a codex`. Or copy the skill folder (.agents/skills/revit-toolkit-internals in Nice3point/RevitToolkit) into .agents/skills/revit-toolkit-internals in your project. Codex loads it when a task matches its description.

Can I use Revit Toolkit Internals in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add Nice3point/RevitToolkit --skill revit-toolkit-internals -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/revit-toolkit-internals, .gemini/skills/revit-toolkit-internals, .github/skills/revit-toolkit-internals and .opencode/skills/revit-toolkit-internals in your project.

What does Revit Toolkit Internals need to run?

Going by SKILL.md and its folder, Revit Toolkit Internals needs the command-line tools its instructions call (dotnet).

Does Revit Toolkit Internals access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Revit Toolkit Internals safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Revit Toolkit Internals use?

Revit Toolkit Internals is published under the MIT licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Revit Toolkit Internals use?

About 2.5k tokens (SKILL.md is roughly 10k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Revit Toolkit Internals?

Skills that share tags, products or a category with Revit Toolkit Internals: Scaffold (codewithmukesh/dotnet-claude-kit, 751 stars), Corvus Benchmarks (corvus-dotnet/Corvus.JsonSchema, 199 stars), Create Migration (fullstackhero/dotnet-starter-kit, 6.8k stars) and Improve Skill Quality (dotnet/skills, 5.6k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Revit Toolkit Internals?

Nice3point (a GitHub user) maintains it in Nice3point/RevitToolkit, which has 176 GitHub stars. The repository holds 3 skills in this directory. The repository was last updated on October 7, 2026.

Source: Nice3point/RevitToolkit on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.