DEV Community

Cover image for The Setup Is the Strategy: How I Orchestrated a Product Migration with Claude Code

The Setup Is the Strategy: How I Orchestrated a Product Migration with Claude Code

Most engineers using Claude Code are getting a fraction of its value. Not because the tool isn't capable — but because they're using it out of the box, unconfigured, the way you'd use a new IDE without installing extensions or setting up your build system. The default experience is decent. The configured experience is transformative.

I'm a Senior Software Engineering Manager leading a team focused on leveraging AI to find acceleration opportunities across the software development lifecycle. I've been playing around with AI tooling for a while and could see its potential, so I proposed a proof of concept: take a real product migration — the kind of project that would normally require a team of engineers across multiple sprints — and attempt it solo, using Claude Code as my primary development platform. Not "AI-assisted development" An AI-first model where every phase of the SDLC runs through Claude Code's feature set.

The migration itself was substantial:

  • 4 legacy repositories consolidated into 2,
  • a database migration from MySQL to PostgreSQL,
  • framework upgrades across the full stack (Spring Boot 2 to 3, Java 17 to 21, React 17 to 18),
  • an authentication model replacement,
  • and complete test suites for everything.

What made this work wasn't Claude Code itself. It was how I set it up.

The skills that made me effective at leading engineering teams — providing clear context, delegating with specificity, reviewing rigorously, building repeatable processes — turned out to be exactly the skills that make Claude Code most effective. Engineers whose day-to-day revolves around writing code by hand sometimes struggle with this shift because the instinct is to do the work yourself, not to set up the system and direct it. I'd spent years not writing the code myself. I was already an orchestrator. The medium changed, the model didn't.

This post walks through how I configured Claude Code for a real migration, organized as building blocks. Each layer depends on the one below it. Skip the foundation and the rest falls apart.

Building blocks of an AI-first migration


Building Block 1: Planning — Laying the Foundation

Before any code was written, I built the context and planning infrastructure. This is the layer most people skip, and it's the layer that matters most.

CLAUDE.md — The Master Context

Claude Code reads CLAUDE.md files on every session start. They're your project memory — the equivalent of onboarding documentation for a new team member. I built a multi-level hierarchy:

  • Workspace-level (181 lines): overview of all 25+ repositories, tech stack summary, cross-service architecture, shared build commands
  • Domain-level: 18-service catalog, glossary of domain terms, JWT authentication architecture, service communication patterns
  • Per-repo: service-specific conventions, module structure, testing standards, local dev setup

Each level inherits from its parent. When Claude Code opens a session in any repo, it automatically has the full context stack — from the broadest architectural view down to the specific service conventions.

This is the single highest-leverage thing you can configure. A well-written CLAUDE.md prevents Claude from re-exploring your codebase every session, asking questions you've already answered, or making assumptions that contradict your architecture. It's free, it's immediate, and it compounds over time.

CLAUDE.md hierarchy — workspace, domain, and repo levels

The Memory System

Claude Code has a persistent memory system — files that survive across sessions. I built 17 memory files organized by type:

  • User: who I am, my role, what I'm working on
  • Feedback: corrections that become permanent rules
  • Project: active work context, ticket maps, architectural decisions
  • Reference: pointers to external systems (Confluence pages, Jira boards, SonarQube dashboards)

The feedback memories are the most powerful. Every time I corrected Claude — "don't amend commits, it breaks CI and MR reviews" or "always fix all test failures before committing, even seemingly pre-existing ones" or "copy application-local.yml to worktrees because it's gitignored" — that correction became a permanent rule. One-time mistakes became permanent automation. After a few weeks, the memory system had captured dozens of workflow-specific rules that would take a new team member months to internalize.

The Context Funnel

For the planning phase itself, I fed Claude Code everything it would need to design the migration:

  • The four legacy repositories (full source access)
  • Dev database connections (read-only) to both MySQL and PostgreSQL
  • A reference implementation — a similar product that had already been migrated to the platform
  • Live Swagger documentation from upstream services (router, rostering, authentication APIs)

