Skip to content
Agentmart
Submit a tool

seams-dotnet

Use when measuring or enforcing module boundaries in a .NET or C# solution: the project reference graph between .csproj files, cycles between assemblies or…

Skill by jpenley

IndexedMIT
Write a review

Chalk Labs

Need help deploying seams-dotnet?

Chalk Labs sets up agents like this inside real teams: connected to your tools, tested on your data, with a human in the loop where it matters.

Book a call

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/jpenley-seams-dotnet

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Use when measuring or enforcing module boundaries in a .NET or C# solution: the project reference graph between .csproj files, cycles between assemblies or namespaces, deep reaches into another assembly's internals, fan-in and fan-out, InternalsVisibleTo, or architecture tests with ArchUnitNET or NetArchTest.

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/seams-dotnet

What's inside

Skill name
seams-dotnet
Description
Use when measuring or enforcing module boundaries in a .NET or C# solution: the project reference graph between .csproj files, cycles between assemblies or namespaces, deep reaches into another assembly's internals, fan-in and fan-out, InternalsVisibleTo, or architecture tests with ArchUnitNET or NetArchTest.
License
MIT
Instructions
72 lines in SKILL.md · view on GitHub

Files (3)

  • SKILL.md
  • SOURCES.md
  • openai.yaml · agents/

SKILL.md (first lines)

# Seams (.NET)

Tooling for the edges of **modules** in a .NET solution. Load the `gates` skill with your skill tool: its Part 2 holds the procedure (map, measure, decide, enforce, prove, document, report); this skill supplies the .NET commands. The vocabulary is the `modules` skill's (**module**, **interface**, **seam**, **depth**).

In .NET a module usually maps to a **project** (one `.csproj`, one assembly), and inside a large project to a **namespace**. A module's **interface** is its entry points: the `public` types of its contract (often a `*.Contracts` or `*.Abstractions` project, or the module's root namespace). Everything else is internals, whatever its access modifier says.

Command details, package names, and versions: [SOURCES.md](SOURCES.md). Tool facts drift between SDK releases; when a command surprises you, check the linked page or `--help` rather than memory.

## Measure the edges

Work from the solution file (`.sln`, `.slnx`, or `.slnf`).

**The project graph.** List the projects (`dotnet sln list`), then each project's direct references (`dotnet reference list --project <path>`; on SDK 9 and earlier `dotnet list <path> reference`, or `dotnet msbuild <path> -getItem:ProjectReference`). Note which projects are tests and which are hosts (web, worker, console), since they sit at the top of the graph by design.

**Cycles.** At project level MSBuild refuses a reference cycle (`dotnet build -graph` names it as MSB4251), so a solution that builds has none; say so and move to namespaces. Namespace cycles inside a project are the ones that hide. Find them with an ArchUnitNET slice rule run once as a probe (a scratch test in a test project with the package; `Architecture` is built as in the enforcement example below):

```csharp
Slices().Matching("MyApp.(*)").Should().BeFreeOfCycles().Check(Architecture);
```

The failure lists every cycle between the slices. Adjust the pattern to the level that matches the modules (`MyApp.(*)` is one namespace level under `MyApp`; `(**)` matches nested levels).

**Deep reaches**: record caller, target, and the file and line for each of these:

- A project reference to a module's implementation project where a contract project exists (`Orders` references `Billing.Infrastructure` instead of `Billing.Contracts`).
- A **transitive reach**: SDK-style project references flow transitively, so a project can use types from a project it never references. Set `<DisableTransitiveProjectReferences>true</DisableTransitiveProjectReferences>` in the caller's `.csproj` for one build, so only that project changes; every new compile error in it is a use of a project reached only transitively. Revert it afterwards unless the user chooses it as the fix.
- `using` directives or fully qualified names that name another module's internal namespaces (`*.Internal`, `*.Infrastructure`, `*.Persistence`, or whatever the module's internals are called): search the source.
- `InternalsVisibleTo`, in `.csproj` items (`<InternalsVisibleTo Include="..."/>`) and `[assembly: InternalsVisibleTo(...)]` attributes: each grant to an assembly other than the module's own tests is a reach past the interface.

**Fan-in and fan-out**, per project from the graph; report the table sorted by the sum.

Done when the graph, the cycle result (project and namespace level), the deep-reach list, and the fan-in/fan-out table are all written down, each with the command or rule that produced it.

## Enforce a boundary

The mechanisms, strongest first:

