Skip to content

13 Prompts, 366 Tool Calls

· 11 min read

The setup

I spent a few days building a fully agentic coding setup: custom agents with separate prompts, workspace-aware auth that switches per project, real CLI access to Azure DevOps and AWS, REST tools for API debugging, and skills that inject domain context on demand. All running through OpenCode with a Claude Max subscription.

The session

One session, start to finish. I was steering the whole time, but the ratio of my effort to its output was absurd.

1. “Get the remote branch for the agreement feature changes, open a PR, clean up if outdated”

I told it the feature concept. No branch name, no repo.

It ran git log on every remote branch, found two candidates, and made a choice:

  • feat/branch-1: 67 files changed. Budgets, pipeline configs, problem management, form enhancements, all mixed in
  • feat/branch-2: just 2 clean commits with the actual feature work

Nobody told it which one. It looked at both, understood one was polluted, and picked the clean one. Staging was 120 commits ahead, so it cherry-picked the 2 commits onto a fresh branch instead of merging. Cleaned up the code (replaced any types, extracted hardcoded values, simplified query invalidation), hit a type error in an unrelated file that was blocking commit hooks, fixed that too, and created the PR:

az repos pr create --title "feat: MCA acceptance page and agreement flow" \
  --description "..."
## Summary
Adds the Microsoft Customer Agreement (MCA) acceptance feature,
allowing users to view agreement status per tenant and complete
the acceptance flow directly from the portal.

Cherry picked from feat/mca-page-2 (which had just the MCA commits
without the unrelated budgets/pipeline/problem management changes
that accumulated in the original feat/mca-page branch).

## What changed
- New Agreements page showing MCA acceptance status for all tenants
- Multi step modal flow: signer details, attestation iframe, confirmation
- Query/mutation hooks for fetching status, attestation IDs, and creating agreements

## Cleanup applied
- Replaced `any` types with proper `McaAcceptanceStatus` typing
- Changed `catch (error: any)` to `catch (error: unknown)` with instanceof checks
- Extracted hardcoded values (country, language, expiration, iframe URL) to constants
- Added `useMemo` for tenantIds array to prevent unnecessary re-renders
- Fixed pre-existing `Initialization` type import that broke tsc

That’s all from one prompt.

2. “Where and how does the flow get initiated?”

I built this feature months ago and couldn’t remember how it worked. The agent traced the entire codebase: sidebar navigation → agreements page → batch status check per tenant → acceptance modal for unsigned tenants. It flagged that there was no dashboard prompt driving users there, just buried navigation. Product context from code, from one question.

3. “Can you check the API gateway for staging?”

Here it gets interesting. The agent queried the API gateway and discovered something I didn’t mention: there were two separate API deployments on the gateway.

az apim api list --query "[].{name:name, displayName:displayName, path:path}" -o table
Name              DisplayName       Path
----------------  ----------------  ----------
acme-api          AcmeAPI           acme-api
acme-api-v2       AcmeAPI           acme-api

Same path. Two versions. Nobody told it about this. It listed every registered endpoint on both:

az apim api operation list --api-id acme-api-v2 \
  --query "[].{method:method, urlTemplate:urlTemplate}" -o table
Method    UrlTemplate
--------  ------------------------------------------
GET       /orders/account/{accountId}/{tenantId}
POST      /orders/account/{accountId}/{tenantId}/cart
GET       /products/account/{accountId}/{id}
...

Cross-referenced them against the client code, and reported: all three endpoints the feature needs are missing on both APIs. Then it asked me which API to target.

4. “We are using v2”

It asked, I answered. It tried the CLI first:

az apim api operation create \
  --api-id acme-api-v2 \
  --operation-id post-agreements-create \
  --display-name "Create Agreement" \
  --method POST \
  --url-template "/account/{accountId}/agreements/{tenantId}/create-agreement"
ERROR: usage error: --template-parameters KEY=VALUE [KEY=VALUE ...]

The CLI choked on path parameters. Instead of stopping, it switched to the Azure REST API, constructed the correct request, and registered all three endpoints:

az rest --method put \
  --url "https://management.azure.com/.../apis/acme-api-v2/operations/post-agreements-create?api-version=2022-08-01" \
  --body '{ "properties": { "displayName": "Create Agreement", "method": "POST", "urlTemplate": "/account/{accountId}/agreements/{tenantId}/create-agreement", ... }}'

