← Live! 360 Orlando 2026 resources

Thu Nov 19 · time TBA

Agentic DevOps: How I Use Claude Code and Azure DevOps to Ship Code While I Sleep

Every night a scheduled Azure Pipeline picks up one work item tagged claude-ready, has Claude Code build it, runs the build and tests, and opens a pull request. In the morning you review it like a teammate's PR. Here's how to set it up: six steps, one afternoon.

What you need

  • An Azure DevOps project with a repo and Azure Pipelines
  • An Anthropic API key (platform.claude.com)
  • Azure Key Vault (optional; a secret pipeline variable works too)
  • Claude Code installed on your machine

Step 1: CLAUDE.md, set it up once

You won't read this file day to day. Claude does, on every run, at your desk or at 2 AM. Set it up right once, then let Claude keep it current.

  1. 1.
    Run /init in Claude Code. It writes the first version from your code.
  2. 2.
    Tell Claude what to add: build and test commands, your coding patterns, which packages to use.
  3. 3.
    Add a never list: config files like appsettings.json, connection strings, git add -A.

Every few weeks, ask Claude

prompt
Check CLAUDE.md against the current code. List what's out of date or missing, then fix it.

Step 2: The work item is the spec

Write what's broken and what should happen. Describe the behavior, not the implementation. Claude knows your code base. Keep it short: the description gets cut off at 1,000 characters. Big job? Split it into several items.

What most backlogs look like

Title:
Fix the export button
Description:
It doesn't work sometimes. Make it work.
Tags:
(none)

Claude-ready

Title:
CSV export returns a 500 when a report has more than 10,000 rows
Description:
Large reports should export and download like small ones.
Tags:
claude-ready

The tag is the on switch. Nothing gets picked up unless you tag it claude-ready.

Save this query (Boards → Queries → New query → Editor)

WIQL
SELECT [System.Id], [System.Title], [System.State]
FROM WorkItems
WHERE [System.Tags] CONTAINS 'claude-ready'
  AND [System.AreaPath] UNDER '<Your Project>'
  AND [System.State] <> 'Removed'
  AND [System.State] <> 'Closed'
ORDER BY [Microsoft.VSTS.Common.Priority] ASC

Why one item a night

Several AI branches off the same main means merge conflicts in the morning. And you stay the gate. Review and merge before the next one starts.

Step 3: A PAT (Personal Access Token)

A PAT is a password for a script. It lets the pipeline act as you in Azure DevOps.

  • Where: Azure DevOps → User settings (top right) → Personal access tokens → New Token
  • Scopes: Code (Read & write) and Work Items (Read & write)
  • It expires. Put the expiry date on your calendar. Mine expired once and the nightly runs failed quietly.

Step 4: Key Vault, where the keys live

Never put keys in the repo or the YAML.

  1. 1.
    In Azure Key Vault, add two secrets: AnthropicApiKey and AzureDevOpsPat.
  2. 2.
    In Azure DevOps → Project settings → Service connections, create (or reuse) an Azure Resource Manager connection.
  3. 3.
    Give that connection's identity permission to read secrets on the vault: Get + List (access policy) or the "Key Vault Secrets User" role (RBAC).
  4. 4.
    Add this as the first step of the nightly stage:
    yaml
    - task: AzureKeyVault@2
      inputs:
        azureSubscription: '<your service connection>'
        KeyVaultName: '<your key vault>'
        SecretsFilter: 'AnthropicApiKey,AzureDevOpsPat'

No Key Vault?

Pipeline → Edit → Variables → add both as secret variables. It works the same way.

Cost

The pipeline uses an Anthropic API key, which bills per token, separately from your Claude subscription. (claude setup-token can bill your Pro/Max plan instead.) Set a spend limit and low-balance alerts at platform.claude.com. One complicated item can eat a lot of credits overnight.

Step 5: Have Claude Code write the nightly stage

Don't write the YAML yourself. Paste this into Claude Code in your repo:

prompt
Add a stage to azure-pipelines.yml that runs Claude Code on our Azure DevOps work items overnight.
- Runs on a schedule at 2 AM Eastern, Monday-Friday, and when I click Run. Never on a code push.
- Pulls AnthropicApiKey and AzureDevOpsPat from our Key Vault through the existing service connection.
- Installs Claude Code, sets a git identity of "Claude (Automated)", and uses the PAT to push branches.
- Takes ONE work item tagged claude-ready, implements it, runs dotnet build and dotnet test, and
  opens a PR. If anything fails: no PR, tag it claude-blocked.
