Skip to content
| Marketplace
Sign in
Visual Studio>Tools>AGcaRO — Generated Files as Read-Only
AGcaRO — Generated Files as Read-Only

AGcaRO — Generated Files as Read-Only

Hermes Silva

| (0) | Free
Stops you from accidentally editing source files produced by code generators. Files carrying the <auto-generated> tag — or recognised by name (*.g.cs, *.designer.cs) and by folder (obj, node_modules)
Download

AGcaRO — Auto Generated control as ReadOnly

A Visual Studio extension that opens generated source files as read-only, so nobody wastes an afternoon editing a file the next code generation will overwrite.

AGcaRO

Visual Studio 2022 | 2026 .NET Framework 4.7.2 111 tests MIT


The problem

You open Model.g.cs, fix the bug, run the build — and the generator silently puts the old code back. The fix is gone, and you find out an hour later.

Generated files look exactly like hand-written ones in the editor. The <auto-generated> header is easy to scroll past, and nothing stops you from typing.

What AGcaRO does

//------------------------------------------------------------------------------
// <auto-generated>          ← the file opens locked, with the reason in the info bar
//------------------------------------------------------------------------------
🔒 Locks the editor on generated files as soon as the document opens — before you can type.
🔎 Recognises them by content, name and folder: <auto-generated>, @generated, DO NOT EDIT, *.g.cs, *.designer.cs, **/obj/** and 60-plus patterns out of the box.
🌐 Language-agnostic: C#, VB, F#, C/C++, XAML, TypeScript, Python, SQL, Go, Java, protobuf, XML — any text format.
💬 Explains the block. An info bar states exactly why ("marker <auto-generated> found on line 2"). Try to type and the status bar answers, instead of the bare beep Visual Studio would give.
🔓 Gets out of the way when you need it: unlock for the session, allow one file permanently, or flip the master switch. Every unlock is logged.
♻️ Follows regeneration. When the generator rewrites the file without the tag, the lock lifts on its own — no close-and-reopen.
👥 Team configuration. A version-controlled .agcaro.json at the repository root applies to everyone, overriding individual preferences.
⚡ Negligible cost. It reads at most 8 KB of the header and memoises the decision. A generated file hundreds of megabytes long is decided in under 5 ms.

Installing

From the Visual Studio Marketplace

Search for AGcaRO under Extensions ▸ Manage Extensions ▸ Online.

From source

git clone https://github.com/Tootega/AGcaRO
cd AGcaRO
.\New-Vsix.ps1 -Configuration Release

The package lands in artifacts\AGcaRO-<version>-Release.vsix next to its SHA-256 hash. Close Visual Studio and double-click it.

Build prerequisite: Visual Studio with the Visual Studio extension development workload (the Microsoft.VisualStudio.Component.VSSDK component).

Working on the extension

Open AGcaRO.slnx and press F5: Visual Studio builds it, installs it into the experimental hive and opens a second instance with it loaded — leaving your working installation untouched.


How detection works

Rules are evaluated in this order, and the first one that decides ends the evaluation:

# Rule Result Cost
1 Protection disabled editable —
2 Path is not a file on disk (diff, Peek, metadata) editable —
3 On the permanent allow list editable glob
4 Matches an exclusion pattern editable glob
5 In a generated folder (obj, bin, node_modules…) protected glob, no I/O
6 Header contains AGcaRO:allow-edit editable header read
7 Header contains a generated-code marker protected same read
8 Name matches a generated-file pattern protected glob
9 None of the above editable —

Steps 3 to 5 come before the read precisely so the common case never touches the disk. Once the document is open, step 6 uses the text the editor already holds — zero I/O.

Only the header counts. By default the first 40 lines or 8 KB, whichever comes first. That is what keeps detection cheap, and what stops a file that merely mentions the tag halfway down from being locked.

What is recognised out of the box

Content markers (case-insensitive, any comment syntax)

<auto-generated, <autogenerated, <auto-generated-file, @generated, do not edit, do not edit this file, do not modify, do not modify this file, this code was generated, this file was generated, generated by the protocol buffer compiler, autogenerated by thrift, generated by ragel, machine generated code, plus the Portuguese equivalents used by several in-house generators.

File name patterns

*.g.cs, *.g.vb, *.g.fs, *.g.i.cs, *.generated.*, *.designer.cs, *.designer.vb, *.xaml.g.cs, *.razor.g.cs, *.feature.cs, *.assemblyinfo.cs, *.globalusings.g.cs, temporarygeneratedfile_*.cs, reference.cs, *.pb.go, *.pb.cc, *_pb2.py, *_pb2_grpc.py, *grpc.cs, *.tt.cs, *.min.js, *.min.css, *.dbml.cs, *.edmx.cs, *.xsd.cs, *.wsdl.cs, *.tab.c, resource.designer.cs — around 40 in total.

Generated folders and never-protected patterns

Folders: **/obj/**, **/bin/**, **/.vs/**, **/node_modules/**, **/packages/**, **/generated/**, **/autogenerated/**.

Never protected: **/*.md, **/*.txt, **/.editorconfig, **/.gitignore, **/.gitattributes — files that often say "do not edit" yet are maintained by hand.


