Claude Certification
All case studies
Claude Code · 20% of exam

Migrating Rails 5 → 7 at LumenPay

A 400K-line monolith and a five-person team — how Claude Code took the timeline from quarters to weeks.

Company
LumenPay (fictional payments startup)
Duration
2 weeks
Outcome
Completed the upgrade in 11 working days vs. the original estimated 8 weeks. Zero customer-facing incidents during the migration window.

The setup

LumenPay's main monolith — 400,000 lines of Rails 5.2, started in 2018 — had to land on Rails 7.1 before a security mandate cut off support. Five engineers, a hairy migration spec, and an immovable deadline three weeks out.

Week 1, Day 1 — Bound the work

The senior engineer opened a fresh worktree and gave Claude Code its marching orders:

> Read config/application.rb and Gemfile.
> Produce a migration checklist for Rails 5.2 → 7.1, grouped by file.
> Note the deprecated APIs we depend on and which gems block the upgrade.

Eight minutes later: a 73-item checklist with file paths and risk ratings. The team triaged in person, marked items "Claude can do this", "needs a human", or "needs a human + Claude as a pair."

Day 2 — Commit the safety baseline

Before letting Claude Code touch production code paths, the platform engineer committed a project-scoped .claude/settings.json:

{
  "permissions": {
    "deny": [
      "git push --force*",
      "git push origin main*",
      "bundle exec rake db:drop*",
      "rm -rf*"
    ],
    "allow": ["bundle install", "bundle exec rspec*", "git diff*"]
  },
  "hooks": {
    "PreToolUse": [".claude/hooks/check-no-secrets.sh"]
  }
}

Every engineer's session inherited these rules. Nobody could accidentally force-push or wipe a database from a Claude Code session.

Day 3 — A /migrate-rails slash command

The pattern repeated across files: read the file, apply the documented Rails 7 changes, run the spec for that area, commit on green. They committed it once:

# .claude/commands/migrate-rails.md
For the file path I provide:
1. Read it.
2. Apply Rails 7.1 migration changes per the Rails Upgrade Guide.
3. Run the spec for this area only (`bundle exec rspec spec/<corresponding>`).
4. If green, stage the file and write a commit message starting with "rails 7:".
5. If red, summarize the failures and STOP.

The slash command turned 11 days of repetitive prompting into 11 days of /migrate-rails app/models/payment.rb calls.

Day 5 — Log every file edit to Slack

Engineering leadership wanted visibility without micromanaging. A PostToolUse hook posted every Edit and Write to a #rails-upgrade Slack channel:

TOOL=$(jq -r '.tool_name' <<<"$INPUT")
FILE=$(jq -r '.tool_input.file_path' <<<"$INPUT")
if [[ "$TOOL" == "Edit" || "$TOOL" == "Write" ]]; then
  curl -s -X POST "$SLACK_WEBHOOK" -d "{\"text\": \":memo: $FILE\"}"
fi

Channel got noisy fast and that was fine. When something exploded the next morning, the on-call could scroll back and see exactly which file had been touched at 6:14 PM.

Day 8 — A "payments debugging" skill

LumenPay's payments code has tribal knowledge — which webhooks retry, which counter resets nightly, the exact log lines that mean an authorization failed silently. The team encoded this as a Skill:

.claude/skills/payments-debug/
  SKILL.md
  reference/error-codes.md
  reference/known-failure-modes.md
  scripts/tail-payment-logs.sh

The skill auto-loaded whenever the conversation involved a payment ID. Junior engineers got expert behavior without typing a paragraph of setup every time.

Day 11 — Code-review agent in CI

The team built a small code-review agent on the Agent SDK and ran it on every Rails upgrade PR:

session = Session(
  system=REVIEW_PROMPT_RAILS_7,
  tools=[Tool("read_file"), Tool("git_diff")],
)
review = await session.run(f"Review PR #{pr_number}.")
post_to_github_review(review)

It caught two deprecated patterns the human reviewers had missed across 60 PRs.

What stuck

  • Bound the work first. Don't unleash Claude Code on "do the migration" — feed it a checklist.
  • Commit safety baselines as soon as the harness touches a sensitive repo.
  • Slash commands turn repetitive prompts into single-token invocations.
  • Hooks are the right place for org-wide observability.
  • Skills are how teams encode tribal knowledge so juniors inherit it.
  • The Agent SDK lets you embed the same review behavior inside CI.
Principles applied