With this context loaded, I used the brainstorming skill (from the superpowers plugin) to generate the migration design across all eight repositories simultaneously. The skill enforces a structured process: explore context, ask clarifying questions, propose approaches with trade-offs, present the design for approval, then write a spec document.

I also used agent teams — an experimental Claude Code feature that runs parallel reviewers with independent context windows — to stress-test the design. Three independent agents reviewed the same architecture and caught issues a single pass missed:

  • Missing resume logic for interrupted user flows (a legacy endpoint had been removed without accounting for in-progress sessions)
  • Frontend state invalidation gaps in the data fetching layer
  • Unnecessary network hops that could be eliminated now that previously separate services lived in the same JVM

Giving AI direct database access allowed exact column-by-column mapping between the legacy and target schemas. It caught DDL mismatches — timestamp type differences, nullable column discrepancies, default value conflicts — that ORM annotations hide. Without this, the migration would have hit runtime errors that are painful to debug after the fact.

The context funnel — from raw inputs to structured outputs

Atlassian MCP + Custom Jira Skill — From Design to Tickets

This is where the Atlassian MCP enters the story. It connects Claude Code directly to Jira and Confluence — no browser, no context switching.

First, the design became documentation: 20+ Confluence pages generated directly from Claude Code via MCP. Design documents, use case specifications, system architecture diagrams — all created and published without leaving the terminal. That said, this is where I hit my first major failure. The Atlassian MCP's updateConfluencePage tool silently truncates content beyond ~5KB. I asked Claude to update two design documents — 37KB and 46KB — and both were overwritten with partial content. I had to manually restore them from Confluence's page history. The data loss was real. I immediately encoded a memory rule: never update large Confluence pages via MCP, only add comments. Lesson learned the hard way.

Then came the decomposition. This was one of the most powerful things I did: I tasked Claude with breaking the architecture into Jira tickets scoped for three constraints:

  • Reviewable code reviews: no 2,000-line merge requests that reviewers rubber-stamp. Each ticket's scope had to produce a merge request a human could meaningfully assess.
  • QA throughput: QA can't test a monolithic "migrate everything" ticket. Each ticket needed to be independently testable with clear acceptance criteria.
  • Parallel development: tickets needed clean boundaries so multiple could be in-flight simultaneously without merge conflicts.

The result: 19 Jira tickets created in a single session from the design docs. Each with acceptance criteria in Atlassian Document Format, story points, sprint assignment, and a parent epic link. But it couldn't link them — the MCP tool for creating issue links between tickets throws a "not found" error. I had to go into Jira manually and add the "is blocked by" relationships myself. Not everything is automatable yet.

The Jira API has other quirks that would bite you every session without the right setup. So I built the my-jira skill — a custom skill file that encodes all the workarounds:

  • createJiraIssue renders newlines as literal \n text. The skill enforces a follow-up editJiraIssue call to fix formatting.
  • Story points live in customfield_10058, not the obvious-looking field. The wrong field silently saves to the wrong place — you'd never know until someone checks the sprint board.
  • QA testing note templates, project constants, sprint IDs, assignee account IDs — all encoded in one place.

One skill file eliminated an entire class of silent failures.


Building Block 2: Execution — The Development Loop

With the plan in place and tickets created, execution begins. Each ticket follows the same cycle: design doc, plan doc, execute, review, iterate, merge, move to QA. The tools enter the story as the workflow demands them.

The per-ticket execution loop

Per-Ticket Planning

Every ticket — no matter how small — gets two documents before any code is written:

  1. Design doc (what + why): the problem being solved, the approach, the constraints
  2. Plan doc (how + steps): every file to change, every migration rule, every commit interval

I review the plan before execution starts. This is the gate. The AI generates, I validate. I know the domain, the constraints, the edge cases that don't show up in code. This is where the orchestrator model is most visible: I'm not writing plans by hand, but I'm reading every one and catching the things that only domain knowledge reveals.

Worktrees — Parallel Execution

Each ticket executes in a dedicated git worktree. Claude Code's /execute-plan skill runs the plan step-by-step in an isolated working directory.

At peak, I had 8 active worktrees across 2 repositories — 4 tickets developed concurrently. The tickets depended on each other, but the worktree model let me develop them in parallel and rebase with --onto as dependencies merged upstream. All four hit QA in the same sprint.

