agentleFS
joslatjoslat/maf-doctor/.github/skills/maf-anti-pattern-scanner/SKILL.md

maf-anti-pattern-scanner

Skill14 starsChanged 3 months agoMITView on GitHub

Scans a MAF 1.3.0 codebase for known anti-patterns AFTER migration is complete. Prefer the MCP tool MafScanAntiPatterns for one-shot scans; this skill is for understanding the rule taxonomy or contributing new anti-pattern rules. Detects insecure credential usage (DefaultAzureCredential, hard-coded keys), unsafe defaults (EnableSensitiveData=true in non-dev), thread-unsafe state in AIContextProvider, missing observability (UseOpenTelemetry not wired), and missing identity (ManagedIdentityCredential preferred over secret-based auth). Counterpart to migration tooling: this is steady-state best-practice review.

We split this skill into the rules it gives an agent

8 rules. About 0 are common, 2 are distinctive, and 6 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 6

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    After a migration plan finishes — verify the converted code isn't merely compiling, it's idiomatic.

    line 12
  2. Very specific:

    Fix: Read from IConfiguration / Azure.Identity / Microsoft.Extensions.Configuration.UserSecrets.

    line 36
  3. Very specific:

    Fix: Use ProviderSessionState<T> for per-session state, or make fields readonly and immutable.

    line 49
  4. Very specific:

    Fix: Add .UseOpenTelemetry(otelOptions) to the builder chain.

    line 62
  5. Distinctive:

    When the team discovers a new anti-pattern that should be caught at scan time:

    line 103
  6. Very specific:

    Add a new MAF-AP-<AREA>-<NNN> entry above with rule + pattern + fix + source.

    line 105
  7. Very specific:

    Add the matching rule constant in src/maf-autopilot/Tools/AntiPatternScannerTool.cs.

    line 106
  8. Very specific:

    Add a test in src/maf-autopilot.Tests/AntiPatternScannerToolTests.cs proving the new rule fires.

    line 107

≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

maf-anti-pattern-scanner

The migration tooling answers "is this code on MAF 1.3.0?" This skill answers a different question: "is this MAF 1.3.0 code following best practices?" Same codebase, different lens.

When to use

  • After a migration plan finishes — verify the converted code isn't merely compiling, it's idiomatic.
  • On any clean 1.3.0 codebase as a periodic audit.
  • In CI on PRs touching MAF agent/workflow code, scoped to the diff.

When NOT to use

  • For migration discovery — that's maf-obsolete-api-registry + cs0618-hunter. This skill assumes you're already on 1.3.0.
  • For runtime correctness checks — that's maf-fan-out-validator. This skill checks idiom and configuration, not topology correctness.

Anti-patterns covered

Each is a "rule" with a unique ID, a severity, and a deterministic search pattern. The MCP tool MafScanAntiPatterns ingests this list.

Security

MAF-AP-SEC-001 — DefaultAzureCredential in production code (severity: error)

Pattern: new DefaultAzureCredential() anywhere outside a test project (*Tests.csproj). Why: DefaultAzureCredential walks an authentication chain that includes developer credentials, environment variables, and managed identity. The chain order can change between SDK versions; production deployments should NEVER tolerate that surprise. Pin to the specific credential type your environment uses. Fix: Replace with ManagedIdentityCredential (Azure-hosted) or WorkloadIdentityCredential (Kubernetes), or ClientSecretCredential / ClientCertificateCredential for explicit service principals. Source: maf-constraints.instructions.md hard rule #4.

MAF-AP-SEC-002 — Hard-coded API keys (severity: error)

Pattern: String literal matching (sk-|api[-_]?key)[A-Za-z0-9_-]{16,} anywhere in .cs files. Why: Keys in source land in git history forever. Fix: Read from IConfiguration / Azure.Identity / Microsoft.Extensions.Configuration.UserSecrets.

MAF-AP-SEC-003 — EnableSensitiveData = true in non-dev (severity: error)

