A New Collection of Thoughtful Learning Apps — Now Available on iOS & Android

Image
I’m excited to share a set of mobile apps I’ve recently completed and published on both the Google Play Store and the Apple App Store. These apps are designed with a simple goal in mind: to make meaningful, structured content more accessible, whether you’re studying theology or improving your English vocabulary. 📱 Now Available on Both Platforms All apps are live and available for download: Google Play Developer Page: https://play.google.com/store/apps/dev?id=5835943159853189043 Apple App Store Developer Page: https://apps.apple.com/ca/developer/q-z-l-corp/id1888794100 📖 Theology & Confession Study Apps For those interested in Reformed theology and classical Christian teachings, I’ve developed a series of apps that present foundational texts in a clean, focused reading format: The Belgic Confession Canons of Dort Heidelberg Catechism Westminster Shorter Catechism Each app is designed to provide a distraction-free experience, making it easier to read, reflect, and revisit these im...

Building a GitHub Copilot Skill for Spring Boot Modernization at Scale

Building a GitHub Copilot Skill for Spring Boot Modernization at Scale



What starts as a simple prompt for one application quickly becomes an engineering process problem at scale. This post shares the design principles behind a reusable GitHub Copilot skill that standardized Spring Boot upgrades across dozens of services while reducing manual effort and review overhead.


The Real Challenge of Framework Modernization

Upgrading a single Spring Boot application is usually straightforward.

An experienced engineer can handcraft a prompt, point GitHub Copilot at a repository, review a few changes, and work through the upgrade. The challenge isn't upgrading one application. The challenge is upgrading the next ten, twenty, or forty applications with the same level of quality, consistency, and safety.

That is where a reusable GitHub Copilot Skill becomes valuable.

Rather than relying on engineers to repeatedly write the "perfect upgrade prompt," a skill encodes the entire modernization process once and applies it consistently across every repository. It transforms tribal knowledge, hard-earned lessons, and best practices into a repeatable workflow.

In our case, that approach helped modernize 42 Spring Boot applications in a single week, with upgrade pull requests generated automatically across the portfolio.

The key lesson was simple:

The value of a skill is not that it is smarter than an LLM. The value is that it enforces the same disciplined process every single time.


Why a Skill Instead of a Prompt?

Large language models are exceptionally capable at code transformations, including application upgrades. However, free-form prompting introduces variability.

Different engineers will:

  • Ask the problem differently
  • Skip important verification steps
  • Forget framework-specific breaking changes
  • Use inconsistent reporting formats
  • Apply different levels of risk mitigation

Over time, this creates operational inconsistency.

A skill addresses this by introducing structure:

Deterministic Detection

The skill uses scripts instead of model reasoning to determine:

  • Current Spring Boot version
  • Java baseline
  • Build system
  • Dependency management strategy
  • Module layout

No guessing. No assumptions.

Mandatory Planning

The upgrade approach is generated and reviewed before any code modifications occur.

Framework-Specific Knowledge

Known migration issues and breaking changes are maintained centrally and reused across every future upgrade.

Consistent Deliverables

Every modernization produces the same report structure, making pull requests easier to review and audit.

Safety Gates

The skill can prevent unsafe actions, such as skipping major version transitions or proceeding without determining the correct target version.


The Evolution of the Skill

The first iteration was underwhelming.

Like many initial automation attempts, it focused primarily on:

  • Detecting the current version
  • Running a build
  • Reporting project health

That was useful, but it was not modernization.

Real modernization requires more than validating that an application compiles. It requires understanding:

  • What the latest supported version actually is
  • What breaking changes exist between releases
  • Which dependencies can be removed
  • Which dependencies must be updated
  • Which code patterns need migration

Only after adding those checks did the skill begin creating meaningful business value.


The Seven-Step Upgrade Process

The design eventually converged on a seven-step workflow with two non-negotiable safety gates.

The exact implementation may vary by organization, but the engineering principles remain broadly applicable.


Step 1: Establish the Baseline

Before any decision can be made, the skill must determine the project's current state.

This information should come from a detection script rather than the LLM itself.

For Maven projects, this typically means inspecting:

  • Parent POM versions
  • Spring Boot BOM versions
  • Compiler settings
  • Java runtime requirements

For Gradle builds, equivalent metadata can be extracted from build files.

Most importantly, the skill must display the raw detection results before proceeding.

If the version cannot be determined, the process stops.

This eliminates an entire category of upgrade failures caused by incorrect assumptions.


Step 2: Resolve the Latest Stable Version

One of the most common mistakes an AI agent can make is confidently reporting an outdated version as the latest release.

The solution is straightforward:

Never allow the model to answer version questions from memory.

Instead, retrieve version metadata from authoritative sources such as:

  • Maven Central
  • Internal artifact repositories
  • Framework release APIs
  • Enterprise package mirrors

Migration guides and release notes remain extremely valuable, but they are supplementary sources, not the authority for version determination.

A modernization workflow should always be able to explain:

  • Which version was selected
  • Why it was selected
  • Where that information came from

Step 3: Create the Migration Plan

Before touching code, the skill generates a complete upgrade strategy.

The plan should include:

Current State Assessment

  • Existing framework versions
  • Runtime versions
  • Project structure
  • Dependency overrides

Target State

  • Recommended Spring Boot version
  • Corresponding Java version requirements
  • Dependency alignment strategy