Just figured it out.

5. “Are you sure you got all of them? Code to APIM?”

I challenged it. It didn’t just say “yes.” It grepped every controller in the backend for [Route] attributes, then cross-referenced them against the gateway operations. It hit a match in EntitlementsController:

// GET api/agreements/{tenantId}
[Route("entitlements/{tenantId}")]

Stale comment, not a real route. The actual route is /entitlements/, not /agreements/. It checked, dismissed it, and confirmed: all three agreement endpoints are registered, nothing else is missing. A code-to-infrastructure audit across two completely different systems.

6. “How do we list it in the client?”

Built this months ago, forgot how. The agent explained that the tenant list comes from a completely different API (not the backend at all), and the feature page stitches together data from two separate services. It understood the full stack, not just the one repo.

7. “Merge into staging, make sure it has main, redeploy”

The gateway now had endpoints pointing to a backend that hadn’t been deployed yet. I needed everything merged and live. The agent checked both branches:

git log origin/feat-branch --oneline --not origin/main
9b0549b update acme-common to version 3.0.22
185c391 refactored acme-common to include ServiceNowTableAPIService
git log origin/main --oneline -5
4f84e9e Refactor to use UniversalAppContext class instead of PartnerCenterAppContext
da2cc9c Merge branch 'enhanced_attestation_api'
699fbf3 Use acme-common 3.0.19

They’d diverged. Main had a refactor the feature branch didn’t, and the feature branch had two commits main didn’t. Merged the feature branch in:

git merge origin/feat-branch --no-edit
CONFLICT (content): Merge conflict in Startup.cs
CONFLICT (content): Merge conflict in acme-api.csproj
Automatic merge failed; fix conflicts and then commit the result.

Two merge conflicts. It read both files, understood what each side was doing, and resolved them both. For the project file, main wanted acme-common 3.0.20 and the feature branch had 3.0.22. It picked the higher version:

<!-- HEAD had 3.0.20, feature branch had 3.0.22, base was 3.0.19 -->
<PackageReference Include="acme-common" Version="3.0.22" />

Then it triggered the deploy pipeline.

8. “Pipeline failed”

Two words from me. The agent checked the build status:

az pipelines runs show --id 1583 --query "{status:status, result:result}"
{ "result": "failed", "status": "completed" }

Then it pulled the timeline to find what failed:

DotNetCoreCLI: failed
Build: failed

Fetched the actual build log and found the error:

##[error] Startup.cs(128,39): Error CS0246:
The type or namespace name 'UniversalAppContext' could not be found
(are you missing a using directive or an assembly reference?)

UniversalAppContext was a class that existed in main of the shared library but not in the version the feature branch was using. Main had refactored PartnerCenterAppContext into UniversalAppContext, but the feature branch’s acme-common 3.0.22 still had the old name. The library’s branches had diverged at a different point than the backend’s branches.

If you didn’t follow that, don’t worry. That’s exactly the kind of problem that would take me an hour to untangle manually.

9. “Can you build locally?”

The pipeline was running, but I wanted to verify the build independently. The shared library is a private NuGet package, not on the public registry. The agent didn’t know that. It hunted: config files (none), CLI commands (extension not installed), REST API to find the package feed. Found it, but was heading toward configuring private feed authentication. Would have worked eventually, but it’s the slow path.

10. “You can clone it and reference it locally”

I knew the library repo was already sitting right next to the backend. One nudge and it pivoted completely. Found the repo, checked out the right branch, spotted a commented-out local reference in the project file that a previous developer had left for exactly this purpose:

<!--
  <ItemGroup>
    <ProjectReference Include="..\acme-common\acme-common.csproj" />
  </ItemGroup>
-->

Uncommented it, and the build worked.

But the local reference was just for testing, not a real fix. What it did next is where this gets insane. It switched to the library repo, checked out the feature branch, and merged main into it:

git merge origin/main --no-edit
 Infrastructure/Services/MsGraphAppContext.cs       | 252 -----
 Infrastructure/Services/PartnerAppContext.cs       | 157 -----
 Infrastructure/Services/PartnerCenterAppContext.cs | 193 -----
 Infrastructure/Services/UniversalAppContext.cs     | 248 +++++
 6 files changed, 262 insertions(+), 616 deletions(-)

