{
  "schema": "https://ai-atoms.com/schemas/skill-v1.json",
  "type": "skill",
  "id": "skill/detect-static-dependencies",
  "version": "1.0.1",
  "name": "detect-static-dependencies",
  "description": "Scan C# source files for hard-to-test static dependencies — DateTime.Now/UtcNow, File.*, Directory.*, Environment.*, HttpClient, Console.*, Process.*, and other untestable statics. Produces a ranked report of static call sites by frequency. USE FOR: find untestable statics, scan for static dependencies, testability audit, identify hard-to-mock code, find DateTime.Now usage, detect static coupling, testability report, static analysis for testability. DO NOT USE FOR: generating wrappers (use generate-testability-wrappers), migrating code (use migrate-static-to-wrapper), general code review, or finding statics that are already behind abstractions.",
  "system_prompt_fragment": "# Detect Static Dependencies\n\nScan a C# codebase for calls to hard-to-test static APIs and produce a ranked report showing which statics appear most frequently, which files are most affected, and which abstractions already exist in the .NET ecosystem to replace them.\n\n## When to Use\n\n- Auditing a project's testability before adding unit tests\n- Understanding the scope of static coupling in a legacy codebase\n- Prioritizing which statics to wrap first (highest-frequency wins)\n- Creating a migration plan for incremental testability improvements\n\n## Response Guidelines\n\n- Scale the response to the user's request. A question about a specific category (e.g., \"find time statics\") should focus on that category with file locations and counts, not produce a full report across all categories.\n- When the user provides a specific file or directory path, scan only that scope — do not expand to the entire solution unless asked.\n- The full structured report format in Step 4 is for comprehensive audit requests. For focused questions, return only the relevant subset (e.g., category summary + affected files for the requested category).\n\n## When Not to Use\n\n- The user wants wrappers generated (hand off to `generate-testability-wrappers`)\n- The user wants mechanical migration done (hand off to `migrate-static-to-wrapper`)\n- The statics are already behind interfaces or `TimeProvider`\n- The code is not C# / .NET\n\n## Inputs\n\n| Input | Required | Description |\n|-------|----------|-------------|\n| Target path | Yes | A file, directory, project (.csproj), or solution (.sln) to scan |\n| Exclusion patterns | No | Glob patterns to skip (e.g., `**/obj/**`, `**/Migrations/**`) |\n| Category filter | No | Limit to specific categories: `time`, `filesystem`, `environment`, `network`, `console`, `process` |\n\n## Workflow\n\n### Step 1: Determine scan scope\n\nResolve the target to a set of `.cs` files:\n- If a `.cs` file, scan that single file.\n- If a directory, scan all `.cs` files recursively (excluding `obj/`, `bin/`).\n- If a `.csproj`, find its directory and scan `.cs` files within.\n- If a `.sln`, parse it, find all project directories, and scan `.cs` files across all projects.\n\nAlways exclude `obj/`, `bin/`, and any user-specified exclusion patterns.\n\n### Step 2: Search for static dependency patterns\n\nScan each file for calls matching these categories:\n\n| Category | Patterns to search for | Recommended replacement |\n|----------|----------------------|------------------------|\n| **Time** | `DateTime.Now`, `DateTime.UtcNow`, `DateTime.Today`, `DateTimeOffset.Now`, `DateTimeOffset.UtcNow`, `Task.Delay(`, `new CancellationTokenSource(TimeSpan` | `TimeProvider` (.NET 8+) |\n| **File System** | `File.ReadAllText(`, `File.WriteAllText(`, `File.Exists(`, `File.Delete(`, `File.Copy(`, `File.Move(`, `Directory.Exists(`, `Directory.CreateDirectory(`, `Directory.GetFiles(`, `Directory.Delete(`, `Path.Combine(`, `Path.GetTempPath(` | `IFileSystem` (System.IO.Abstractions NuGet) |\n| **Environment** | `Environment.GetEnvironmentVariable(`, `Environment.SetEnvironmentVariable(`, `Environment.MachineName`, `Environment.UserName`, `Environment.CurrentDirectory`, `Environment.Exit(` | Custom `IEnvironmentProvider` |\n| **Network** | `new HttpClient(`, `HttpClient.GetAsync(`, `HttpClient.PostAsync(`, `HttpClient.SendAsync(` | `IHttpClientFactory` (built-in) |\n| **Console** | `Console.WriteLine(`, `Console.ReadLine(`, `Console.Write(`, `Console.ReadKey(` | `IConsole` wrapper or `ILogger` |\n| **Process** | `Process.Start(`, `Process.GetCurrentProcess(`, `Process.GetProcessesByName(` | Custom `IProcessRunner` |\n\n### Step 3: Aggregate and rank results\n\nCount each static call pattern across the entire scan scope. Produce a summary with:\n\n1. **Category summary** — total call sites per category (time, filesystem, env, etc.)\n2. **Top patterns** — the 10 most frequent individual patterns ranked by count\n3. **Most affected files** — files with the highest number of static dependencies\n4. **Existing abstractions available** — for each category, note the recommended .NET abstraction:\n   - Time → `TimeProvider` (built-in since .NET 8)\n   - File system → `System.IO.Abstractions` (NuGet package)\n   - HTTP → `IHttpClientFactory` (built-in)\n   - Environment → custom `IEnvironmentProvider`\n   - Console → custom `IConsole` or `ILogger`\n   - Process → custom `IProcessRunner`\n\n### Step 4: Present the report\n\nFormat the output as a structured report:\n\n```\n## Static Dependency Report\n\n**Scope**: <project/solution name>\n**Files scanned**: <count>\n**Total static call sites**: <count>\n\n### Category Summary\n| Category     | Call Sites | Recommended Abstraction |\n|-------------|-----------|------------------------|\n| Time         | 42        | TimeProvider (.NET 8+) |\n| File System  | 31        | System.IO.Abstractions |\n| Environment  | 12        | IEnvironmentProvider   |\n| ...          | ...       | ...                    |\n\n### Top 10 Patterns\n| # | Pattern             | Count | Files |\n|---|---------------------|-------|-------|\n| 1 | DateTime.UtcNow     | 28    | 14    |\n| 2 | File.ReadAllText    | 18    | 9     |\n| ...                                      |\n\n### Most Affected Files\n| File                          | Static Calls | Categories          |\n|-------------------------------|-------------|---------------------|\n| Services/OrderProcessor.cs    | 12          | Time, FileSystem    |\n| ...                                                               |\n\n### Migration Priority\n1. **Time** (42 sites) — Use `TimeProvider`, zero NuGet dependencies on .NET 8+\n2. **File System** (31 sites) — Use `System.IO.Abstractions` NuGet package\n3. ...\n```\n\n### Step 5: Suggest next steps\n\nBased on the report, recommend:\n- Which category to tackle first (fewest dependencies, best built-in support)\n- Whether to use `generate-testability-wrappers` for custom wrapper generation\n- Whether to use `migrate-static-to-wrapper` for mechanical bulk migration\n\n## Validation\n\n- [ ] All `.cs` files in scope were scanned (check count)\n- [ ] Report includes category totals, top patterns, and affected files\n- [ ] Each detected pattern has a recommended replacement listed\n- [ ] `obj/` and `bin/` directories were excluded\n- [ ] Migration priority is ordered by impact (count × ease of replacement)\n\n## Common Pitfalls\n\n| Pitfall | Solution |\n|---------|----------|\n| Scanning `obj/` or generated code | Always exclude `obj/`, `bin/`, and `*.Designer.cs` |\n| Counting wrapped calls as statics | Check if the call is behind an interface or injected service before counting |\n| Missing statics inside lambdas/LINQ | Search covers all code within `.cs` files, including lambdas |\n| Recommending `TimeProvider` on < .NET 8 | Check `TargetFramework` in `.csproj` — if < net8.0, recommend `NodaTime.IClock` or custom `ISystemClock` |\n| Ignoring test projects | Only scan production code — exclude `*.Tests.csproj` projects from the scan |",
  "applicable_domains": [
    "code",
    "dotnet",
    "engineering"
  ],
  "invocation": [
    "/detect-static-dependencies"
  ],
  "tags": [
    "dotnet-test",
    "dotnet",
    "csharp",
    "microsoft"
  ],
  "authored_by": "anthropics",
  "source_url": "https://github.com/dotnet/skills/blob/main/plugins/dotnet-test/skills/detect-static-dependencies/SKILL.md",
  "lifecycle": "stable",
  "category": "dotnet",
  "provenance": {
    "source": "dotnet/skills",
    "source_url": "https://github.com/dotnet/skills/blob/main/plugins/dotnet-test/skills/detect-static-dependencies/SKILL.md",
    "author": "Microsoft / .NET Foundation",
    "license": "MIT",
    "notes": "Imported by scripts/import-anthropic-skills.py."
  }
}