Upgrade Path

Major version jumps should never happen in a single step.

For example:

Spring Boot 2.4

Spring Boot 2.7

Spring Boot 3.0

Spring Boot 3.5

Each hop is evaluated independently.

Breaking Change Analysis

Examples include:

  • Jakarta namespace migration
  • Spring Security DSL changes
  • Spring Cloud configuration updates
  • Actuator endpoint changes
  • Jackson compatibility updates

Dependency Audit

The skill should identify:

  • Redundant dependency versions
  • Obsolete overrides
  • Framework-managed dependencies
  • Incompatible libraries

Risk Areas

Common risks include:

  • Security-sensitive components
  • Serialization layers
  • Database schema interactions
  • Poorly tested services

Reuse Previous Upgrade Work

One of the highest-leverage additions to our process was searching for prior successful upgrades.

If another team already solved:

  • A Jakarta migration issue
  • A Spring Security migration pattern
  • A dependency compatibility problem

Then the skill should reuse those proven changes rather than rediscover them.

At scale, every upgrade should make future upgrades faster.


Step 4: Create a Clean Baseline

Before upgrading anything:

mvn clean verify

or

gradle clean build

should complete successfully.

Without a known-good baseline, it becomes difficult to determine whether failures are caused by modernization work or pre-existing issues.

Low test coverage should also be flagged explicitly so stakeholders understand verification limitations.


Step 5: Upgrade One Hop at a Time

This is the single most important safety mechanism.

For each version hop:

  1. Update framework version
  2. Apply required migrations
  3. Build
  4. Run tests
  5. Verify application startup
  6. Commit the change

Only after a successful verification cycle should the next hop begin.

If a build fails:

  • Diagnose
  • Fix
  • Rebuild

Do not continue stacking changes.

Large unverified jumps dramatically increase troubleshooting complexity.


Step 6: Verify the Entire Application

Reaching the target version is not enough.

The final validation should include:

  • Clean builds
  • Full test execution
  • Application startup verification
  • Removal of obsolete package references
  • Dependency hygiene checks
  • Review of remaining warnings

Anything left unresolved should be documented explicitly.


Step 7: Produce a Modernization Report

A reviewer should be able to understand the upgrade in minutes.

A useful report typically contains:

Upgrade Summary

Spring Boot 2.7.18 → 3.5.5
Java 17 retained

Upgrade Path

2.7.18 → 3.0.x → 3.5.5

Changes Applied

- 42 files modified
- 7 configuration properties renamed
- 11 dependency overrides removed

Validation

- Build successful
- Tests passed
- Application startup verified

Follow-Up Items

- Remaining deprecation warnings
- Technical debt opportunities
- Future modernization candidates

This report becomes the foundation for the pull request description and long-term audit history.


Two Non-Negotiable Rules

If there is only one thing to remember from this article, it is these two rules.

Rule #1: Never Trust a Guessed Version

Every version must come from deterministic detection or a live authoritative source.

Never rely solely on model memory.

Rule #2: Never Batch Upgrade Hops

Every major or significant version transition must be independently verified before moving to the next.

These two guardrails eliminate a surprising percentage of upgrade failures.


Lessons Learned from Real Upgrades

A few recurring issues surfaced repeatedly.

Annotation Processor Problems

Some projects compiled under one JDK but failed under another because annotation processors were not configured correctly.

This became a permanent item in our modernization checklist.

Stopping Short of the Latest Patch

Early versions of the skill occasionally stopped on an intermediate version.

The fix was adding a final version-resolution check before declaring success.

Agent Approval Pauses

Even with autonomous execution enabled, agents sometimes paused during higher-risk operations.

This turned out to be a feature rather than a flaw, ensuring human review occurred at important decision points.

Missing Pull Requests

File changes alone are not a finished deliverable.

The skill must explicitly include instructions to:

  • Commit
  • Push
  • Create or update the PR

Otherwise some runs stop prematurely.

Build Time Dominates

Most execution time is spent waiting for build and test validation, not reasoning.

That is expected.

The same would be true of an experienced engineer performing the work manually.


Running Many Upgrades in Parallel

The biggest productivity gain came from using VS Code's new Agents Window.

The process was simple:

  1. Identify target repositories
  2. Configure a standard upgrade skill
  3. Launch one agent session per repository
  4. Let each workspace run independently
  5. Review results and PRs periodically

Instead of upgrading repositories sequentially, the work becomes a supervised batch operation.

This dramatically increases throughput while preserving review quality.


Final Thoughts

A Spring Boot modernization skill is not about replacing engineering judgment.

It is about standardizing proven engineering practices.

The most successful skills combine:

  • Deterministic version detection
  • Live version verification
  • Structured planning
  • Incremental upgrades
  • Strong validation
  • Reusable organizational knowledge

More importantly, every upgrade improves the next one.

Your migration checklist grows. Your compatibility database improves. Your automation becomes more reliable.

Eventually, framework modernization shifts from a large project to a repeatable operational process.

And that is where the real value of AI-assisted software modernization begins.

❤️ Support This Blog


If this post helped you, you can support my writing with a small donation. Thank you for reading.


Comments

Popular Posts

A New Collection of Thoughtful Learning Apps — Now Available on iOS & Android

2023, New Start! New AdSense Account! New Earnings!

Swagger annotations for API that allows downloading files as zip