Fabian
(M)
June 25, 2026, 10:38am
1
Hi there,
I am currently migrating our PyRevit based plugin suite from 5.3 to 6.4 and ran into what appears to be a problem with the new C# loader. It seems that the authusers field in extensions.json is completely ignored, therefore breaking the per-user extension filtering our plugin suite depends on.
Environment: pyRevit 5.3.1 → 6.4.0, Revit 2024–2027
In PyRevit 5.3 and older the authusers field allowed passing a list of usernames per extension to control who sees it — allowing a single shared folder with multiple extensions and handling visibility in the background with minimum additional effort:
{
"name": "some-extension",
"type": "extension",
"authusers": ["username_a", "username_b"],
"url": "...",
"dependencies": ["Lib"]
}
With the new C# loader this field is silently ignored and all extensions are loaded for all users regardless of the list.
I was looking at the PyRevit CLI and found that it could do the same thing, but for me the effort of getting it running and maintaining the deployment pipeline isn’t really worth it compared to the much simpler solution of using extensions.json.
At the moment I am forcing every user back to the old loader via user_config.core.new_loader = False in a startup script, but that is not a long term solution. It would be great to know whether this is a known gap, a planned deprecation, or something that was missed in the port — so we know whether to wait for a fix or look for an alternative approach.
Thanks for your help and to all who are working to get the new C# loader polished, great work!
Frank_L
(Frank Loftus)
June 26, 2026, 2:01pm
2
@Fabian , have you started an issue on Github? I know they usually suggest to do that.
1 Like
Fabian
(M)
June 29, 2026, 6:10am
3
Hi Frank,
I haven’t done that yet. I wanted to check if anyone had more context first before opening an issue. Thanks for the suggestion. I will open one if there are no other replies to this topic.
porrt23
(Porter Wilde)
June 29, 2026, 5:53pm
4
develop ← romangolev:develop
opened 11:56PM - 12 Apr 26 UTC
PR Description
## Summary
A grab-bag of fixes and improvements for the… new C# session loader
(`pyRevitAssemblyBuilder` + related runtime pieces). The common thread is
bringing the C# loader into closer parity with the legacy Python loader, and
fixing a few rough edges that only show up in real multi-extension setups.
None of these changes touch the legacy Python loader path — everything is
gated behind `new_loader = true`. Users on the old loader are unaffected.
## What changed and why
### 1. Extension authorization parity (`authusers` / `authgroups`)
The legacy Python loader honours `authusers` / `authgroups` entries in
`extension.json`: an extension is only loaded for users whose Windows username
matches one of the `authusers`, or who belong to one of the `authgroups`
(resolved via SID). The new C# loader didn't implement this at all, so
authorization-restricted extensions were visible to everyone when
`new_loader = true`.
This PR:
- Adds `AuthorizedUsers` and `AuthorizedGroups` to `ParsedExtension`.
- Parses `authusers` / `authgroups` arrays from `extension.json` in the
extension parser (matching how Python reads them).
- Implements a `user_has_access` check in `ExtensionManagerService` that
filters extensions by the current username and by group SID membership,
so the behaviour matches the legacy loader exactly.
- Pre-materialises library-extension lib paths during the same pass, which
also shaves some load time.
### 2. Keep the session Output Window alive during startup scripts
On a fresh session load, any extension with a startup script may open its own
`ScriptConsole`. When the user has `close_other_outputs` enabled, each of
those new consoles runs `ApplyCloseOthersConfig` on `Window_Loaded`, which
closes *every other* open output window — including the session loader's own
output window.
That's fatal, because:
- `ScriptConsole.Window_Closed` sets `ClosedByUser = true` regardless of who
triggered the close (the name is misleading; it's really "closed by
anyone").
- From that point on, `ScriptIO.Write` short-circuits at
`if (output.ClosedByUser) { return; }` and silently drops every write.
- Everything logged after that — including e.g. a `StackBuilder` warning
about a duplicate stack name — lands only in the log file, never in the
Output Window.
The fix introduces an `IsSessionOutput` flag on `ScriptConsole`. The session
loader marks its own window with it, and `CloseActiveOutputWindows` skips
any window that has it set, in both the exclude-this-window branch and the
close-all branch. Startup scripts' `close_others` behaviour is preserved for
regular script windows.
### 3. StackBuilder robustness + unit tests
Improvements to how the stack builder assembles items and handles edge
cases (fewer-than-2 items, existing stack items, duplicate names). New
`StackBuilderTests` covers the paths, with a shared `MockLogger` helper so
other parser tests can reuse it.
### 4. Build-system tweaks
The Roslyn `Microsoft.CodeAnalysis*.dll` set was being copied into many
output directories during build, slowing incremental builds and bloating
the bin tree. `Directory.Build.targets` now skips redundant copies, and a
new `DeployCodeAnalysisDlls` target handles the one location that still
needs them. Net result: faster `pipenv run pyrevit build products` and
smaller diffs on DLL commits.
### 5. Small related touch-ups
- `AssemblyBuilderService` and `CommandTypeGenerator` — minor adjustments
to support the above flows.
- `SessionManagerService` — wiring for the parity/filtering work.
- `AGENTS.md` — project-wide instruction for the opencode agent.
## Files of interest
- `dev/pyRevitLoader/pyRevitAssemblyBuilder/SessionManager/ExtensionManagerService.cs`
- `dev/pyRevitLoader/pyRevitExtensionParser/ParsedExtension.cs`,
`dev/pyRevitLoader/pyRevitExtensionParser/ExtensionParser.cs`
- `dev/pyRevitLabs.PyRevit.Runtime/ScriptConsole.cs`,
`dev/pyRevitLabs.PyRevit.Runtime/ScriptConsoleManager.cs`
- `pyrevitlib/pyrevit/loader/sessionmgr.py`
- `dev/pyRevitLoader/pyRevitAssemblyBuilder/UIManager/Builders/StackBuilder.cs`
- `dev/pyRevitLoader/pyRevitExtensionParserTester/StackBuilderTests.cs`,
`MockLogger.cs`
- `dev/pyRevitLoader/Directory.Build.targets`
## Notes for reviewers
- All runtime changes are behind the `new_loader` flag. A legacy-loader
reload should be byte-identical in behaviour.
- The `IsSessionOutput` flag is additive — only the session loader sets it,
so existing scripts that rely on `output.close_others()` see no change.
- The `ClosedByUser` field name is retained for back-compatability
it looks like there was a pull request to fix this with the new loader a few months ago. Not sure if the required formatting changed in doing so as I haven’t looked too much into it myself. TBH, I didn’t even know there was an authuser settings until this post
Fabian
(M)
June 30, 2026, 7:38am
5
Hi Porter,
good hint on the PR. It seams that it PR was released with pyRevit 6.5.3 so I tried that version, but the issue is still the same.
I created an issue for the topic: [Bug]: Authusers field in extensions.json ignored by new C# loader · Issue #3460 · pyrevitlabs/pyRevit · GitHub
1 Like
Jean-Marc
(Jean-Marc Couffin)
July 1, 2026, 8:58pm
6
This should be fixed with the latest wip installer
Please have a go and test it.
Fabian
(M)
July 2, 2026, 7:13am
7
Hi,
i use the wip installer from this ci run: Merge pull request #3462 from pyrevitlabs/cursor/fix-clone-already-ex… · pyrevitlabs/pyRevit@909ecb8 · GitHub (10h old) to check the fix.
Resulting in the following setup:
==> Registered Clones (full git repos)
==> Registered Clones (deployed from archive/image)
master | Branch: “master” | Version: "6.5.4.26182+2018
" | Path: “C:\Users\f.meister\AppData\Roaming\pyRevit-Master”
==> Attachments
master | Product: “2026 First Customer Ship” | Engine: IPY342 (342) | Path: “C:\Users\f.meister\AppData\Roaming\pyRevit-Master”
master | Product: “2025 First Customer Ship” | Engine: IPY342 (342) | Path: “C:\Users\f.meister\AppData\Roaming\pyRevit-Master”
master | Product: “2024.2.1” | Engine: IPY342 (342) | Path: “C:\Users\f.meister\AppData\Roaming\pyRevit-Master”
master | Product: “2023.1.2” | Engine: IPY342 (342) | Path: “C:\Users\f.meister\AppData\Roaming\pyRevit-Master”
==> Default Extension Search Path
C:\Users\f.meister\AppData\Roaming\pyRevit\Extensions
==> Extension Sources - Default
https://github.com/pyrevitlabs/pyRevit/raw/master/extensions/extensions.json
==> Extension Sources - Additional
==> Installed Revits
2026 First Customer Ship | Version: 26.0.4.409 | Build: 20250227_1515(x64) | Language: 1033 | Path: “C:\Program Files\Autodesk\Revit 2026”
2025 First Customer Ship | Version: 25.0.2.419 | Build: 20240307_1300(x64) | Language: 1033 | Path: “C:\Program Files\Autodesk\Revit 2025”
2024.2.1 | Version: 24.2.10.64 | Build: 20240408_1515(x64) | Language: 1033 | Path: “C:\Program Files\Autodesk\Revit 2024”
2023.1.2 | Version: 23.1.20.70 | Build: 20230510_1100(x64) | Language: 1033 | Path: “C:\Program Files\Autodesk\Revit 2023”
==> Running Revit Instances
PID: 18348 | 2024.2.1 | Version: 24.2.10.64 | Build: 20240408_1515(x64) | Language: 0 | Path: “C:\Program Files\Autodesk\Revit 2024”
==> User Environment
Microsoft Windows 10 [Version 10.0.26200]
Active User:
Admin Access: No
Install Scope: PerUser
Active Config: “C:\Users\f.meister\AppData\Roaming\pyRevit\pyRevit_config.ini”
%APPDATA%: “C:\Users\f.meister\AppData\Roaming”
Latest Installed .Net Framework: 10.0.2
Installed .Net Target Packs: v3.5 v4.0
No .Net-Core Target Packs are installed.
Active CPython Engine Version: 3123
pyRevit CLI v6.5.4.26182+2018.909ecb8009c9cb5be8a18ba8868a060887782a0b
Unfortunately, this fix isn’t working on my setup. The behavior is unchanged as far as I can see. I feel like there might be a mistake on my side, but I don’t know what to try.