Using it

When a file opens locked

An info bar appears at the top of the document with the exact reason and offers Unlock for this session, Always allow this file, Settings and Stop showing this.

Try to type and the status bar explains the block and reminds you of the shortcut.

Commands

Under Extensions ▸ AGcaRO, on the editor context menu and on the Solution Explorer context menu:

Command What it does
Unlock for This Session Frees the file until Visual Studio closes. Ctrl+K, Ctrl+Alt+U
Always Allow This File Records a permanent exception
Re-lock This File Undoes the unlock
Diagnose Current File Explains in the Output window why the file is (or is not) protected
Enable Protection Master switch, with a check mark
Re-evaluate Open Documents Drops the cache and re-applies everything
Settings... Opens Tools ▸ Options ▸ AGcaRO

Opting a file out from inside the file

Put AGcaRO:allow-edit in the header. Useful for a file that started life in a generator and is now maintained by hand. Strict mode turns this off.


Configuration

Per user

Tools ▸ Options ▸ AGcaRO, across two pages: General (behaviour, feedback, diagnostics) and Detection (the marker and pattern lists).

Per repository — .agcaro.json

A file at the solution or repository root, version-controlled alongside the code, overriding everyone's individual preferences. It is re-read on its own whenever it changes.

{
  "$schema": "https://github.com/Tootega/AGcaRO/docs/agcaro.schema.json",

  // On this team, generated files are not edited.
  "allowUnlock": false,
  "strictMode": true,

  "nameGlobs": {
    "add": ["*.mygenerator.cs", "*Orm.g.cs"],   // on top of the factory patterns
    "remove": ["*.min.js"]                      // ...and drop one of them
  },

  "excludeGlobs": {
    "add": ["src/Legacy/**"]                    // relative to this file's folder
  }
}

Every list accepts either an array (which replaces the factory list) or the object form { replace, remove, add } (which adjusts it). Comments and trailing commas are accepted. Malformed JSON only produces a warning in the Output window and the global configuration keeps applying — the extension never stops working because of a broken config file.

The full schema lives in docs/agcaro.schema.json, and a commented example in docs/examples/.agcaro.json.

Precedence

user allow list  ▸  .agcaro.json  ▸  global options  ▸  factory defaults

Settings reference

Setting Default What it does
enabled true Master switch
showInfoBar true Info bar at the top of protected documents
allowUnlock true Enables the unlock commands
enforcement Shell Shell or ShellAndReadOnlyRegion
strictMode false Unlocks do not survive closing the document; the in-file opt-out is ignored
applyFileSystemAttribute false Also sets the on-disk read-only attribute
respectAllowMarker true Honours AGcaRO:allow-edit
allowMarker AGcaRO:allow-edit The opt-out text
headerLineLimit 40 Header lines inspected
headerByteLimit 8192 Bytes read per file
cacheCapacity 2048 Memoised decisions
logLevel Errors Off, Errors, Info, Verbose