The practical limit: about 4 active Claude Code sessions at a time, depending on how many contexts you can keep in your head. You're reviewing output from multiple streams, making judgment calls, and keeping the overall architecture coherent. It's project management, not coding.

8 worktrees, 2 repos, 4 tickets shipping in parallel

GitLab CLI + The manage-mr Skill

Merge requests aren't just git push. There's the strategy description, the pipeline to monitor, quality gates to check, and the fix-push-recheck cycle when something fails.

The manage-mr skill wraps the full lifecycle:

  1. Create the MR with a description derived from the plan doc
  2. Monitor the CI pipeline with /loop on a recurring interval
  3. Check SonarQube quality gates
  4. If anything fails: read the failure, trace to source, fix, re-push

The /loop skill deserves its own mention. It runs a command on a configurable interval — I used it to poll CI pipelines. Pipeline fails? Claude reads the build log, traces the error to the source file, applies a fix, pushes, and the loop continues. No browser, no manual checking.

One recurring failure pattern worth mentioning: AI would sometimes aggressively remove "unused" state variables without checking the callbacks that referenced them, breaking CI. It also missed secondary integration tests that asserted on the removed behavior. The fix was straightforward each time, but the pattern recurred enough that I added a memory rule: "verify all references before removing anything." The pipeline loop caught these quickly, but they shouldn't have happened in the first place.

SonarQube MCP

Connected via MCP server, Claude can query pull request issues, check quality gates, and fix vulnerabilities directly from the terminal. The migration shipped with 95%+ API coverage, 91% frontend coverage, zero bugs, zero vulnerabilities, and zero security hotspots at the time of QA handoff.

Chrome DevTools MCP

For frontend work, Claude needs to see the actual rendered application — not just the code. The Chrome DevTools MCP connects Claude to a live browser session. I log in, navigate to the page, and Claude inspects the live DOM, console errors, and network requests.

This is a game-changer for UI work. It finds CSS/layout bugs, missing state updates, and rendering issues that code-level analysis and screenshots could never surface. Claude can see what the user sees.

Figma MCP

During frontend porting, Claude references Figma designs directly via MCP. No screenshotting, no describing layouts in words. It reads the design context — component structure, spacing, colors, typography — and translates to code. This kept the ported UI faithful to the design without the constant back-and-forth of "does this match the mockup?"

Postman MCP

The API collection stays in sync with endpoint changes. Test scripts auto-chain with dynamic JWT extraction. This matters because QA depends on Postman to validate the API — if the collection is stale, they're blocked. The MCP integration ensures the collection reflects the latest API state at all times.

The move-to-qa Skill

When a ticket is ready for QA, there's a ritual: add structured testing notes (environment, credentials, test steps, caveats), transition the ticket to the QA column, notify the QA channel. Getting any step wrong means the QA engineer wastes time asking clarifying questions.

The move-to-qa skill encodes the entire handoff as a single invocation. One command handles the comment (in the exact template QA expects), the Jira transition, and the notification. Consistent handoff, every time, no steps skipped.

Keeping Everything in Sync

Here's where the orchestration model really pays off. When implementation changes a design decision or uncovers a requirement gap, Claude updates Confluence and Jira in the same session — with the caveat that large page edits go through comments, not full page updates (see the Confluence truncation lesson above). The old friction — finish code, open browser, update Jira, update Confluence — is the kind of manual chore that developers frequently skip. Now it's one prompt: "Update the design doc to reflect that we're using a materialized view instead of a join, and comment the change on the Jira ticket."

Documentation stays in sync because it's part of the workflow, not an afterthought.

The MCP ecosystem — every system connected to one terminal


Building Block 3: Review & Iteration

Code Review Plugins

The code-review and pr-review-toolkit plugins run multi-agent PR reviews with confidence-based scoring. They're effective as a first-pass filter:

  • Caught syntax and formatting bugs
  • Off-by-one errors in date filters
  • Missing transactional annotations
  • Raw data leakage in error responses

