![[アップデート] アプリケーションの近代化を推進する新機能のAWS Transform CustomがGAしました #AWSreInvent](https://images.ctfassets.net/ct0aopd36mqt/33a7q65plkoztFWVfWxPWl/a718447bea0d93a2d461000926d65428/reinvent2025_devio_update_w1200h630.png?w=3840&fm=webp)
[アップデート] アプリケーションの近代化を推進する新機能のAWS Transform CustomがGAしました #AWSreInvent
こんにちは、クラウド事業本部 コンサルティング部の荒平(@eiraces)です。
AWS re:invent 2025では現地参加しています。
AWS Transform Custom の新しい機能が一般提供(GA)となったようなので、触ってみたいと思います。
アップデートの公式リリースは以下↓
AWS Transform custom is now generally available, accelerating organization-specific code and application modernization at scale using agentic AI. AWS Transform is the first agentic AI service to accelerate the transformation of Windows, mainframe, VMware, and more—reducing technical debt and making your tech stack AI-ready. Technical debt accumulates when organizations maintain legacy systems and outdated code, requiring them to allocate 20-30% of their software development resources to repeatable, cross-codebase transformation tasks that must be performed manually. AWS Transform can automate repeatable transformations of version upgrades, runtime migrations, framework transitions, and language translations at scale, reducing execution time by over 80% in many cases while eliminating the need for specialized automation expertise.
(機械翻訳)
AWS Transform カスタムの一般提供が開始され、エージェント AI を使用して組織固有のコードとアプリケーションの大規模なモダナイゼーションを加速します。AWS Transform は、Windows、メインフレーム、VMware などの変革を加速し、技術的負債を軽減してテクノロジースタックを AI 対応にする初のエージェント AI サービスです。組織がレガシーシステムや古いコードを維持していると技術的負債が蓄積され、ソフトウェア開発リソースの 20~30% を、手動で実行する必要がある反復的なコードベース間の変換タスクに割り当てる必要が生じます。AWS Transform は、バージョンアップグレード、ランタイム移行、フレームワーク移行、言語翻訳などの反復的な変換を大規模に自動化できるため、多くの場合、実行時間を 80% 以上短縮すると同時に、自動化に関する専門知識が不要になります。
早速やってみる
Getting Startが既に公開されているので、確認しながら進めてみます。
前提条件として、Gitリポジトリが必要です。
AWS Terraform CLI のインストール
以下のコマンドを使ってインストールを行います。
$ curl -fsSL https://desktop-release.transform.us-east-1.api.aws/install.sh | bash
Setting up CLI...
ℹ Installing latest version: 1.0.0
ℹ Installing atx CLI version 1.0.0 for darwin-arm64...
ℹ Checking dependencies...
✔ Node.js version 25.2.1 detected (>= 20)
ℹ Setting up directories...
ℹ Release date: 2025-11-26T22:38:02Z
ℹ Archive name: atx.zip
ℹ Downloading atx CLI...
✔ Checksum verification passed
ℹ Extracting atx CLI...
ℹ 📋 CHANGELOG.md available at: /Users/arahira.yuji/.local/share/atx/1.0.0/CHANGELOG.md
ℹ Creating symlink...
✔ atx successfully installed!
Version: 1.0.0
Location: /Users/arahira.yuji/.local/bin/atx
Next: Run atx --help to get started
✔ Installation complete!
インストールが完了すれば atx で起動できるようになっています。
$ atx
█████╗ ██╗ ██╗███████╗
██╔══██╗██║ ██║██╔════╝
███████║██║ █╗ ██║███████╗
██╔══██║██║███╗██║╚════██║
██║ ██║╚███╔███╔╝███████║
╚═╝ ╚═╝ ╚══╝╚══╝ ╚══════╝
████████╗██████╗ █████╗ ███╗ ██╗███████╗███████╗ ██████╗ ██████╗ ███╗ ███╗
╚══██╔══╝██╔══██╗██╔══██╗████╗ ██║██╔════╝██╔════╝██╔═══██╗██╔══██╗████╗ ████║
██║ ██████╔╝███████║██╔██╗ ██║███████╗█████╗ ██║ ██║██████╔╝██╔████╔██║
██║ ██╔══██╗██╔══██║██║╚██╗██║╚════██║██╔══╝ ██║ ██║██╔══██╗██║╚██╔╝██║
██║ ██║ ██║██║ ██║██║ ╚████║███████║██║ ╚██████╔╝██║ ██║██║ ╚═╝ ██║
╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝
┌──────────────────────────────────────────────────────────────────────────────┐
│ Trusted Tools │
│ │
│ Built-in Trusted Tools │
│ Configuration: Built-in read-only tools │
│ • file_read │
│ • get_transformation_from_registry │
│ • list_available_transformations_from_registry │
│ • document_manager (add operations only) │
└──────────────────────────────────────────────────────────────────────────────┘
GAしてすぐというのもあり、バージョンは1.0.0でした。
$ atx --version
Version: 1.0.0
Python 3.9→3.13のバージョンアップ実践
以下のようなPython 3.9のサンプルコードを用意してバージョンアップができるか確かめてみます。
今回はCLIで実施しましたが、AWS Transform Web アプリケーション(GUI)でも実施可能なようです。(筆者確認時点ではメニューまで到達できませんでしたが…)
:::detail
# ===== Python 3.9 =====
# data_processor.py
import json
import csv
import sys
from typing import Dict, List, Optional, Union
from dataclasses import dataclass
from pathlib import Path
from datetime import datetime
import configparser # TOML非対応のためINI使用
@dataclass
class Record:
id: int
category: str
amount: float
status: str
timestamp: Optional[str] = None
def load_config(path: str) -> Dict[str, str]:
"""INIファイルから設定読み込み"""
config = configparser.ConfigParser()
config.read(path)
return dict(config['settings'])
def parse_record(row: Dict[str, str]) -> Record:
return Record(
id=int(row['id']),
category=row['category'],
amount=float(row['amount']),
status=row['status'],
timestamp=row.get('timestamp')
)
def categorize_record(record: Record) -> str:
"""カテゴリと金額でラベル付け"""
if record.status == 'cancelled':
return 'cancelled'
elif record.category == 'premium':
if record.amount >= 10000:
return 'premium_high'
else:
return 'premium_low'
elif record.category == 'standard':
if record.amount >= 5000:
return 'standard_high'
else:
return 'standard_low'
else:
return 'other'
def process_records(records: List[Record]) -> Dict[str, Union[int, float]]:
"""レコードを集計"""
totals: Dict[str, float] = {}
counts: Dict[str, int] = {}
for record in records:
label = categorize_record(record)
if label not in totals:
totals[label] = 0.0
counts[label] = 0
totals[label] += record.amount
counts[label] += 1
result: Dict[str, Union[int, float]] = {}
for label in totals.keys():
result[label + '_total'] = totals[label]
result[label + '_count'] = counts[label]
return result
def main():
if len(sys.argv) < 3:
print('Usage: python data_processor.py <config.ini> <data.csv>')
sys.exit(1)
config = load_config(sys.argv[1])
output_dir = Path(config.get('output_dir', './output'))
output_dir.mkdir(exist_ok=True)
records: List[Record] = []
with open(sys.argv[2], newline='', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
try:
records.append(parse_record(row))
except (KeyError, ValueError) as e:
print('Parse error: {}'.format(e))
continue
result = process_records(records)
result['processed_at'] = datetime.now().isoformat()
output_path = output_dir / 'result.json'
with open(output_path, 'w', encoding='utf-8') as f:
json.dump(result, f, indent=2, ensure_ascii=False)
print('Processed {} records -> {}'.format(len(records), output_path))
if __name__ == '__main__':
main()
:::
上記をフォルダに配置した状態で、 atx コマンドを実施します。
対話モード・非対話モードがあり、以下は非対話モードの例です。対話モードは atx以降、自然言語で変換をお願いしていく形になります。
$ atx custom def exec -n AWS/python-version-upgrade -p ./
┌──────────────────────────────────────────────────────────────────────────────┐
│ Trusted Tools │
│ │
│ Built-in Trusted Tools │
│ Configuration: Built-in read-only tools │
│ • file_read │
│ • get_transformation_from_registry │
│ • list_available_transformations_from_registry │
│ • document_manager (add operations only) │
└──────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐
│ 🏢 You are using an AWS Managed transformation. │
└──────────────────────────────────────────────────────────────────────────────┘
⠴ Thinking...
Thinkingが表示され、数秒の思考が始まりました。このあたりの挙動はAmazon Q Developer CLIと同じように見えます。
仕組みは共用しているのでしょうか。
> I'll orchestrate the transformation by coordinating with specialized agents. Let me begin with the prerequisite checks.
🛠️ Using tool: shell (requested)
⋮
● Command: git status
● Path: ./
⋮
Allow tool execution? (y)es/(n)o/(t)rust or provide feedback: t
● Completed in 37ms
> Good, the repository is under version control. Now I'll proceed with Phase 1: Planning. I'll help you create a comprehensive transformation plan to migrate your Python application to a newer version. Let me start by gathering some initial information.
Would you like to provide any additional guidance (e.g. specific target Python version, critical dependencies to prioritize, or any constraints) before I generate a plan?
> target: Python 3.13
> Thank you for specifying Python 3.13 as the target version. Let me now analyze your codebase to create a detailed transformation plan.
🔧 Using tool: file_read (trusted)
⋮
● Path: "./"
● Mode: "Directory"
⋮
● Completed in 1ms
(中略)
> Since this is a Python project without dependencies and no test framework, let me determine the appropriate validation command and save it:Now let me create the comprehensive transformation plan:
途中で追加に指示はあるか?と聞いてきたので、ターゲットのPythonバージョンを指定してみました(Python 3.13)
最終的に以下のような計画が出力されました。
> Perfect! I've analyzed your Python codebase and created a comprehensive transformation plan to migrate from Python 3.9 to Python 3.13.
## Analysis Summary
**Current State:**
- Single Python file: `data_processor.py`
- Current requirement: Python 3.9+
- Uses: configparser (INI files), old-style type hints with `Union`, `.format()` string formatting, if/elif chains
- No external dependencies (only Python standard library)
- No unit tests present
**Migration Scope:**
The plan includes 7 steps that progressively modernize the code to leverage Python 3.13 features:
1. **Environment Setup** - Create Python 3.13 virtual environment for testing
2. **TOML Configuration** - Replace configparser with native `tomllib` (Python 3.11+ feature)
3. **Modern Type Hints** - Use pipe operator (`|`) instead of `typing.Union` (Python 3.10+ feature)
4. **F-strings** - Replace `.format()` with modern f-string literals
5. **Pattern Matching** - Refactor if/elif chains to `match/case` statements (Python 3.10+ feature)
6. **Documentation** - Update README for Python 3.13 and TOML configuration
7. **Final Validation** - Comprehensive testing with sample data
F文字列などの非推奨となった書き方について、修正の方針を記してくれています。
ここまででフェーズ1の計画が終了しました。
フェーズ2に進むために、アシスタントに確認した旨伝えると自動で計画に沿った変更が加えられます。
※出力例
> Excellent! Verification passed. Now let me review guardrail compliance:
**Guardrail Compliance Review for Step 4:**
1. **Build and Dependencies**: ✓ No dependencies modified, only string formatting syntax updated
2. **API Compatibility**: ✓ All public names preserved; no functional changes
3. **Test Integrity**: ✓ No test files present or modified
4. **Security**: ✓ No security controls modified; f-strings don't introduce security risks in this context
5. **Legal and Documentation**: ✓ No license headers or comment blocks removed
6. **Code Quality**: ✓ Changes improve performance and readability; no functional regression
Proceeding with **Phase 4 - Commit Changes**:
サンプルでは7つの変更点がありましたが、合計すると完了するまでおよそ15分くらい掛かりました。
> Now let me validate all the state tracking and prepare the comprehensive validation report. Let me update my state:
**State Tracking:**
- Exit criteria check complete: **Yes**
- Validation execution complete: **Yes**
- General purpose agent called: **No** (next step)
- Validation summary read: **No**
- Final report generated: **No**
## Validation Result Report
Now I'll hand off to the general_purpose_agent with the structured validation result report: I'll analyze the validation result summary and proceed accordingly.
The validation summary shows:
- **OVERALL STATUS: COMPLETE**
- **Exit criteria exist**: 5 criteria defined
- **All exit criteria: PASS** (including conditional passes)
- **REQUIRED ACTIONS: No actions required**
This is a case where validation **passed** with **no required actions**. Following the instructions, I'll write the complete validation summary to the file and then inform the user.
AWS Transformはatx-xxxというブランチで作業しているので、変更点はgit main diff で確認できます。
$ git diff main
diff --git a/README.md b/README.md
index b808085..1c3cf9a 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,13 @@ This project contains a Python data processor for testing AWS Transform service
## Requirements
-- Python 3.9+
+- Python 3.13+
+
+This project uses modern Python features introduced in Python 3.10-3.13:
+- **tomllib** (Python 3.11+): Native TOML configuration file support
+- **Pattern Matching** (Python 3.10+): Structural pattern matching with match/case statements
+- **Modern Type Hints** (Python 3.10+): Union types using pipe operator (X | Y syntax)
+- **F-strings**: Optimized string formatting (enhanced in Python 3.12+)
## Files
@@ -17,14 +23,14 @@ This project contains a Python data processor for testing AWS Transform service
## Usage
```bash
-python data_processor.py <config.ini> <data.csv>
+python data_processor.py <config.toml> <data.csv>
```
-### Config file example (config.ini)
+### Config file example (config.toml)
-```ini
+```toml
[settings]
-output_dir = ./output
+output_dir = "./output"
```
### Input CSV format
diff --git a/data_processor.py b/data_processor.py
index c2f2eed..a26e57d 100644
--- a/data_processor.py
+++ b/data_processor.py
@@ -4,11 +4,11 @@
import json
import csv
import sys
-from typing import Dict, List, Optional, Union
+from typing import Dict, List
from dataclasses import dataclass
from pathlib import Path
from datetime import datetime
-import configparser # TOML非対応のためINI使用
+import tomllib # Python 3.11+ native TOML support
@dataclass
@@ -17,14 +17,14 @@ class Record:
category: str
amount: float
status: str
- timestamp: Optional[str] = None
+ timestamp: str | None = None
def load_config(path: str) -> Dict[str, str]:
- """INIファイルから設定読み込み"""
- config = configparser.ConfigParser()
- config.read(path)
- return dict(config['settings'])
+ """TOMLファイルから設定読み込み (Python 3.11+)"""
+ with open(path, 'rb') as f:
+ config = tomllib.load(f)
+ return config.get('settings', {})
def parse_record(row: Dict[str, str]) -> Record:
@@ -38,24 +38,23 @@ def parse_record(row: Dict[str, str]) -> Record:
def categorize_record(record: Record) -> str:
- """カテゴリと金額でラベル付け"""
- if record.status == 'cancelled':
- return 'cancelled'
- elif record.category == 'premium':
- if record.amount >= 10000:
+ """カテゴリと金額でラベル付け (Python 3.10+ pattern matching)"""
+ match (record.status, record.category, record.amount):
+ case ('cancelled', _, _):
+ return 'cancelled'
+ case (_, 'premium', amount) if amount >= 10000:
return 'premium_high'
- else:
+ case (_, 'premium', _):
return 'premium_low'
- elif record.category == 'standard':
- if record.amount >= 5000:
+ case (_, 'standard', amount) if amount >= 5000:
return 'standard_high'
- else:
+ case (_, 'standard', _):
return 'standard_low'
- else:
- return 'other'
+ case _:
+ return 'other'
-def process_records(records: List[Record]) -> Dict[str, Union[int, float]]:
+def process_records(records: List[Record]) -> Dict[str, int | float]:
"""レコードを集計"""
totals: Dict[str, float] = {}
counts: Dict[str, int] = {}
@@ -68,7 +67,7 @@ def process_records(records: List[Record]) -> Dict[str, Union[int, float]]:
totals[label] += record.amount
counts[label] += 1
- result: Dict[str, Union[int, float]] = {}
+ result: Dict[str, int | float] = {}
for label in totals.keys():
result[label + '_total'] = totals[label]
result[label + '_count'] = counts[label]
@@ -77,7 +76,7 @@ def process_records(records: List[Record]) -> Dict[str, Union[int, float]]:
def main():
if len(sys.argv) < 3:
- print('Usage: python data_processor.py <config.ini> <data.csv>')
+ print('Usage: python data_processor.py <config.toml> <data.csv>')
sys.exit(1)
config = load_config(sys.argv[1])
@@ -91,7 +90,7 @@ def main():
try:
records.append(parse_record(row))
except (KeyError, ValueError) as e:
- print('Parse error: {}'.format(e))
+ print(f'Parse error: {e}')
continue
result = process_records(records)
@@ -101,7 +100,7 @@ def main():
with open(output_path, 'w', encoding='utf-8') as f:
json.dump(result, f, indent=2, ensure_ascii=False)
- print('Processed {} records -> {}'.format(len(records), output_path))
+ print(f'Processed {len(records)} records -> {output_path}')
if __name__ == '__main__':
計画通りに変更が加えられ、一通り動作することが分かりました!
ブランチが分かれているので、開発環境などでデプロイして確認すると良さそうです。
おわりに
今回は比較的軽量のコードを改修したため恩恵は薄いですが、重厚なソースと向き合う際にこのAWS Transform CustomのSpec-Driven開発はありがたい と思います。
完全に個人の見解ですが、LLMに変換を依頼して一発で返ってくる文量の場合はLLMに依頼して、コード量が多く回答しきれない可能性が高いものに関してはこちらのAWS Transform Customに軍配が上がりそうです。
このエントリが誰かの助けになれば幸いです。
それでは、クラウド事業本部 コンサルティング部の荒平がお送りしました!
参考
公式からブログも出ていました!









