diff --git a/.claude/settings.local.json b/.claude/settings.json
similarity index 100%
rename from .claude/settings.local.json
rename to .claude/settings.json
diff --git a/.gitignore b/.gitignore
index a4fe18b..e1a1752 100644
--- a/.gitignore
+++ b/.gitignore
@@ -398,3 +398,6 @@ FodyWeavers.xsd
# JetBrains Rider
*.sln.iml
+
+# Claude local settings
+.claude/*.local.json
diff --git a/README.md b/README.md
index caabcfd..b16b516 100644
--- a/README.md
+++ b/README.md
@@ -200,6 +200,7 @@ The source generator includes analyzers that help catch common issues at compile
| [XPC3001](XrmPluginCore.SourceGenerator/rules/XPC3001.md) | Warning | Prefer nameof over string literal for handler method |
| [XPC3002](XrmPluginCore.SourceGenerator/rules/XPC3002.md) | Info | Consider using modern image registration API |
| [XPC3003](XrmPluginCore.SourceGenerator/rules/XPC3003.md) | Warning | Image registration without method reference |
+| [XPC3004](XrmPluginCore.SourceGenerator/rules/XPC3004.md) | Error | Do not use LocalPluginContext as TService in RegisterStep |
| [XPC4001](XrmPluginCore.SourceGenerator/rules/XPC4001.md) | Error | Handler method not found |
| [XPC4002](XrmPluginCore.SourceGenerator/rules/XPC4002.md) | Warning | Handler signature does not match registered images |
| [XPC4003](XrmPluginCore.SourceGenerator/rules/XPC4003.md) | Error | Handler signature does not match registered images |
diff --git a/XrmPluginCore.SourceGenerator.Tests/DiagnosticTests/LocalPluginContextAsServiceAnalyzerTests.cs b/XrmPluginCore.SourceGenerator.Tests/DiagnosticTests/LocalPluginContextAsServiceAnalyzerTests.cs
new file mode 100644
index 0000000..5ee43db
--- /dev/null
+++ b/XrmPluginCore.SourceGenerator.Tests/DiagnosticTests/LocalPluginContextAsServiceAnalyzerTests.cs
@@ -0,0 +1,277 @@
+using FluentAssertions;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+using System.Collections.Immutable;
+using XrmPluginCore.SourceGenerator.Analyzers;
+using XrmPluginCore.SourceGenerator.CodeFixes;
+using XrmPluginCore.SourceGenerator.Tests.Helpers;
+using Xunit;
+
+namespace XrmPluginCore.SourceGenerator.Tests.DiagnosticTests;
+
+///
+/// Tests for LocalPluginContextAsServiceAnalyzer that errors when LocalPluginContext is used as TService in RegisterStep.
+///
+public class LocalPluginContextAsServiceAnalyzerTests : CodeFixTestBase
+{
+ [Fact]
+ public async Task Should_Report_XPC3004_When_LocalPluginContext_Explicitly_Specified()
+ {
+ // Arrange
+ const string pluginSource = """
+
+using XrmPluginCore;
+using XrmPluginCore.Enums;
+using Microsoft.Extensions.DependencyInjection;
+using TestNamespace;
+
+namespace TestNamespace
+{
+ public class TestPlugin : Plugin
+ {
+ public TestPlugin()
+ {
+ RegisterStep(
+ EventOperation.Update,
+ ExecutionStage.PostOperation,
+ Execute);
+ }
+
+ private void Execute(LocalPluginContext context) { }
+
+ protected override IServiceCollection OnBeforeBuildServiceProvider(IServiceCollection services)
+ => services;
+ }
+}
+""";
+
+ var source = TestFixtures.GetCompleteSource(pluginSource);
+ var diagnostics = await GetDiagnosticsAsync(source);
+
+ // Assert
+ diagnostics.Should().ContainSingle(d => d.Id == "XPC3004");
+ var diagnostic = diagnostics.Single(d => d.Id == "XPC3004");
+ diagnostic.Severity.Should().Be(DiagnosticSeverity.Error);
+ diagnostic.GetMessage().Should().Contain("Contact");
+ diagnostic.GetMessage().Should().Contain("LocalPluginContext");
+ }
+
+ [Fact]
+ public async Task Should_Report_XPC3004_When_LocalPluginContext_Used_As_TService_With_Lambda()
+ {
+ // Arrange
+ const string pluginSource = """
+
+using XrmPluginCore;
+using XrmPluginCore.Enums;
+using Microsoft.Extensions.DependencyInjection;
+using TestNamespace;
+
+namespace TestNamespace
+{
+ public class TestPlugin : Plugin
+ {
+ public TestPlugin()
+ {
+ RegisterStep(
+ EventOperation.Update,
+ ExecutionStage.PostOperation,
+ ctx => ctx.TracingService.Trace("hello"));
+ }
+
+ protected override IServiceCollection OnBeforeBuildServiceProvider(IServiceCollection services)
+ => services;
+ }
+}
+""";
+
+ var source = TestFixtures.GetCompleteSource(pluginSource);
+ var diagnostics = await GetDiagnosticsAsync(source);
+
+ // Assert
+ diagnostics.Should().ContainSingle(d => d.Id == "XPC3004");
+ }
+
+ [Fact]
+ public async Task Should_Not_Report_XPC3004_When_DI_Service_Used()
+ {
+ // Arrange
+ const string pluginSource = """
+
+using XrmPluginCore;
+using XrmPluginCore.Enums;
+using Microsoft.Extensions.DependencyInjection;
+using TestNamespace;
+
+namespace TestNamespace
+{
+ public class TestPlugin : Plugin
+ {
+ public TestPlugin()
+ {
+ RegisterStep(
+ EventOperation.Update,
+ ExecutionStage.PostOperation,
+ nameof(ITestService.HandleUpdate));
+ }
+
+ protected override IServiceCollection OnBeforeBuildServiceProvider(IServiceCollection services)
+ => services.AddScoped();
+ }
+
+ public interface ITestService
+ {
+ void HandleUpdate();
+ }
+
+ public class TestService : ITestService
+ {
+ public void HandleUpdate() { }
+ }
+}
+""";
+
+ var source = TestFixtures.GetCompleteSource(pluginSource);
+ var diagnostics = await GetDiagnosticsAsync(source);
+
+ // Assert
+ diagnostics.Should().NotContain(d => d.Id == "XPC3004");
+ }
+
+ [Fact]
+ public async Task Should_Not_Report_XPC3004_For_SingleTypeParam_Overload()
+ {
+ // Arrange — RegisterStep with a single type arg uses Action
+ const string pluginSource = """
+
+using XrmPluginCore;
+using XrmPluginCore.Enums;
+using Microsoft.Extensions.DependencyInjection;
+using TestNamespace;
+
+namespace TestNamespace
+{
+ public class TestPlugin : Plugin
+ {
+ public TestPlugin()
+ {
+ RegisterStep(
+ EventOperation.Update,
+ ExecutionStage.PostOperation,
+ sp => sp.GetRequiredService