AI caught roughly 30-40% of issues — the low-to-mid-level stuff that humans miss under time pressure.

But the high-level stuff still needed a human reviewer: permission architecture that needed refactoring, structural design decisions for domain enums, Java stream filtering optimizations, missing API documentation annotations. These aren't bugs — they're design-level improvements that require understanding the system's intent, not just its syntax. AI review is a floor-raiser, not a ceiling-raiser. It catches what slips through, but it doesn't replace architectural judgment.

AI vs Human review — complementary, not competing

Responding to Review Comments

When human reviewers leave comments on merge requests, Claude reads and responds via the GitLab integration. Implement the requested changes, push, and the review loop continues — all from the terminal. The reviewer doesn't know or care that the fixes were AI-assisted. They just see responsive, well-reasoned changes.


The Cost

Honest accounting matters. Over the course of the migration — roughly 15 work days from planning through QA handoff — I spent close to $5,000 in API token costs running Claude Code through AWS Bedrock.

For a migration of this scope — four repos, database migration, full-stack framework upgrades, auth model replacement, ~50 tickets, ~580 tests — that's a fraction of what the engineering time alone would cost with a traditional team across multiple sprints.

Lessons learned on cost management:

  • Clear your context frequently. This is the single biggest cost lever. Claude Code caches your conversation context and re-reads it on every turn. Long marathon sessions accumulate enormous cache read and cache write charges that dwarf the actual input/output token costs. Use /compact aggressively, and prefer multiple shorter focused sessions over all-day marathons.
  • Use the right model for the job. Opus for planning, architecture, and complex reasoning. Sonnet for routine execution, test generation, and boilerplate. Haiku for quick lookups. The cost difference between models is significant and most execution work doesn't need the most powerful model.
  • The cost is front-loaded. The initial setup — CLAUDE.md files, skills, MCPs, memory rules, the design phase — was the most token-intensive period. Once configured, subsequent tickets were dramatically cheaper because the context was already built and the workflows were encoded.

Closing

By the end of the POC, the migration had produced roughly 50 tickets, 580 passing tests, 95%+ API coverage, and zero bugs, vulnerabilities, or security hotspots at QA handoff. One engineer, half a month, one tool — configured deliberately for every phase of the work.

The throughput increase didn't come from AI writing better code. It came from iterating faster, verifying more thoroughly, and managing parallel execution streams.

The building blocks made this possible:

The building blocks — planning, execution, review

  • Planning: CLAUDE.md gave the AI context. Memory gave it institutional knowledge. The brainstorming skill gave it structure. The Atlassian MCP and custom Jira skill turned designs into documentation and actionable, well-scoped tickets.
  • Execution: worktrees enabled parallel development. Skills encoded repeatable workflows. MCPs connected Claude Code to every system in the SDLC — version control, CI/CD, code quality, design tools, project management, documentation.
  • Review: plugins raised the floor on code review quality. Human reviewers caught the architectural and design-level issues that AI can't.

Each layer depends on the one below it. Skip the foundation — the CLAUDE.md files, the memory, the skills — and the execution layer produces mediocre results. That's what most people experience. They skip straight to "write me some code" without investing in the setup, get underwhelming output, and conclude the tool isn't useful.

The setup is the strategy.

If you're starting from zero, here's my recommendation: write your CLAUDE.md first. Just the basics — tech stack, project structure, build commands, conventions. Then add one MCP integration for the system you context-switch to most often (probably your issue tracker). Then build one custom skill for your most repeated workflow. Build up from there. Each layer makes the next one more effective.

Top comments (1)

Collapse
 
automate-archit profile image
Archit Mittal

The CLAUDE.md as master context is the single highest-leverage thing most people miss with Claude Code. I've found that spending 30 minutes writing a detailed CLAUDE.md saves hours of re-explaining context across sessions. The memory system layering is smart too — I use a similar approach where I keep a decisions.md that logs every architectural choice with reasoning, so when Claude suggests something that contradicts a previous decision, the context file catches the conflict before it becomes a bug. The Atlassian MCP integration for auto-generating Jira tickets from design specs is the kind of workflow that makes AI tooling genuinely transformative rather than just convenient.