Design decisions worth explaining

Protection lives in the editor, not on disk. The file system read-only attribute is available as an option (applyFileSystemAttribute) but ships off: marking the file on disk makes some generators fail when they try to rewrite it. Protecting the developer must not cost you the generator.

The default mechanism is Visual Studio's own. BSF_USER_READONLY blocks typing, pasting, formatting, snippets and refactorings — and, decisively, the shell knows how to suspend it while reloading the document after the generator rewrites the file. ShellAndReadOnlyRegion adds a direct buffer lock for anyone who wants maximum enforcement, at the cost of sometimes needing to close and reopen the file after regeneration.

Failing means allowing, never locking. An I/O error, an unreachable network share, a denied permission, an unreadable configuration: in every one of those cases the file is treated as editable. A protection extension that locks the developer out because of its own error is worse than no extension at all.

The header window is bounded on purpose. Scanning whole files would find markers anywhere, but it would also lock any file that merely quotes the tag in a comment — and it would make opening a large generated file noticeably slower.


FAQ

Does it stop the generator from writing the file?

No. The lock lives in the editor's buffer, not on disk. The generator writes freely, and AGcaRO re-evaluates the file afterwards.

I unlocked a file, edited it, and the generator wiped my changes. Whose fault is that?

Yours, and AGcaRO said so before you started. Unlocking is deliberately explicit and is written to the audit log for exactly this conversation.

Why is my hand-written file locked?

Run Extensions ▸ AGcaRO ▸ Diagnose Current File: the Output window will name the rule and, for a content marker, the line number. The usual culprit is a DO NOT EDIT phrase in the header. Add the file to excludeGlobs, or put AGcaRO:allow-edit in its header.

Does it slow down opening a solution?

No. Nothing is scanned up front — evaluation happens lazily, per document, as each one opens. The package itself loads in the background and only when a solution is present.

Can I make protection mandatory for my team?

Yes. Commit an .agcaro.json with "allowUnlock": false and "strictMode": true. The unlock commands disappear and the in-file opt-out marker stops being honoured.

The file stayed locked after the generator ran. Why?

Almost certainly enforcement is set to ShellAndReadOnlyRegion, whose direct buffer lock can block the reload. Switch back to Shell (the default), or close and reopen the file.

Which languages are supported?

All of them. Detection reads the header as plain text and looks for markers regardless of comment syntax, so it works for any text-based format — including ones that did not exist when this was written.


Development

src/AGcaRO/
  Core/            detection engine - plain .NET, no Visual Studio dependency at all
  Editor/          editor integration: locking, info bar, command filter
  Services/        logging, configuration and the coordinator
  Options/         the Tools > Options pages
  Commands/        menu commands
tests/             111 tests over Core, runnable with `dotnet test`
samples/           sample files + manual verification walkthrough
build/             helper scripts: build, publishing and asset generation
publish/           Marketplace manifest and store page
docs/              requirements, publishing guide and the .agcaro.json schema
.github/workflows/ CI and release
New-Vsix.ps1       produces the .vsix packages - at the root, being the release entry point

Core/ deliberately does not reference the VSSDK: the test project compiles those sources straight against net8.0, which is what lets the whole suite run without Visual Studio.

Scripts