1. **The compiler, by access.** Internals are `internal`; the interface is `public`. Grant `InternalsVisibleTo` only to the module's own test project. A caller outside then can't compile against the internals at all.
2. **The compiler, by reference.** Callers reference only the contract project. To stop them reaching the implementation transitively, set `DisableTransitiveProjectReferences` to `true` in the callers (they then list every project they use directly), or have the host alone reference the implementation.
3. **An architecture test**, for rules the compiler can't express: namespace rules inside one project, "only the host references infrastructure", no cycles. Put it in a test project so `dotnet test`, and so the existing CI, runs it. ArchUnitNET (`TngTech.ArchUnitNET` plus the adapter for the test framework, such as `TngTech.ArchUnitNET.xUnit`) covers dependency and cycle rules and is actively released; NetArchTest (`NetArchTest.Rules`) covers dependency rules but hasn't been released since 2021, and its fork `NetArchTest.eNhancedEdition` adds slices. Keep whichever the project already uses.

   ```csharp
   using static ArchUnitNET.Fluent.ArchRuleDefinition;   // Types()
   using ArchUnitNET.xUnit;                              // .Check(Architecture)

   private static readonly Architecture Architecture =
       new ArchLoader().LoadAssemblies(typeof(OrderService).Assembly, typeof(Invoice).Assembly).Build();

   [Fact]
   public void Orders_does_not_reach_billing_internals() =>
       Types().That().ResideInNamespaceMatching(@"^MyApp\.Orders(\..+)?$")
           .Should().NotDependOnAny(Types().That().ResideInNamespaceMatching(@"^MyApp\.Billing\.Internal(\..+)?$"))
           .Check(Architecture);
   ```

   ArchUnitNET's `ResideInNamespace("X")` matches namespace `X` exactly, not `X.Sub`; use `ResideInNamespaceMatching` with a regex to cover a module's sub-namespaces. The slice probe from measuring (`Slices()` from `ArchUnitNET.Fluent.Slices.SliceRuleDefinition`) becomes a permanent no-cycles test the same way.

4. **A banned-API analyzer**, when a namespace or type must never be used from a set of projects: `Microsoft.CodeAnalysis.BannedApiAnalyzers` with a `BannedSymbols.txt` added as `AdditionalFiles`, one documentation ID per line (`N:MyApp.Billing.Internal` bans a namespace). Violations are RS0030 build diagnostics, errors under warnings-as-errors.

**Existing violations**: follow `gates`' red-baseline step (measure, show the count, ask). The .NET ratchet: turn the rule on for the projects or namespaces already clean, each one left out a ratchet entry, or turn RS0030 into an error project by project. Never add `NoWarn`, `#pragma warning disable`, or an exclusion in the architecture test to get green.

## Violations to plant

A `using` of the forbidden namespace plus a use of one of its types in the caller, a `ProjectReference` to the forbidden project, or an internal type called from outside. The failure names it as a compile error, RS0030, or the architecture test's failing type.

Why a rule stayed green, in .NET: architecture rules fail open quietly, through a namespace filter that matches no types (or only the top namespace), an `ArchLoader` that didn't load the assembly, or a severity left below error.

## Document the boundary

Next to the code: the module's `README.md`, or a comment at the top of the architecture test. The `CONSTRAINTS.md` row's command is `dotnet test`.

From jpenley/AITuning, MIT.

More from jpenley/AITuning

Signals

Stars
0
Forks
0
Open issues
0
Last commit (this folder)
Oct 16, 2026 (14 days ago)
Last release
Oct 17, 2026 (13 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from jpenley

Done for you

Rather not set it up yourself?

Chalk Labs scopes, builds and runs agents for your team: the task audit, the eval harness, the integrations and the weekly ops report. Fixed scope, priced before we start.

See how we build AI agents →Read the case studies

Chalk Labs is a two-founder AI and growth studio. We build AI agents, CRMs and MVPs for Web3 and AI companies, and have shipped 50+ product and token launches.

launches shipped
50+
launches shipped
media placements
500+
media placements
founders on every account
2
founders on every account

Press we've placed: Forbes · CoinDesk · Decrypt · Cointelegraph · The Block

Rahil Jain, Co-founder, Chalk Labs. Ex-Goldman Sachs engineer. You talk to the person who builds it.

Get seams-dotnet running in your business

Tell us what you want to automate. A founder replies within one working day with a plan, not a pitch deck.

Goes to the Chalk Labs founders, not the newsletter. Privacy

Need help deploying seams-dotnet?

CallGet help
Cite this page

seams-dotnet skill. Agent Mart. https://agentmart.dev/skills/jpenley-seams-dotnet (last updated 2026-10-24)