- Hard time limit of 90 minutes.
Before you build anything, ask me five questions about what I'm about to build.

What you should get looks roughly like this:

yaml
schedules:
  - cron: '0 7 * * 1-5'        # cron is UTC: 07:00 UTC = 2 AM Eastern (standard time)
    displayName: 'Nightly Claude Development'
    branches: { include: [ main ] }
    always: true

- stage: ClaudeDevelopment
  dependsOn: []
  condition: or(eq(variables['Build.Reason'], 'Schedule'),
                eq(variables['Build.Reason'], 'Manual'))
  jobs:
  - job: ClaudeImplementation
    timeoutInMinutes: 120

The condition is what keeps Claude out of your normal CI. A regular push builds and deploys. It never wakes Claude up.

Step 6: The command and the standing prompt

You don't run this yourself. Claude Code wrote it into the nightly stage in Step 5. This is what's inside the step named "Claude autonomous development": one claude -p command, and the prompt it runs is the text inside the quotes.

The one command

bash
claude -p '
You are working autonomously on <Project>.
Build: dotnet build <Solution>.sln -c Release
Test:  dotnet test <TestProject>

1. Query Azure DevOps for work items tagged claude-ready (Azure DevOps MCP server).
2. For the top item: read it, implement it, build and test. If both pass, branch
   claude/workitem-{id}, commit, push, and open a PR. Swap claude-ready for
   claude-implemented and comment on the item with a summary.
3. If it fails: comment why and tag claude-blocked. No PR.
4. Maximum work items to process: 1 per run.

Do not ask questions. Follow the patterns in CLAUDE.md.
Do NOT modify appsettings.json or connection strings. Never git add -A.
' \
  --dangerously-skip-permissions \
  --no-session-persistence \
  --verbose \
  --max-turns 200
-p
Run once and exit. No chat window. Prompt in, work done, quit.
--dangerously-skip-permissions
Don't stop to ask “can I run this?” Nobody's awake to click Yes.
--max-turns 200
A ceiling on how many steps it takes before it has to stop.
--no-session-persistence
Don't save the conversation. Every night starts clean.

Everything in this step, including the prompt, is in the YAML that Step 5 generated. To change the rules, change the YAML.

Which model?

Nothing in the command sets a model, so Claude Code uses its current default. To pin one, add --model sonnet (or --model opus) to the claude -p line. Use an alias, not a dated model name: dated names get retired and the nightly stops with a 404.

Why skipping permissions is OK here

The run happens on a throwaway Microsoft-hosted agent with two secrets, and nothing reaches main until you merge. On a team or a self-hosted agent, use --allowedTools with an explicit list instead.

The safety net

Claude may only open a PR if dotnet build and dotnet test both pass. For UI checks, add Playwright for .NET (the Microsoft.Playwright NuGet package). The tests are written in C#, run inside dotnet test, and the same gate covers them.

playwright.dev/dotnet

Run it

  1. 1.
    Pipelines → your pipeline → Run pipeline → main → Run
  2. 2.
    Open the run → the Claude stage → the job → the Claude step, and watch the log
  3. 3.
    Tonight the schedule does it for you

The morning review checklist

  • Open the PR: linked work item, Claude's summary comment, files changed. Is it the right size for the ask?
  • Pull the branch and run it locally
  • Test it: click through the feature like a user would
  • Read the diff. Would you have written it this way? Watch config and secrets. Push back if it over-engineered.
  • Merge, or improve the work item and re-tag it

The guardrails

  • Opt-in tag: only items tagged claude-ready
  • One item a night
  • Hard limits: 90-minute timeout, 200 turns
  • You merge. It can open a PR; only you merge, and merging is what deploys. (Teams: require a reviewer on main with a branch policy.)

What went wrong (so it doesn't happen to you)

  • A model got retired. The model my pipeline named started returning 404s. Watch the retirement notices. The fix: pin an alias like --model sonnet instead of a dated model name (see "Which model?" in Step 6).
  • The PAT expired. Calendar reminder, and rotate it before it expires.
  • The overnight bill. One complicated item burned through my credits. Set spend alerts and keep items small.
  • Overlapping work. Several items at once means branches that conflict. One a night.

Docs worth bookmarking

Slides

Slides (PDF) will be posted here after the session.

How to reach me

Working on something like this? Let's talk.

Start a conversation