Script Purpose
New-Vsix.ps1 Packaging — tests, builds, validates the .vsix and publishes it to artifacts\ with a SHA-256
build\Build.ps1 Development loop: build and test
build\Publish-Vsix.ps1 Publishes to the Marketplace. Start with -Validate, then -WhatIf
build\Test-Scripts.ps1 Checks BOM, syntax and curly quotes in the .ps1 files. -Fix adds the BOM
build\Test-MefExports.ps1 Verifies the MEF composition by reading the assembly metadata
build\New-Assets.ps1 Regenerates the icons and the preview image
build\New-SampleFiles.ps1 Generates the sample files
.\New-Vsix.ps1                            # bump the build and produce Release into artifacts\
.\New-Vsix.ps1 -Configuration Both        # Debug and Release sharing one version
.\New-Vsix.ps1 -NoVersionBump             # rebuild without bumping
.\New-Vsix.ps1 -Version 1.1.0             # pinned version, repository untouched

.\build\Build.ps1                         # build and test, without packaging
.\build\Publish-Vsix.ps1 -Validate        # check everything without contacting the store

Versioning

MAJOR.MINOR.BUILD, starting at 1.0.123. New-Vsix.ps1 bumps BUILD on every packaging run and writes it to source.extension.vsixmanifest — commit that change along with the rest.

The manifest is the single source of the version: the .csproj reads it from there (target SetVersionFromManifest), so AssemblyVersion, FileVersion and the VSIX version can never diverge. Never set the version anywhere else.

Situation What to do
Ordinary build Nothing — 1.0.123 → 1.0.124 automatically
Raise MINOR or MAJOR Edit the manifest by hand (1.0.150 → 1.1.0) and commit; the next run continues from 1.1.1
Rebuild without advancing -NoVersionBump
In CI -NoVersionBump — an ephemeral runner has nowhere to commit the bump

Working on the PowerShell scripts

The scripts run on both Windows PowerShell 5.1 and PowerShell 7 — except Test-MefExports.ps1, which needs 7 (it uses System.Reflection.Metadata, absent from .NET Framework) and refuses to run on 5.1 with a clear message.

build\Test-Scripts.ps1 checks for the two traps below, and CI runs it:

UTF-8 with a BOM is not optional. Without it, Windows PowerShell 5.1 reads the file as ANSI and any accented character breaks the parser before the first line executes. The .editorconfig pins charset = utf-8-bom, but automated tooling strips BOMs easily — Test-Scripts.ps1 -Fix puts them back.

Never use curly quotes (“ ”) inside literals. PowerShell accepts them as string delimiters equivalent to ", so one in the middle of a message ends the string there and the error surfaces several lines later with a misleading message. Quote with straight single quotes.

Troubleshooting the build

Symptom Cause Fix
VSSDK1048 during the deploy step Stale incremental state in obj\ Run with -Clean
Build produces the DLL but no .vsix -t:Restore,Build in one invocation evaluates the project before the VSSDK targets exist Run Restore and Build separately (the scripts already do)
VsixPublisher.exe not found Extensibility workload missing Install Visual Studio extension development

Publishing

The full walkthrough — creating the publisher, generating the PAT, validating and publishing — is in docs/PUBLISHING.md, with a release checklist and the common pitfalls.

Before the first publish, replace the placeholder values (publisher, repository URLs) listed in the table at the top of that document.

Documents

  • docs/REQUIREMENTS.md — the expanded requirements, with traceable IDs (FR-* / NFR-*) referenced from the code comments.
  • docs/PUBLISHING.md — publishing to the Marketplace.
  • samples/README.md — manual verification walkthrough inside VS.
  • CHANGELOG.md — change history.

Compatibility

Visual Studio 2022 (17.x) and 2026 (18.x) — Community, Professional and Enterprise
Manifest InstallationTarget [17.0,) — the API-version-based compatibility model
Runtime .NET Framework 4.7.2 (in-process, like every VSIX)
Dependencies none beyond the VSSDK itself

Contributing

Issues and pull requests are welcome. Before opening a PR:

.\build\Test-Scripts.ps1     # if you touched any .ps1
.\build\Build.ps1            # build + 111 tests

New detection rules should come with a test in tests/AGcaRO.Core.Tests and, when they are worth demonstrating, a file under samples/ plus a row in its walkthrough table.

Licence

MIT — see LICENSE.txt.

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2026 Microsoft