1 The Agentic Shift: Software Engineering with Claude Code
Software engineering is evolving, but not in the way most trend pieces describe. Teams still write code, review pull requests, and run production services. What has changed is how much of the mechanical, repetitive work can be assisted. Claude Code is not a smarter autocomplete. It is a repo-aware CLI assistant that can reason over your codebase, plan multi-file changes, implement them, and help you verify results—all through natural language.
The practical challenge for senior developers and architects is no longer “should we use AI,” but “how do we integrate Claude Code safely across the SDLC without losing architectural control.” This section focuses on how Claude Code actually works in day-to-day development, how it fits into real workflows, and how humans stay in charge of design decisions.
Throughout this section, examples use current, production-ready stacks (ASP.NET Core, Angular, SQL Server) and describe real workflows, not speculative tooling.
What You’ll Need (Prerequisites)
Before running Claude Code, make sure you have:
- Operating System: macOS 13.0+, Windows 10 1809+, or Ubuntu 20.04+ / Debian 10+
- A terminal (bash, PowerShell, zsh, etc.). On Windows, Git for Windows (which provides Git Bash) is required for native Windows usage.
- An authenticated Claude account (Pro or Max is recommended, but some features also work with free plans)
- A local project folder you can work with
- Note: Node.js is no longer required if you use the recommended native installer. It is only needed for the deprecated npm installation method.
This foundational setup ensures Claude Code can load your project and reason across all files.
1.1 From Copilots to Intent-Driven Automation: How Claude Code Works
Most developers’ first experience with AI coding tools comes from inline copilots: small suggestions in an editor with limited context. Claude Code operates differently. It runs as a CLI tool that can traverse your entire repository, manage context across prompts, and produce coordinated edits across multiple files in one operation.
Instead of issuing discrete “commands” like traditional tools, you interact with Claude Code through structured prompts. A typical interaction loop looks like this:
- Describe the task in natural language
- Claude proposes a plan before writing code
- Claude implements coordinated edits across files
- You verify and refine results
This loop mirrors how senior engineers already work, but with AI assistance handling much of the routine execution.
Installing and Running Claude Code
Claude Code can be installed using several official methods. Once installed, you interact with it using the claude command.
Option 1: Native Installer (Recommended)
The native installer is Anthropic’s recommended installation method. It does not require Node.js, includes automatic background updates, and works across all supported platforms.
macOS / Linux / WSL:
curl -fsSL https://claude.ai/install.sh | bash
Windows (PowerShell):
irm https://claude.ai/install.ps1 | iex
Windows (CMD):
curl -fsSL https://claude.ai/install.cmd -o install.cmd && install.cmd && del install.cmd
Then in your terminal:
# navigate to your repo
cd billing-service
# start a Claude Code session
claude
You’ll be prompted to authenticate with your Claude account the first time you run it. Run claude doctor after installation to verify your setup.
Option 2: Package Managers
macOS (Homebrew):
brew install --cask claude-code
Windows (WinGet):
winget install Anthropic.ClaudeCode
Note: Homebrew and WinGet installations do not auto-update. Run
brew upgrade claude-codeorwinget upgrade Anthropic.ClaudeCodeperiodically.
Option 3: npm (Deprecated)
npm installation still works but is deprecated in favor of the native installer. To migrate an existing npm install, run claude install.
npm install -g @anthropic-ai/claude-code
This method requires Node.js 18+. Do not use sudo npm install -g as it can cause permission and security issues.
Windows-Specific Notes
Many development teams run Windows as their primary OS. Claude Code has first-class Windows support:
- Native Windows requires Git for Windows (which provides Git Bash). For portable Git installations, set the path:
$env:CLAUDE_CODE_GIT_BASH_PATH="C:\Program Files\Git\bin\bash.exe" - WSL (both WSL 1 and WSL 2) is also supported. WSL 2 enables sandboxing for enhanced security; WSL 1 does not.
- Binaries on Windows are signed by Anthropic, PBC, and SHA256 checksums are published in each release manifest.
IDE Integration
Claude Code has official extensions for VS Code and JetBrains IDEs (IntelliJ, PyCharm, etc.) that integrate its functionality into your editor—providing inline diffs, plan review, file @-mentions, conversation history, and checkpoint-based undo. In VS Code, the extension installs automatically the first time you run claude in the integrated terminal.
1.2 A Real End-to-End Claude Code Workflow (Plan → Execute → Verify)
To understand how Claude Code fits into the SDLC, consider a concrete example: adding a new “Billing Cycle Reset” feature to an existing ASP.NET Core API.
Step 1: Planning Before Code
First you ask Claude to write a plan, before any code is written:
I need to add a "Billing Cycle Reset" feature to this repository.
Context:
- Backend: ASP.NET Core with EF Core
- Architecture: vertical-slice (one folder per feature)
- Database: SQL Server
Task:
Create a step-by-step implementation plan. Cover:
1. Which entities and domain objects are involved
2. Commands, handlers, and validation needed
3. API endpoint(s) to expose
4. Database changes (if any)
5. Unit and integration tests to add
Do not generate code yet. Output the plan as a numbered checklist
so I can review and approve before we start coding.
Claude typically responds with:
- Identify the billing domain and relevant entities
- Add a command and handler for resetting the cycle
- Add validation rules
- Add an API endpoint
- Update database schema (if needed)
- Add unit and integration tests
This plan becomes the contract between you and Claude for the implementation phase.
Step 2: Executing the Plan
Once the plan is agreed on, you ask Claude to implement it:
Implement the Billing Cycle Reset feature using the plan you created.
Rules:
- Follow the existing folder structure and naming conventions in this repo
- Do not modify or refactor files unrelated to this feature
- Wire up validation, the command handler, and the API endpoint
- Add at least one unit test for the success path
After you finish, list every file you created or changed.
Claude then edits multiple files in one coordinated patch—including command classes, handlers, API endpoints, and tests. It accomplishes this by reasoning over the project context you provided when starting the session.
Example generated handler (simplified):
public sealed class ResetBillingCycleHandler
{
private readonly BillingDbContext _db;
public ResetBillingCycleHandler(BillingDbContext db)
{
_db = db;
}
public async Task HandleAsync(
Guid customerId,
DateTime effectiveDate,
CancellationToken ct)
{
var cycle = await _db.BillingCycles
.SingleOrDefaultAsync(x => x.CustomerId == customerId, ct);
if (cycle == null)
throw new InvalidOperationException("Billing cycle not found.");
cycle.Reset(effectiveDate);
await _db.SaveChangesAsync(ct);
}
}
Claude generates code that aligns with existing architectural patterns because it has already read the repository context.
Step 3: Verification and Iteration
After implementation, you ask Claude to verify its work:
Review every file you just created or changed for the Billing Cycle Reset feature.
Check for:
- Missing input validation or null checks
- Error handling gaps (what happens if the billing cycle is not found?)
- Missing or incomplete test coverage
- Naming or structural inconsistencies with the rest of the codebase
If you find issues, list each one and then fix them.
After fixing, run "dotnet build" to confirm the project compiles.
Claude often identifies additional concerns, explains them, and proposes fixes—acting like a second engineer reviewing the patch. The human engineer still approves and commits the final changes.
1.3 Constraints and the Human Role
Claude Code does not replace architects or senior engineers. It changes where they spend their time. Constraints matter more than prompt wording. Claude infers patterns from your project structure and existing code. If that structure is inconsistent, outputs become mixed.
Humans still decide domain boundaries, when to refactor versus extend, which trade-offs are acceptable, and what “good enough” means. Claude handles the execution-heavy parts: boilerplate generation, cross-file refactoring, repetitive test creation, and consistency enforcement.
Experienced teams invest early in written governance—architecture notes, folder rules, naming conventions, and examples of correct implementations. Claude follows these rules, not arbitrary intuition. When teams treat Claude Code as part of the SDLC—not a novelty tool—they ship faster, make fewer mechanical mistakes, and spend more time on real engineering decisions.
2 Establishing the Project Brain: Context and Governance
Claude Code does not behave like a stateless chatbot. It reasons over your repository, learns patterns from existing files, and relies heavily on written guidance inside the project. The quality of its output is directly tied to the quality of the context you give it. This is what we refer to as the “project brain.”
In practice, the project brain is not a complex configuration system. It is a small set of files and conventions that Claude Code already understands today. These files define architectural intent, workflow rules, and domain language so Claude can apply them consistently across planning, implementation, testing, and review.
For real-world Claude Code usage, the project brain has three concrete components:
- A well-written CLAUDE.md at the repository root
- The .claude/ folder for persistent context and memory
- Optional MCP servers for controlled, read-only external context
There is no multi-agent configuration file, no role-based permissions, and no built-in Jira automation. Everything starts with repository context.
2.1 CLAUDE.md: The Single Source of Architectural Truth
Claude Code automatically looks for a file named CLAUDE.md in the repository root. If present, it treats this file as authoritative guidance. This is not marketing or convention—it is how Claude Code is designed to work.
In practice, CLAUDE.md replaces CONTRIBUTING.md for agent workflows. Humans may skim it. Claude reads it every time.
A good CLAUDE.md is short, explicit, and opinionated. It does not explain why decisions were made. It explains what rules to follow.
A Practical CLAUDE.md Template That Works Today
Below is a tested, production-friendly structure that Claude Code responds to well:
# Project Overview
This repository contains a billing service built with ASP.NET Core and EF Core.
The architecture follows a vertical-slice pattern.
# Architecture Rules
- Use vertical slices organized by feature (Billing, Invoicing, Payments).
- Do not introduce shared "Common" folders.
- Each slice may contain:
- Commands
- Queries
- Handlers
- Validators
- Tests
# Backend Conventions
- ASP.NET Core Minimal APIs only.
- Commands and queries use MediatR.
- Handlers must be internal.
- EF Core DbContext is scoped per request.
- Do not access DbContext outside handlers.
# Naming Rules
- Commands end with Command.cs
- Queries end with Query.cs
- Validators end with Validator.cs
- Test files mirror production folder structure.
# Testing Rules
- Every command must have at least one unit test.
- Integration tests go under Tests/Integration.
- Do not mock DbContext in integration tests.
# Things to Avoid
- Do not introduce new architectural patterns.
- Do not refactor unrelated code.
- Do not add dependencies without calling them out explicitly.
This file alone eliminates most ambiguity. When Claude generates code, it mirrors these rules without being reminded in every prompt.
Key Principles for an Effective CLAUDE.md
Choose one architectural pattern explicitly. Claude does not invent architecture—it copies what it sees. If the repository mixes patterns, Claude will mix them too. State your choice plainly: "We use a vertical-slice architecture. Do not create separate Application or Infrastructure layers." Or for layered architecture: "Domain has no dependencies. Infrastructure depends on Domain."
List technology constraints, not version numbers. Claude does not need speculative versions. It needs boundaries: "Backend: ASP.NET Core. ORM: EF Core. Use the existing versions in the repository. Do not upgrade frameworks unless explicitly asked."
Include workflow rules. Claude respects written workflow rules even though it cannot enforce Git permissions: "Prefer small, reviewable commits. When adding new behavior, add tests first or alongside code."
2.2 The .claude/ Folder: Persistent Context and Memory
Claude Code supports a .claude/ directory for storing persistent context. This is not a configuration system. It is a memory mechanism.
Claude reads files under .claude/ automatically and treats them as durable project knowledge. In addition, Claude Code now has auto memory—a persistent directory (~/.claude/projects/<project>/memory/) where Claude records learnings, patterns, and insights as it works across sessions. You can also quickly add memories using the # key shortcut during a session (e.g., “remember that we use pnpm” or “our API tests need a local Redis instance”), and Claude will save them to your CLAUDE.md files for future reference.
A common and effective structure looks like this:
.claude/
architecture.md
domain-glossary.md
api-notes.md
architecture.md
Used for details that don’t belong in CLAUDE.md:
Billing flows are time-based.
Billing cycles can be reset manually by admins.
Historical data must not be deleted.
domain-glossary.md
This file dramatically improves Claude’s accuracy:
Billing Cycle: A fixed time range for charging a customer.
Reset: Closing the current cycle and starting a new one.
Effective Date: The timestamp that defines the start of a cycle.
Claude uses this language when naming classes, methods, and API routes.
api-notes.md
Used for integration quirks:
The billing API is consumed by the admin portal.
Breaking API changes are not allowed.
All endpoints require authentication.
This context persists across sessions without repeating prompts.
2.3 Model Context Protocol (MCP): What Is Real Today
MCP allows Claude to access external, structured context through servers you run—markdown documentation, OpenAPI specs, internal SDK docs, or read-only SQL schema metadata. It is not a built-in Jira or GitHub automation feature.
Example prompt once an MCP server is configured:
Using the internal documentation MCP server, answer these questions
about our billing system:
1. How are billing cycles calculated (monthly, quarterly, custom)?
2. What happens when a cycle boundary falls on a weekend or holiday?
3. Are there any known edge cases documented for mid-cycle resets?
Cite the specific documentation pages you found the answers in.
What MCP can and cannot do today:
- Claude can create GitHub PRs using the
ghCLI (sessions are automatically linked to PRs viagh pr create, and the--from-prflag resumes sessions linked to a specific PR). - Claude cannot natively sync Jira issues or mutate arbitrary external systems without tooling you build.
MCP extends Claude’s reach, but it is bounded by the servers and tools you explicitly configure.
The core principle is simple: every rule written once is a prompt you never have to repeat. When teams invest in CLAUDE.md and .claude/ context, Claude becomes predictable, boring, and reliable—exactly what you want from an SDLC tool.
3 Requirements Engineering and Solution Design
Claude Code is most effective when it is involved before implementation starts. When used correctly, it becomes a requirements analyst, design reviewer, and planning assistant—turning raw input (meeting notes, rough feature ideas, architectural questions) into structured artifacts that drive consistent implementation.
There are no special commands involved—everything happens through deliberate prompts, review, and reuse of outputs. The same example—Billing Cycle Reset—is threaded through requirements, design, planning, and coordination.
3.1 Agent-Driven Discovery: From Raw Notes to a Structured PRD
Most features begin as informal input. Someone summarizes a meeting, drops notes into Slack, or writes a short ticket. The first job is turning that input into something precise enough to design against.
Claude Code fits naturally here because it excels at structuring messy information without inventing requirements.
Step 1: Paste the Raw Input
Developers paste notes directly into the Claude session:
Here are notes from a billing meeting:
- Customers want to manually reset their billing cycle
- Only admins can do this
- Reset should close the current cycle and start a new one
- We need an audit trail
- The UI should show the new cycle immediately
- Performance matters; this runs during peak hours
Step 2: Ask for a Structured PRD
Instead of asking Claude to design a solution, you ask it to organize the problem:
Using the meeting notes I pasted above, create a concise Product Requirements
Document (PRD).
Structure the PRD with these sections:
1. Problem Statement — one paragraph describing the user need
2. User Roles — who can perform this action and who cannot
3. Functional Requirements — numbered list of what the system must do
4. Non-Functional Requirements — performance, security, auditability
5. Edge Cases — what happens when input is invalid, timing is wrong, etc.
Important: do not propose a technical design or database schema yet.
Keep the language plain enough for a product owner to review.
Claude produces a structured PRD. Engineers and product owners review it, adjust wording, and confirm intent. This PRD becomes a stable input for architectural decisions.
The important detail here is sequence: structure first, design later.
3.2 Architecture Decision Records (ADR) with Claude Code
Once requirements are agreed on, teams move to architectural decisions. Claude Code helps by forcing explicit trade-off analysis instead of informal reasoning.
3.2.1 Evaluating Trade-Offs with a Real Prompt
For the Billing Cycle Reset feature, a common question is whether it justifies service separation.
Claude Code prompt:
We need to decide how to implement the Billing Cycle Reset feature.
Context:
- ASP.NET Core backend
- SQL Server database
- Single deployable service today
- Team of 6 engineers
- Strong transactional consistency required
Options to evaluate:
1. Modular monolith with vertical slices
2. Separate billing microservice
Produce an ADR with:
- Context
- Decision
- Options considered
- Pros and cons
- Rationale
Claude generates an ADR draft that makes assumptions explicit. Engineers review it, remove anything inaccurate, and commit the final ADR to the repository.
Claude is not the decision maker. It is a structured reasoning aid.
3.2.2 Generating a More Realistic Mermaid Diagram
Once the ADR is accepted, teams often add diagrams for shared understanding.
Claude Code prompt:
Generate a Mermaid flowchart diagram showing the full request flow
for the Billing Cycle Reset feature.
Include these nodes in order:
- Admin Portal (UI)
- Billing API endpoint
- Authorization check
- ResetBillingCycleCommandHandler
- SQL Server database write
- Audit log insert
- BillingCycleResetEvent (domain event)
- Real-time notification to connected clients
Output only the Mermaid code block so I can paste it into a markdown file.
Claude generates a richer diagram:
flowchart LR
UI[Admin Portal] --> API[Billing API]
API --> Auth[Authorization]
Auth --> Cmd[ResetBillingCycleCommandHandler]
Cmd --> Db[(SQL Server)]
Cmd --> Audit[(Audit Log)]
Cmd --> Event[BillingCycleResetEvent]
Event --> Notify[Realtime Notification]
This diagram reflects a real production flow and is suitable for ADRs, PRDs, or onboarding docs.
3.3 Turning an Epic into a “Prompt Plan” (Team Convention)
Once requirements and architecture are agreed on, teams need a bridge between design and execution. Many teams use what they call a Prompt Plan.
It’s important to be clear: A Prompt Plan is not a Claude Code feature. It is a team convention—a structured implementation outline that Claude can reliably follow.
Think of it as a lightweight technical specification written for an agent.
Creating the Prompt Plan
Claude Code prompt:
Create a technical implementation plan for the Billing Cycle Reset feature.
Constraints:
- Follow existing vertical-slice structure
- Do not refactor unrelated code
- Use existing database schema unless explicitly required
Output format:
- Commands and handlers
- API endpoints
- Validation rules
- Database interactions
- Tests to add
Claude produces:
Feature: Billing Cycle Reset
Commands:
- ResetBillingCycleCommand
- Validate admin permissions
- Validate effective date is not in the future
Handlers:
- ResetBillingCycleHandler
- Load current billing cycle
- Close existing cycle
- Create new cycle
- Write audit log entry
API:
- POST /billing/cycle/reset
Database:
- No schema changes
- Insert audit log record
Tests:
- Unit test: successful reset
- Unit test: invalid effective date
- Integration test: end-to-end reset
This plan is reviewed and adjusted by humans. Once approved, it becomes the single source of truth for implementation.
Executing Against the Plan
Execution is explicit:
Implement the Billing Cycle Reset feature exactly as described in the
Prompt Plan above.
Rules:
- Follow existing folder structure, naming conventions, and patterns
- Create the command, handler, validator, and API endpoint
- Add unit tests for success and invalid-date scenarios
- Do not introduce new NuGet packages or refactor unrelated code
After implementation, output a summary table:
| File | Action (created/modified) | Purpose |
Claude now has a stable contract to follow, which dramatically reduces drift and rework.
3.4 Coordinating Backend and Frontend with a Single Threaded Flow
Backend and frontend coordination works best when it is sequential and explicit, not parallel and implicit.
For the Billing Cycle Reset feature, the flow looks like this:
Step 1: Implement Backend First
Claude implements commands, handlers, API endpoints, and tests based on the Prompt Plan.
Step 2: Generate an API Summary for Frontend
Once backend work is done, you ask Claude to summarize the API surface:
Summarize the Billing Cycle Reset API for frontend use.
Include:
- Endpoint
- HTTP method
- Request body
- Response shape
- Authorization requirements
Claude produces a concise, frontend-ready summary.
Step 3: Use That Summary to Generate Frontend Components
In the same or a new session:
Using the Billing Cycle Reset API summary above, generate Angular
standalone components for the admin portal.
Requirements:
- A "Reset Billing Cycle" button that calls POST /billing/cycle/reset
- After a successful reset, display the updated cycle start and end dates
- Use Angular signals for component state (not BehaviorSubject)
- Show a loading spinner during the API call and an error message on failure
- Follow existing component naming conventions and UI patterns in this repo
Do not create new services unless one does not already exist for billing API calls.
Because Claude is working from an explicit backend contract, it does not guess. This keeps backend and frontend aligned without orchestration tools or automation layers.
4 Intelligent Data Modeling: SQL Server and Persistence
Database work is where teams often hesitate to involve AI. The risk feels higher, the blast radius is larger, and mistakes are harder to undo. Claude Code fits into this part of the SDLC best when it is used as a reviewer, planner, and code generator under explicit constraints, not as an autonomous database operator.
In practice, Claude Code helps teams reason about schema changes, generate EF Core migrations, write safe backfill scripts, and review indexing decisions. The database remains authoritative, and humans stay responsible for execution in real environments. The workflow is deliberate, repeatable, and auditable.
A critical operational rule applies throughout this section: Claude should never receive production data containing PII or sensitive values. Schema definitions, migration scripts, and anonymized query plans are safe. Actual row data is not.
4.1 Reviewing and Designing Schemas with Claude Code
Claude Code does not connect directly to your database unless you explicitly provide schema information. This is a feature, not a limitation. Most teams start database work by giving Claude the schema as text and asking it to reason about structure and intent.
Reviewing an Existing Schema
A typical workflow starts like this:
Here is the current SQL Server schema for the BillingCycle table:
CREATE TABLE BillingCycle (
Id UNIQUEIDENTIFIER NOT NULL PRIMARY KEY,
CustomerId UNIQUEIDENTIFIER NOT NULL,
CurrentPeriodStart DATETIME2 NOT NULL,
CurrentPeriodEnd DATETIME2 NOT NULL,
Metadata NVARCHAR(MAX) NULL
);
Review this schema.
Call out potential performance, consistency, or maintainability issues.
Do not propose changes yet.
Claude responds with observations such as:
- Missing index on
CustomerId - Risk of unbounded JSON growth in
Metadata - No built-in support for historical/audit scenarios
At this stage, Claude is acting as a design reviewer, not a schema author.
Proposing Schema Changes Explicitly
Only after review do teams ask for proposals:
Based on the schema review above, propose concrete schema improvements
for the BillingCycle table.
Constraints:
- Database: SQL Server
- ORM: EF Core (code-first migrations)
- All changes must be backward compatible (no dropping columns, no renaming)
- Include the exact SQL ALTER/CREATE statements I can review
For each change, explain the trade-off (e.g., added index improves reads
but slows inserts). Do not apply changes — just propose them.
Claude suggests changes and explains trade-offs. Humans decide what moves forward and what does not.
4.1.1 Temporal Tables and JSON Columns as a Deliberate Choice
When teams choose to use temporal tables or JSON columns, Claude Code helps by generating consistent, repeatable patterns, not by inventing database features.
Example prompt:
We want to add history tracking for BillingCycle using SQL Server temporal tables.
Generate the SQL definition and explain how EF Core should map to it.
Example output:
CREATE TABLE BillingCycle (
Id UNIQUEIDENTIFIER NOT NULL PRIMARY KEY,
CustomerId UNIQUEIDENTIFIER NOT NULL,
CurrentPeriodStart DATETIME2 NOT NULL,
CurrentPeriodEnd DATETIME2 NOT NULL,
Metadata NVARCHAR(MAX) NULL,
SysStartTime DATETIME2 GENERATED ALWAYS AS ROW START,
SysEndTime DATETIME2 GENERATED ALWAYS AS ROW END,
PERIOD FOR SYSTEM_TIME (SysStartTime, SysEndTime)
)
WITH (SYSTEM_VERSIONING = ON);
Claude also explains how historical queries work and when they should be used, which prevents misuse later in reporting or audit flows.
4.1.2 Indexing Decisions as a Human–Claude Review Loop
Indexing is where Claude Code is most helpful—and where caution matters most.
Claude does not see live workloads. It reasons only from what you provide. The correct workflow is:
- Capture slow queries or execution plans manually
- Paste query text and plan summaries into Claude
- Ask for analysis and index suggestions
Example prompt:
This query is slow under load:
SELECT *
FROM BillingCycle
WHERE CustomerId = @customerId;
Execution plan summary:
- Clustered index scan
- ~2 million rows scanned
- High logical reads
Suggest indexing options and explain trade-offs.
Claude may suggest:
CREATE INDEX IX_BillingCycle_CustomerId
ON BillingCycle (CustomerId)
INCLUDE (CurrentPeriodStart, CurrentPeriodEnd);
Important caution: Claude’s index suggestions are hypotheses, not guarantees. Always validate proposed indexes in a staging environment using real execution plans and representative data volumes before applying them to production. Indexes affect write performance, storage, and maintenance costs, which Claude cannot observe directly.
Claude helps you think faster, not skip validation.
4.2 Code-First vs Database-First: How Claude Fits In
Claude Code adapts to whichever approach the team chooses, as long as the choice is documented.
The rule is simple: Claude follows the source of truth you declare.
- Code-first: Paste an EF Core entity and ask Claude to “Review it and propose the EF Core migration it would generate. Call out any risky operations.” Claude highlights column additions, nullability changes, and potential data loss risks.
- Database-first: Paste the SQL schema and ask Claude to “Generate EF Core entity and mapping. Do not propose schema changes.” Claude produces entity classes that mirror the database exactly.
- Migrations: Claude should never apply migrations—its role is generation and review. Example: “Generate an EF Core migration for adding Metadata column to BillingCycle. The column must be nullable. No data backfill yet.”
Developers remain responsible for reviewing and applying migrations in all cases.
4.2.1 Safe, Idempotent Data Backfills with Claude Code
Backfills are where Claude Code shines only when rules are explicit.
Example prompt:
We need to backfill Metadata.periodType = 'monthly'
for existing BillingCycle rows where Metadata is null.
Rules:
- Must be idempotent
- Must be safe to run multiple times
- Must avoid long table locks
Generate a SQL script.
Example output (unchanged, intentionally):
IF NOT EXISTS (
SELECT 1 FROM MigrationLog WHERE Name = 'Backfill-BillingCycle-PeriodType'
)
BEGIN
UPDATE BillingCycle
SET Metadata = JSON_MODIFY(COALESCE(Metadata, '{}'), '$.periodType', 'monthly')
WHERE Metadata IS NULL;
INSERT INTO MigrationLog (Name, AppliedOn)
VALUES ('Backfill-BillingCycle-PeriodType', SYSUTCDATETIME());
END
Claude also explains why each guard exists, making the script easier to audit and reuse.
4.3 Using Claude Code to Detect Schema Drift
Claude Code does not have a built-in schema diff feature. Instead, teams pair existing diff tools with Claude’s reasoning.
Common, practical combinations include:
dotnet ef migrations scriptvs. live schema exports- SQL Server Data Tools (SSDT) schema compare
sqldifforsqlpackage /Action:DriftReport- Plain text diffs of model snapshots
Workflow:
- Generate a schema diff using your tool of choice
- Paste the relevant differences into Claude
Example prompt:
I have two sources of truth that have drifted apart.
Source A — EF Core model snapshot (pasted below):
<paste your EF Core model snapshot here>
Source B — Live SQL Server schema diff (pasted below):
<paste your schema diff output here>
For each mismatch:
1. Describe what differs (column type, nullability, missing index, etc.)
2. Recommend which side should change (code or database) and why
3. Provide the exact migration step or SQL statement to fix it
Do not apply any changes — just list and explain.
Claude explains the impact of each mismatch and suggests corrective steps, but does not apply changes automatically. Humans stay in control.
5 Middleware Orchestration: Building the Backend with Claude Code
Backend development is where Claude Code starts to feel genuinely useful. The patterns are repetitive, the rules are well-defined, and small inconsistencies can quickly spread across a codebase. We call this working style intent-driven development: developers describe what they want and what constraints apply, and Claude generates code that fits the existing architecture. Humans remain responsible for deciding why and whether those changes are correct.
5.1 Intent-Driven Development for ASP.NET Core
Claude Code reads the repository, applies rules from CLAUDE.md, and generates code that matches existing patterns. This is constrained execution, not free-form generation.
Example: Adding a New API Endpoint
Claude Code prompt:
Add a new API endpoint to reset a billing cycle.
Constraints:
- Use existing MediatR command handlers
- Follow the vertical-slice structure
- Endpoint must require authentication
- Do not refactor unrelated code
After implementing, summarize the files you changed.
Claude responds with a short plan, then generates coordinated changes across multiple files. One of those files is the Minimal API endpoint.
Generated Minimal API Endpoint
app.MapPost("/billing/cycle/reset", async (
ResetBillingCycleRequest request,
ISender sender,
CancellationToken ct) =>
{
var command = new ResetBillingCycleCommand(
request.CustomerId,
request.EffectiveDate);
var result = await sender.Send(command, ct);
return result.Success
? Results.Ok()
: Results.BadRequest(result.Error);
})
.RequireAuthorization();
Claude generated this because:
- Minimal APIs are already used in the repo
- MediatR is the established orchestration pattern
- Authentication requirements were explicit
If your project uses controllers, pipeline behaviors, or direct handler invocation instead of MediatR, Claude will follow those patterns just as consistently. The same applies to SignalR, gRPC, or other integrations—as long as the intent and boundaries are explicit in your prompt.
5.1.1 The Plan → Compile → Fix Loop in Practice
Claude Code does not silently “fix everything.” It works through the same feedback loop as a human developer, using compiler and test output as input.
Step 1: Build Fails
After generation, you run the build:
$ dotnet build
Compiler output:
error CS7036: There is no argument given that corresponds to the required
parameter 'ct' of 'ISender.Send<TResponse>(IRequest<TResponse>, CancellationToken)'
Step 2: Paste the Error Back to Claude
Claude Code prompt:
The build failed with this compiler error:
CS7036: There is no argument given that corresponds to the required
parameter 'ct' of ISender.Send<TResponse>(IRequest<TResponse>, CancellationToken)
The error is in the Billing Cycle Reset endpoint code you just generated.
Fix only the call site that is missing the CancellationToken argument.
Do not change any business logic or other files.
After fixing, run "dotnet build" to confirm it compiles.
Step 3: Claude Applies a Targeted Fix
var result = await sender.Send(command, ct);
Claude explains what it changed and why. No unrelated files are touched. This loop—generate, compile, fix—is where Claude Code feels like a real collaborator rather than a code generator.
5.2 Applying Domain Patterns with Claude Code
Claude Code is most effective with domain patterns once those patterns already exist. It does not invent Domain-Driven Design, CQRS, or eventing on its own, but it applies them consistently when they are present.
5.2.1 Aggregates, Value Objects, and Domain Events
Claude Code prompt:
Refactor the Billing Cycle Reset logic to follow our domain model patterns.
Changes needed:
1. Move the reset business rules into the BillingCycle aggregate (not the handler)
2. Create a BillingPeriod value object for (Start, End) dates
3. Raise a BillingCycleResetEvent domain event when a cycle is reset
4. Keep the existing API endpoint and handler behavior unchanged
Follow the naming and event-dispatching patterns already used in this codebase.
Do not change unrelated aggregates or handlers.
After refactoring, run "dotnet build" to verify compilation.
Generated Value Object
public sealed record BillingPeriod(DateTime Start, DateTime End)
{
public static BillingPeriod From(DateTime start)
=> new(start, start.AddMonths(1));
}
Generated Domain Event
public sealed record BillingCycleResetEvent(
Guid CustomerId,
DateTime EffectiveDate);
Aggregate Method
public void Reset(DateTime effectiveDate)
{
Period = BillingPeriod.From(effectiveDate);
AddDomainEvent(new BillingCycleResetEvent(CustomerId, effectiveDate));
}
Claude mirrors naming, event dispatching, and method structure based on what already exists in the codebase. If your system uses different patterns—direct services, domain services, or simple procedural logic—Claude follows those instead.
5.2.2 Middleware Configuration Through Explicit Intent
Middleware ordering and cross-cutting concerns (authentication, logging, correlation IDs) are areas where Claude performs well—as long as you state the ordering constraints explicitly. For example: “Authentication must run before authorization. Logging must include a trace ID. Do not change existing middleware order beyond this.” Claude generates the setup code and respects the ordering rules without touching unrelated middleware.
5.3 Commands, Validation, and Consistency at Scale
Once a validation pattern is established, Claude Code applies it consistently across commands and queries.
Claude Code prompt:
Add input validation to ResetBillingCycleCommand using FluentValidation.
Validation rules:
- CustomerId must not be empty
- EffectiveDate must not be in the future
Follow the existing validator patterns in this repo (look at other *Validator.cs
files for naming, constructor style, and how validators are wired into the pipeline).
Do not modify the command class itself — only add the validator.
Generated Command
public sealed record ResetBillingCycleCommand(
Guid CustomerId,
DateTime EffectiveDate)
: IRequest<ResetBillingCycleResult>;
Generated Validator
public sealed class ResetBillingCycleValidator
: AbstractValidator<ResetBillingCycleCommand>
{
public ResetBillingCycleValidator()
{
RuleFor(x => x.CustomerId).NotEmpty();
RuleFor(x => x.EffectiveDate)
.LessThanOrEqualTo(DateTime.UtcNow);
}
}
Claude also verifies that the validator is wired into the existing pipeline rather than requiring manual checks inside handlers.
Common Mistakes to Watch For
Even with good prompts, teams commonly run into a few pitfalls:
- Allowing Claude to infer patterns instead of stating constraints
- Forgetting to specify middleware order
- Asking for “cleanup” alongside feature work
- Not reviewing generated code before compiling
Claude Code amplifies clarity just as much as it amplifies ambiguity. When intent and boundaries are explicit, backend generation becomes predictable and boring—in the best possible way.
6 Modern Frontend: Angular (Signals) and the Reactive UI
Modern Angular development has shifted toward signals as the default state primitive. This change is less about new syntax and more about predictability. Signals make data flow explicit, reduce lifecycle complexity, and are easier for tooling—including Claude Code—to reason about.
This section focuses on Angular 17+ as it exists today, and shows how Claude Code fits into real frontend workflows: migrating legacy code, generating components from APIs, managing state, and enforcing UI consistency.
6.1 Signal-Based Architecture
Angular signals simplify component logic by making state reads and writes explicit—which also makes them easier for Claude Code to reason about. Signals remove implicit subscriptions and teardown logic, reducing the chance of incorrect or partial refactors during automated edits.
Most teams adopt a simple rule (added to CLAUDE.md): signals for component and UI state; observables only at system boundaries (HTTP, WebSockets). Observables still matter at those boundaries because HTTP streams and WebSocket messages are naturally push-based, while signals are better suited for representing current state inside the UI.
6.1.1 Migrating from Observables to Signals with Claude Code
Migration is where Claude Code saves the most time. Instead of rewriting components by hand, teams ask Claude to refactor them with clear scope.
Starting component (legacy pattern):
export class BillingStatusComponent {
private readonly _status$ = new BehaviorSubject<BillingStatus | null>(null);
readonly status$ = this._status$.asObservable();
load(status: BillingStatus) {
this._status$.next(status);
}
}
Claude Code prompt:
Migrate this Angular component from BehaviorSubject-based state
to Angular signals.
Rules:
- Do not change public behavior
- Do not introduce new services
- Update the template if needed
Generated component using signals:
import { signal } from '@angular/core';
export class BillingStatusComponent {
readonly status = signal<BillingStatus | null>(null);
load(status: BillingStatus) {
this.status.set(status);
}
}
Updated template:
<div *ngIf="status() as s">
<span>{{ s.period }}</span>
</div>
Claude succeeds here because:
- The scope was explicit
- The migration rule was clear
- Signals eliminate lifecycle ambiguity
This pattern is repeatable across large codebases.
6.1.2 Generating Components from OpenAPI Specs Using Claude Code
Frontend work often starts after backend APIs exist. Claude Code fits naturally into this handoff by consuming OpenAPI specs and generating typed Angular components.
Step 1: Provide the API Contract
Here is the OpenAPI definition for the billing status endpoint:
GET /billing/status/{customerId}
Response:
{
"customerId": "guid",
"period": "string",
"nextReset": "date-time"
}
Step 2: Prompt Claude to Generate the Component
Claude Code prompt:
Generate an Angular standalone component for the billing status endpoint
defined above (GET /billing/status/{customerId}).
Requirements:
- Use Angular signals for all component state (status, loading, error)
- Call the API using the existing BillingApiClient service
- Show a loading spinner while the request is in progress
- Show an error message if the request fails
- Display customerId, period, and nextReset from the response
- Follow the existing component naming conventions in this project
Generate both the TypeScript component and the HTML template.
Generated Component
@Component({
selector: 'app-billing-status',
standalone: true,
templateUrl: './billing-status.component.html'
})
export class BillingStatusComponent {
readonly status = signal<BillingStatus | null>(null);
readonly loading = signal(false);
readonly error = signal<string | null>(null);
constructor(private readonly api: BillingApiClient) {}
async load(customerId: string) {
this.loading.set(true);
this.error.set(null);
try {
this.status.set(await this.api.getStatus(customerId));
} catch {
this.error.set('Failed to load billing status');
} finally {
this.loading.set(false);
}
}
}
Claude generates both TypeScript and HTML because the intent was complete and bounded.
6.2 Managing Complex State with Signals (Without Overengineering)
Signals reduce the need for heavy global state solutions, but shared state still exists in real applications. Claude Code handles this best when teams keep state containers minimal by default and scale only when needed.
6.2.1 Generating a Signal-Based Store
Claude Code prompt:
Create a signal-based store for billing data.
Requirements:
- Store current billing cycle
- Allow updates from API responses
- No RxJS
Generated Store
@Injectable({ providedIn: 'root' })
export class BillingStore {
private readonly _cycle = signal<BillingCycle | null>(null);
readonly cycle = this._cycle.asReadonly();
setCycle(cycle: BillingCycle) {
this._cycle.set(cycle);
}
}
This minimal store is appropriate when state is small and tightly scoped. Teams scale up to more structured stores (computed signals, derived selectors, or feature-scoped services) only when complexity demands it. Claude handles coordinated multi-file updates (TypeScript, HTML, CSS) well when you ask for one cohesive change with explicit scope and constraints.
6.3 Enforcing UX Consistency
Claude cannot infer your design system. Persist UI rules in a file such as .claude/ui-kit.md (e.g., “Angular Material for dialogs, Tailwind for layout, no custom SCSS, primary buttons use mat-raised-button with color=‘primary’”). Once these rules are part of the working context, Claude applies them consistently across all generated components, preventing UI drift over time.
6.4 The Frontend Feedback Loop
The frontend workflow mirrors the backend Plan → Compile → Fix loop from Section 5.1.1: finalize the API, paste the OpenAPI spec, generate the component, run the build, and feed any errors back to Claude.
Example fix prompt:
The Angular build failed with this TypeScript error:
Property 'active' does not exist on type 'BillingStatus'.
The error is in BillingStatusComponent.
Fix the component so it compiles. Do not change the BillingStatus interface
or the backend API — the fix must be on the component/template side only.
After fixing, run "ng build" to verify it compiles cleanly.
Signal-based components are also straightforward to test—unit tests assert signal values after method calls, without needing fake async schedulers. Claude can generate these tests reliably once it sees one example in the codebase.
7 The Quality Loop: QA and Testing with Claude Code
Testing is where Claude Code proves whether it belongs in the SDLC. Code generation alone is cheap—helping teams maintain correctness over time is not. Claude fits best into QA workflows when it is used as a second engineer who reads failures, reasons about intent, and proposes fixes that humans can review.
This section covers unit test generation, fixing failures from real test output, maintaining Playwright tests as the UI evolves, and analyzing performance results. The core pattern is always the same: fail → paste output → fix → rerun.
7.1 Unit Testing at Scale with xUnit and Moq
Claude Code generates unit tests reliably when it understands three things: the domain model, existing test style, and what behavior matters. That context usually already exists in the repository.
Generating Unit Tests from Existing Code
A typical workflow starts with a concrete request.
Claude Code prompt:
Generate unit tests for ResetBillingCycleCommandHandler.
Rules:
- Use xUnit
- Follow existing test naming conventions
- Cover the success path only for now
- Use in-memory database setup from existing tests
Claude scans the handler, looks at existing test patterns, and produces a test like this:
public sealed class ResetBillingCycleTests
{
[Fact]
public async Task Resets_Cycle_When_Request_Is_Valid()
{
var db = BillingContextFactory.Create();
var handler = new ResetBillingCycleCommandHandler(db, new TestClock());
var result = await handler.Handle(
new ResetBillingCycleCommand(Guid.NewGuid(), DateTime.UtcNow),
CancellationToken.None);
Assert.True(result.Success);
}
}
At this stage, Claude is acting as a test author, not a test runner.
7.1.1 Fixing Failing Tests Using Real Compiler Output
Claude Code does not auto-fix tests. Instead, developers paste real failures back into the session and ask Claude to reason about them.
Step 1: Run Tests Locally
$ dotnet test
Example failure:
System.InvalidOperationException:
Sequence contains no matching element
Step 2: Paste the Failure into Claude
Claude Code prompt:
This test failed when I ran "dotnet test":
System.InvalidOperationException: Sequence contains no matching element
The failing test is Resets_Cycle_When_Request_Is_Valid in ResetBillingCycleTests.
The handler under test is ResetBillingCycleCommandHandler.
Read both files, identify why the exception is thrown
(likely missing seed data in the test setup), and fix the test.
Do not change the handler's public behavior.
After fixing, run the single test to confirm it passes.
Claude reads both the test and handler, identifies that required test data was missing, and proposes a fix.
Step 3: Claude Applies a Targeted Change
db.BillingCycles.Add(new BillingCycle
{
CustomerId = customerId,
CurrentPeriodStart = DateTime.UtcNow.AddMonths(-1),
CurrentPeriodEnd = DateTime.UtcNow
});
Claude explains why the fix is necessary and does not touch unrelated logic. The developer reruns the tests and confirms they pass.
This fail → paste output → fix → rerun loop is the core quality workflow.
7.1.2 Generating Edge-Case Tests Deliberately
Claude does not chase coverage numbers blindly. Instead, teams ask it to reason about missing behavior.
Claude Code prompt:
Review ResetBillingCycleCommandHandler and its existing tests.
1. List edge cases that are NOT covered by current tests
(e.g., future dates, missing customer, concurrent resets)
2. Pick the single most important untested edge case
3. Generate one new xUnit [Fact] test for that case, following existing
test naming and setup patterns in this project
4. Run the new test to confirm it passes (or fails as expected if the
handler does not yet handle the case)
Claude responds with reasoning and produces a focused test:
[Fact]
public async Task Returns_Error_When_EffectiveDate_Is_In_Future()
{
var db = BillingContextFactory.Create();
var handler = new ResetBillingCycleCommandHandler(db, new TestClock());
var futureDate = DateTime.UtcNow.AddDays(1);
var result = await handler.Handle(
new ResetBillingCycleCommand(Guid.NewGuid(), futureDate),
CancellationToken.None);
Assert.False(result.Success);
}
This keeps coverage meaningful rather than inflated.
7.2 End-to-End Testing with Playwright and Claude Code
E2E tests are brittle by nature. UI changes break selectors, layouts shift, and timing assumptions fail. Claude Code helps by maintaining tests, not by inventing them blindly.
Writing an Initial Playwright Test
Claude Code prompt:
Generate a Playwright test for the billing status page.
Requirements:
- Navigate to /billing/status/{customerId}
- Assert billing period is visible
- Use data-testid selectors where possible
Generated test:
def test_billing_status(page):
page.goto("/billing/status/123")
page.wait_for_selector("[data-testid='billing-status']")
assert page.locator("[data-testid='billing-period']").is_visible()
Claude prefers stable selectors when asked explicitly.
7.2.1 Maintaining Tests When the UI Changes
When UI changes break tests, Claude Code helps diagnose and update them.
Step 1: Test Failure
TimeoutError: waiting for selector "#status"
Step 2: Paste Failure and Markup
Claude Code prompt:
This Playwright test failed with:
TimeoutError: waiting for selector "#status"
The test file is: tests/e2e/billing_status.spec.py
The updated HTML for the billing status page now uses data-testid attributes
instead of bare IDs (e.g., data-testid="billing-status" replaced #status).
Read the test file and the current HTML markup, then update the test
selectors to match the new structure. Prefer data-testid selectors for
stability. Do not change the production HTML.
Claude identifies that #status was replaced with data-testid="billing-status" and updates the test accordingly:
page.wait_for_selector("[data-testid='billing-status']")
Claude may suggest adding data-testid attributes if stability is poor, but it does not modify production code unless explicitly asked.
A Note on Flaky Tests
Claude is also useful when tests fail intermittently. By pasting multiple failure logs, timing output, or retry traces, teams can ask Claude to identify patterns—race conditions, async timing assumptions, or reliance on unstable selectors—and suggest stabilizing changes.
7.2.2 Visual Regression Testing as a Review Aid
Claude Code does not run visual diff tools (Playwright snapshots, Percy, Chromatic, etc.), but it works well alongside them. The workflow is: run your visual tests, then paste the snapshot diff summary into Claude.
Claude Code prompt:
A visual regression test failed for the billing status page.
Snapshot diff summary:
<paste your diff summary here — e.g., "3 regions changed: header spacing
increased by 4px, badge color shifted, footer text wrapped to two lines">
Based on this diff:
1. Which changes look intentional (e.g., matching a recent design update)?
2. Which changes look like regressions or unintended side effects?
3. Should I accept this new snapshot baseline or investigate further?
Humans decide whether to accept or reject the diff.
7.3 Performance Testing with Claude Code as an Analyst
Claude Code does not execute load tests or benchmarks. It analyzes results and trends.
k6 Load Test Analysis
After running a k6 test manually, developers paste results.
Sample k6 output:
http_req_duration..............: avg=320ms p95=820ms max=1.4s
http_req_failed................: 0.20%
http_reqs......................: 18,000
vus............................: 50
iterations.....................: 18,000
Claude Code prompt:
Analyze the k6 load test results I pasted above for the billing status
endpoint (GET /billing/status/{customerId}).
Context:
- Traffic was steady at ~100 requests per second for 3 minutes
- Backend: ASP.NET Core + EF Core + SQL Server
- No caching layer in front of the database
Based on the avg, p95, and max latency plus the error rate:
1. What do these numbers tell us about system behavior under load?
2. What are the most likely bottlenecks (database, connection pool, etc.)?
3. What specific diagnostic steps should I take next?
Do not suggest code changes yet — just diagnosis.
Claude responds with reasoning such as:
- p95 latency suggests contention under load
- Error rate is low but non-zero, worth investigating timeouts
- Likely contributors include database reads or missing indexes
- Next steps: profile handler execution, review query plans, add timing logs
Claude does not guess fixes—it suggests where to look. The same pattern applies to microbenchmarks (BenchmarkDotNet, etc.): paste the results, ask Claude to explain cost drivers, and let it suggest optimizations without touching code unless explicitly asked.
8 Cloud Operations: Azure, IaC, and Day 2 Maintenance
Day 2 operations are where software systems either stabilize or slowly degrade. Claude Code fits into this phase as a diagnostic and change-generation assistant that works from real artifacts: logs, configuration files, IaC templates, and pipeline definitions. Humans still run commands, deploy changes, and approve pull requests. Claude accelerates the thinking and writing parts of the loop.
8.1 Infrastructure as Code with Claude Code (Bicep and Terraform)
Claude Code is effective with Infrastructure as Code because IaC is declarative, diff-friendly, and text-based. The agent does not apply infrastructure changes; it generates and edits templates that engineers then review and deploy.
Generating or Modifying Bicep Templates
A realistic workflow starts with intent and constraints.
Claude Code prompt:
We need to provision an Azure App Service for the billing API.
Requirements:
- Linux App Service
- HTTPS only
- System-assigned managed identity
- Diagnostic logs enabled
Generate a Bicep file.
Do not include environment-specific values.
Claude generates a template like this:
param appName string
param location string = resourceGroup().location
param dotnetVersion string = 'DOTNETCORE|8.0'
resource app 'Microsoft.Web/sites@2022-09-01' = {
name: appName
location: location
kind: 'app,linux'
identity: {
type: 'SystemAssigned'
}
properties: {
httpsOnly: true
siteConfig: {
linuxFxVersion: dotnetVersion
}
}
}
Parameterizing the runtime version keeps the template reusable and avoids unnecessary churn when platform versions change.
If requirements evolve later, you ask for a narrow update.
Claude Code prompt:
Update the Bicep template to enable Application Insights diagnostics.
Do not modify unrelated resources.
Claude edits only the relevant sections and explains the diff so it can be reviewed safely.
Editing Existing Terraform Safely
Claude works just as well with Terraform when you provide context.
Claude Code prompt:
Here is our existing Terraform module for App Service.
Add support for system-assigned managed identity.
Do not change variable names.
Claude produces a minimal, reviewable change instead of rewriting the module wholesale.
8.2 CI/CD Pipelines as Living Code
Pipelines tend to drift over time as teams add steps, fix issues, and respond to incidents. Claude Code helps teams reason about pipelines and make deliberate edits without breaking delivery.
Reviewing a Pipeline
Claude Code prompt:
Review this GitHub Actions workflow.
Call out:
- Missing quality gates
- Obvious inefficiencies
- Risky deployment steps
Do not rewrite it yet.
Claude responds with observations, not changes. This mirrors how a senior engineer reviews CI/CD configuration.
Making a Targeted Pipeline Change
Once a decision is made, execution is explicit.
Claude Code prompt:
Update this pipeline to:
- Fail if tests fail
- Upload test results as artifacts
- Keep existing structure
Generate only the YAML changes.
Claude edits the YAML and explains what changed and why. This keeps CI/CD evolution intentional rather than reactive.
8.3 Agent-Assisted Observability (Realistic and Human-Led)
Claude Code does not connect directly to Azure Monitor, Application Insights, or production systems. Observability workflows remain human-driven. Claude’s role is to analyze the evidence you provide and help you reason faster.
This is best described as agent-assisted observability, not automated monitoring.
Important: Never paste secrets, connection strings, access tokens, or customer PII into Claude. Logs and metrics should be scrubbed or summarized before sharing.
8.3.1 Diagnosing Issues from Logs and Metrics
A realistic incident workflow looks like this:
- Engineer notices alerts or failures
- Engineer copies logs, metrics, or query results
- Claude helps interpret them
Claude Code prompt:
I need help diagnosing a production issue from Application Insights data.
Symptoms observed:
- TimeoutException in ResetBillingCycleHandler (87 failures in the last hour)
- Failures occur only under high load (>80 concurrent requests)
- Average request time spikes from ~120ms to ~900ms during incidents
- No recent code deployments or config changes
Stack: ASP.NET Core, EF Core, SQL Server on Azure App Service.
Based on these symptoms:
1. List the most likely root causes in order of probability
2. For each cause, suggest one specific diagnostic action I can take
(a KQL query, a SQL DMV check, a config setting to inspect, etc.)
3. Tell me what to rule out first to narrow the investigation fastest
Claude responds with hypotheses rather than certainties:
- Database query not using an index under load
- Cancellation tokens not respected
- Connection pool pressure during peak traffic
The value is in narrowing the investigation, not declaring a root cause.
Using KQL with Claude (Safely)
Engineers typically run KQL queries themselves, then ask Claude to interpret the results.
Example KQL query:
requests
| where name == "POST /billing/cycle/reset"
| where timestamp > ago(1h)
| summarize
count(),
avg(duration),
percentile(duration, 95)
by success
Claude Code prompt (paste the KQL output inline):
Here is the KQL query output for POST /billing/cycle/reset over the last hour:
success | count | avg_duration | p95_duration
true | 12,430 | 180ms | 420ms
false | 87 | 910ms | 1,600ms
Questions:
1. What does the latency gap between successful and failed requests tell us?
2. Is the 0.7% failure rate concerning at this traffic volume?
3. What should we investigate next — slow database queries, connection pool
exhaustion, retry storms, or something else?
Claude might point out that failures correlate with much higher latency and suggest focusing on slow paths, database access patterns, or retry behavior.
8.3.2 Generating a Hotfix from Real Evidence
Claude Code does not have a “hotfix” command. Hotfixes start with evidence and intent.
Step 1: Provide the Evidence
Claude Code prompt:
We have a production incident — need a minimal hotfix.
Symptoms:
- TimeoutException thrown in ResetBillingCycleHandler
- Stack trace points to the EF Core SingleAsync query
- Only happens under high load (~100+ concurrent requests)
- Average response time spikes from 120ms to 900ms during the issue
The handler file is: src/Billing/ResetBillingCycleHandler.cs
Read the handler, then propose the smallest possible code change that
reduces database overhead for this query path. Do not change business
logic, domain rules, or the public API contract.
Explain the trade-off of your proposed fix.
Step 2: Claude Proposes a Minimal Change
await _db.BillingCycles
.AsNoTracking()
.FirstOrDefaultAsync(
x => x.CustomerId == command.CustomerId,
cancellationToken);
Claude explains why the change reduces overhead and what trade-offs it introduces.
Step 3: Add a Regression Test
Claude Code prompt:
Add an integration test for ResetBillingCycleHandler that verifies
cancellation tokens are respected.
The test should:
1. Create a valid billing cycle in the in-memory database
2. Pass a pre-cancelled CancellationToken to the handler
3. Assert that the handler throws OperationCanceledException (or equivalent)
4. Assert that no database changes were persisted
Follow existing integration test patterns in Tests/Integration/.
Run the test after generating it to confirm it passes.
Claude generates a test that fails before the fix and passes afterward. Humans still decide when and how to deploy.
8.4 Conclusion: A Practical Human–Agent Operations Model
Claude Code does not replace SREs, platform engineers, or on-call rotations. It replaces the slowest parts of the loop: reading noisy logs, correlating signals, reasoning about IaC changes, and writing careful fixes under pressure. Engineers still run CLI commands, apply infrastructure changes, deploy through CI/CD, and monitor production systems. Claude reduces cognitive load, not accountability.
Across the SDLC—from requirements to production—Claude works best when humans provide evidence and intent, Claude proposes structured changes, and humans review, approve, and execute.
What’s next for teams adopting this model: start small. Use Claude for log analysis, IaC reviews, and post-incident fixes before expanding into broader operational workflows. The payoff comes not from autonomy, but from consistency and clarity—when it matters most.