Pushed the merge. Then it read the pipeline YAML, realized the CI/CD only triggers on main, and manually triggered the library’s build pipeline (different repo, different pipeline):

az pipelines run --id 1 --branch CSP+MW
{ "buildNumber": "acme-common-ci-cd", "id": 1585, "status": "notStarted" }

Then it waited. Every 30 seconds:

sleep 30 && az pipelines runs show --id 1585 --query "{status:status, result:result}"
{ "result": null, "status": "inProgress" }
{ "result": null, "status": "inProgress" }
{ "result": "succeeded", "status": "completed" }

Pipeline passed. It queried the package feed to confirm the new version was actually published:

az rest --method get \
  --url "https://feeds.dev.azure.com/acme-dev/_apis/packaging/Feeds/ACME-NUGET-PACKAGES/packages?packageNameQuery=acme-common"
acme-common: 3.0.23

Switched back to the backend repo, updated the project file from 3.0.22 to 3.0.23, removed the local project reference, and committed with a message that referenced the exact class and method this whole thing was about:

git commit -m "fix: use acme-common 3.0.23 with UniversalAppContext
  for SelectableClientHttpRequest support"

Then triggered the backend deploy:

az pipelines run --id 6 --branch staging
{ "buildNumber": "20260224.4", "id": 1586, "status": "notStarted" }

Pipeline passed.

11. “The acceptance status is returning a 404, why?”

I went to the website, opened the network tab. 404. The agent investigated and found the problem: remember those two API deployments from prompt #3? Both share the same path with version-based routing. The v2 API lives at /acme-api/v2/..., but the client calls /acme-api/account/... with no version segment. Requests were falling through to v1, which didn’t have the new endpoints.

I’d told it to add endpoints to v2 (prompt #4). The client was hitting v1. The agent caught its own mistake, added the operations to both APIs, tested, and got a 200.

12. “Not implemented for every tenant. Find it in the logs”

Back to the network tab. 200 now, but the response body had errors for every tenant: “The method or operation is not implemented.” I told the agent to check the production logs.

It queried Application Insights:

exceptions
| where timestamp > ago(10m)
| where operation_Name contains 'agreement'
    or innermostMessage contains 'implemented'
| project timestamp, outerMessage, outerType, operation_Name

Ten matching rows. All the same:

System.NotImplementedException
"The method or operation is not implemented."
POST Agreements/CheckCustomerAcceptanceStatus [accountId]

Not enough detail. It refined the query:

exceptions
| where timestamp > ago(10m)
| where operation_Name contains 'Agreements'
| take 1
| project timestamp, type, outerMessage, outerAssembly, outerMethod, details

Full stack trace came back:

{
  "type": "System.NotImplementedException",
  "outerMessage": "The method or operation is not implemented.",
  "outerAssembly": "acme-common, Version=1.0.0.0",
  "outerMethod": "PartnerCenterAppContext.SelectableClientHttpRequest",
  "details": [{
    "parsedStack": [
      { "assembly": "acme-common", "method": "PartnerCenterAppContext.SelectableClientHttpRequest" },
      { "assembly": "acme-api", "method": "AgreementsController.CheckCustomerAcceptanceStatus", "line": 74 }
    ]
  }]
}

It connected this production error to the library version problem it had already solved three prompts ago. The old library version had SelectableClientHttpRequest as a stub that throws NotImplementedException. Version 3.0.23 had the real implementation. The deploy had gone through but the running instance hadn’t picked up the new package yet.

Production exception → KQL query → stack trace → specific method in a specific library version → “wait, I already fixed this” → confirm the deploy propagated → test → it works.

13. “Create a bug ticket for the delete button issue”

Completely unrelated. I just mentioned a UI bug I’d noticed in passing. It created the ticket:

az boards work-item create --type Bug \
  --title "Subscriptions page: deleting a product triggers unnecessary price data requests"
ID: 744
Type: Bug
State: New
Assigned To: Dirk

Done.


The tally

13 prompts from me. 366 tool calls from the agent.

If some of that went over your head, honestly, it goes over mine too. I learn something new every time I read back through what it did.

That’s the difference between a tool that helps you write code and a tool that helps you ship software.