Pattern: EnableSensitiveData\s*=\s*true in a file that is not under tests/, not under samples/, and not inside an #if DEBUG block. Why: Sensitive-data logging in production leaks PII, prompts, and tool arguments to the log sink. Fix: Gate behind #if DEBUG or builder.Environment.IsDevelopment(). Source: maf-constraints.instructions.md hard rule #5.

Concurrency / state

MAF-AP-CONC-001 — Instance fields on AIContextProvider (severity: error)

Pattern: A class deriving from AIContextProvider (or ChatHistoryProvider) that declares any non-readonly instance field. Why: AIContextProvider instances are shared across sessions. Mutable instance state causes cross-session leakage, races, and non-deterministic responses. Fix: Use ProviderSessionState<T> for per-session state, or make fields readonly and immutable. Source: maf-constraints.instructions.md hard rule #2.

MAF-AP-CONC-002 — .Result / .Wait() on async (severity: warning)

Pattern: \)\s*\.(?:Result|Wait)\b — a .Result / .Wait() immediately following a method CALL (e.g. SomeAsync().Result). Deliberately anchored on the call's close-paren rather than the bare member name: matching task.Result on any member would false-fire on the many non-Task .Result / .Wait properties in real code, so the bare-member form is intentionally out of scope (pinned by a regression test). Why: Sync-over-async deadlocks under SynchronizationContext. Agent runtimes pump async; mixing sync waits is a latent hang. Fix: await the expression. Make the calling method async.

Observability

MAF-AP-OBS-001 — Missing UseOpenTelemetry (severity: warning)

Pattern: A file constructs an AIAgentBuilder / ChatClientAgent but never calls UseOpenTelemetry(...) (anywhere in the same file or any sibling configuration file). Why: Without OTel, agent calls are invisible in production. Token usage, latency, errors all silent. Fix: Add .UseOpenTelemetry(otelOptions) to the builder chain. Wire to your existing OTel exporter. Source: Migration guide §13.

MAF-AP-OBS-002 — IChatClient instantiated without telemetry (severity: info)

Pattern: new ChatClient( or new OpenAIChatClient( not chained with .UseOpenTelemetry() before being passed to an agent builder. Why: OpenTelemetry must wrap the client to capture token costs. Wrap at the lowest level so every agent benefits.

Identity

MAF-AP-ID-001 — Missing ManagedIdentityCredential for Azure hosting (severity: info)

Pattern: A project references Microsoft.Extensions.Azure or Azure.AI.OpenAI and uses a secret-based credential (ClientSecretCredential, EnvironmentCredential) without a comment / config explaining why MSI was rejected. Why: Secret rotation is operational toil and a credential-leak risk. Azure-hosted services should default to managed identity. Fix: new ManagedIdentityCredential(clientId).

Output format

The scanner produces a markdown report:

## MAF anti-pattern scan — <repoPath>

### ❌ <N> errors
| Rule | File | Line | Match |
| MAF-AP-SEC-001 | src/Auth.cs | 42 | new DefaultAzureCredential() |
...

### ⚠️ <N> warnings
...

### ℹ️ <N> info
...

### ✅ <N> rules passed

How the MCP tool invokes this

The MafScanAntiPatterns(repoPath) tool walks all *.cs files under repoPath, applies the regex / Roslyn rules defined in this skill, and produces the report above. The rule IDs in this document are the source of truth; the tool's internal rule list mirrors them.

Updating this skill

When the team discovers a new anti-pattern that should be caught at scan time:

  1. Add a new MAF-AP-<AREA>-<NNN> entry above with rule + pattern + fix + source.
  2. Add the matching rule constant in src/maf-autopilot/Tools/AntiPatternScannerTool.cs.
  3. Add a test in src/maf-autopilot.Tests/AntiPatternScannerToolTests.cs proving the new rule fires.
  4. Cross-reference from maf-constraints.instructions.md if it represents a hard rule.

The cross-reference matters: if a constraint says "NEVER do X" but the scanner doesn't enforce it, the constraint is aspirational, not actionable.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.