
Aws Transform
- 21 installs
- 850 repo stars
- Updated August 3, 2026
- awslabs/agent-plugins
AWS Transform is a Claude skill that migrates, modernizes, and upgrades codebases to AWS and runs continuous-modernization analysis for tech debt, security vulnerabilities, and CVEs.
About
AWS Transform is a skill for migrating, modernizing, and upgrading existing codebases to AWS. A developer uses it to port .NET Framework to .NET 8/10, convert mainframe COBOL to Java, rehost VMware VMs to EC2, migrate SQL Server to Aurora, or upgrade language and SDK versions. It also runs continuous-modernization analysis over repositories to find tech debt, CVEs, and security vulnerabilities and route each workload to the right transformation.
- Migrates and modernizes codebases to AWS (.NET, COBOL mainframe, VMware, SQL Server)
- Runs continuous-modernization analysis for tech debt, CVEs, and security vulnerabilities
- Routes each workload (.NET/VMware/SQL/mainframe) to the correct transformation path
Aws Transform by the numbers
- 21 all-time installs (skills.sh)
- Ranked #812 of 1,039 Cloud & Infrastructure skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
aws-transform capabilities & compatibility
Requires an AWS account and AWS Transform service access
- Capabilities
- document service · code modernization · security audit
- Works with
- aws
- Use cases
- refactoring · security audit · code review
- Pricing
- Bring your own API key
What aws-transform says it does
Migrate, modernize, and upgrade codebases to AWS. Run analysis on repos for tech debt, security vulnerabilities, and modernization opportunities.
Transforms .NET Framework to .NET 8/10, mainframe COBOL to Java, VMware VMs to EC2, SQL Server to Aurora, and upgrades Java/Python/Node.js versions and AWS SDKs.
npx skills add https://github.com/awslabs/agent-plugins --skill aws-transformAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 21 |
|---|---|
| repo stars | ★ 850 |
| Last updated | August 3, 2026 |
| Repository | awslabs/agent-plugins ↗ |
What it does
Migrate or modernize a legacy codebase to AWS and analyze repos for tech debt, CVEs, and modernization opportunities.
Who is it for?
Migrating legacy .NET, mainframe, VMware, or SQL Server workloads to AWS and finding modernization opportunities
Skip if: Infrastructure provisioning, CI/CD pipelines, or general coding tasks
When should I use this skill?
You need to migrate or modernize a legacy codebase to AWS, upgrade language/SDK versions, or analyze repos for tech debt and CVEs.
What you get
Modernized code on AWS targets plus a tech-debt, CVE, and security analysis of the repositories.
- Modernized/migrated code for AWS targets
- Tech-debt and CVE analysis report
- Modernization plan
By the numbers
- .NET Framework to .NET 8/10 migration
- 4 named workload routes (.NET, VMware, SQL, mainframe)
Files
AWS Transform
CRITICAL: Route Before Anything Else
STOP. Before reading files, analyzing code, or starting any workflow, identify the workload first, then route.
Step A: Identify the workload
Look for an explicit workload signal in the user's request — a named technology (.NET, VMware, SQL Server/Aurora/Oracle/MySQL, mainframe/COBOL), workload-specific terminology (Hyper-V, EC2 rehost, stored procs, CICS, JCL), or file/project signals already in the conversation. If no signal is present, treat the request as workload-unspecified.
Step B: Apply workload-specific routing
Workload-specific rules ALWAYS win over the keyword list in Step C. Do not let "analysis" or "tech debt" phrasing override these.
| Workload | Route |
|---|---|
| .NET | Ask the user via AskUserQuestion: "For your .NET work, are you looking to modernize to .NET 8/10 (port the code, change targets), run an assessment for modernization (scope the work, identify blockers, plan the port), or analyze your repos for tech debt, security vulnerabilities, or CVEs?" → "Modernize" or "Assessment for modernization" → proceed to the Overview section (the .NET workload handles both). → "Analyze for tech debt / security / CVEs" → route to continuous modernization (see Step D). |
| VMware | Proceed to the Overview section. NEVER route VMware requests to continuous modernization — even if the user uses words like "analyze", "assess", "find issues". VMware assessment is handled by the VMware workload agent, see vmware. |
| SQL / Database | Proceed to the Overview section. NEVER route SQL/database requests to continuous modernization — SQL Server, Oracle, MySQL, and Aurora migrations are handled by the SQL workload agent, see sql. |
| Mainframe / COBOL | Proceed to the Overview section. NEVER route mainframe requests to continuous modernization — COBOL/CICS/JCL transformations are handled by the mainframe workload agent, see mainframe. |
| Workload-unspecified | Continue to Step C. |
Step C: Keyword-based routing (workload-unspecified only)
This list applies only when the user has not named a workload. If any of the workload rules in Step B matched, you have already routed — do not re-evaluate against this list.
If the user's workload-unspecified request matches any of these intents, route to continuous modernization — do NOT scan files yourself:
- "analysis", "analyze", "find issues", "what's wrong", "tech debt", "security vulnerabilities", "CVEs"
- "what should I fix", "where do I start"
- "report", "dashboard", "compare", "trend"
- "remediate findings", "remediation", "fix what you found"
- "custom transform"
- "continuous modernization", "AWS Transform - continuous modernization"
Step D: For continuous modernization requests
1. First-response telemetry notice (once per session). The first time a request routes here in this session, ALWAYS prepend this line exactly to your reply to the user before doing anything else:
Note: this skill collects telemetry. To opt out, see here.
Show it exactly once per session. Do NOT repeat it on subsequent continuous modernization requests in the same session. If the user explicitly asks to disable telemetry, omit --telemetry for the rest of the session (see each sub-skill's Telemetry section for the flag format). 2. When invoking AWS Transform - continuous modernization (continuous modernization) commands, use atx ct (with a space). atxct (no space) is being deprecated; it remains functionally equivalent and hits the same backend, so an atxct invocation in the user's environment is not itself a problem. Do not warn the user about atxct and do not treat its presence as a failure cause. 3. Check if atx ct is installed AND up to date — run this as a single command:
INSTALLED=$(atx ct --version 2>/dev/null | head -1); LATEST=$(curl -fsSL "https://transform-cli.awsstatic.com/index.json" 2>/dev/null | grep -o '"latest"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"latest"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/'); echo "Installed: ${INSTALLED:-not found}, Latest: ${LATEST:-unknown}"4. If INSTALLED is empty or LATEST is newer: curl -fsSL https://transform-cli.awsstatic.com/install.sh | bash && source ~/.bashrc 5. If atx ct fails after install, the binary itself is rarely the cause — atx ct and atxct share the same backend and fail identically for env/auth/server reasons. Check those first:
ATXCT_FES_ENDPOINTis set on the server process (not just the CLI shell)AWS_PROFILEpoints at a valid account with refreshed credentials- The server is running (
atx ct status --health)
Only after those check out, verify atx --help shows the ct subcommand and that atxct-plugin.mjs is co-located with the atx binary. 6. Start the server using the continuous-modernization-server.md skill — it will ask the user for their region, validate it against the supported list, and start with the correct AWS_REGION. Wait 5s, then verify with atx ct status --health. 7. Then use the appropriate continuous modernization skill — see continuous-modernization
When in doubt for a workload-unspecified request → continuous modernization. This default applies ONLY after Step B has cleared — VMware, SQL, and mainframe never fall through to continuous modernization regardless of how the question is phrased; .NET only routes to continuous modernization after the user picks "analyze for tech debt / security / CVEs" in Step B's intent question (both "modernize" and "assessment for modernization" stay in the .NET workload). Once routed, do NOT manually read source files to find issues — that's what atx ct analysis run does.
CRITICAL: Never Show Pricing or Timing Estimates
Do NOT quote specific dollar amounts, hourly rates, or time estimates for AWS resources or analyses. This includes:
- ❌ "~$0.20/hr", "~$5/day", "$X per analysis"
- ❌ "takes ~30 min", "completes in 2-5 hours", "~30s startup"
- ❌ "ETA: 30 min – 2 hours"
Instead:
- For pricing: redirect to https://aws.amazon.com/ec2/pricing/, https://aws.amazon.com/transform/pricing/, etc.
- If asked directly: "I can't give specific cost or time estimates — pricing depends on your usage and AWS quotas. Check the AWS pricing pages for current rates."
This applies to all responses, all skills, and all situations.
---
Overview
Domain expertise for migrating and modernizing workloads using AWS Transform. Covers .NET Framework to .NET 8/10, mainframe COBOL to Java, VMware to EC2, SQL Server to Aurora PostgreSQL, and custom code transformations (Java, Python, Node.js version upgrades, SDK migrations). Orchestrates assessment, planning, and execution through Managed Agents and AWS Transform CLI with human-in-the-loop checkpoints.
Prerequisites
This skill requires the AWS Transform MCP server (aws-transform-mcp). Configure it in your agent's MCP settings:
{
"mcpServers": {
"aws-transform-mcp": {
"command": "uvx",
"args": [
"awslabs.aws-transform-mcp-server@latest"
]
}
}
}The AWS Transform CLI is also required for custom transformations. Install via:
curl -fsSL https://transform-cli.awsstatic.com/install.sh | bashMandatory workflow
Follow these phases in order. Do NOT skip ahead. Authentication is handled just-in-time — only when a chosen action actually needs it. Do NOT probe auth before the user has declared an intent.
Resume → Check .atx/context.json
Intent → Ask user what they want to do
Discovery → Scan workspace + query available agents
Scope → User selects what to modernize (GATE 1)
Assessment → Run workload assessment (NOT optional)
Requirements → Draft from assessment report
Approval → User approves requirements (GATE 2)
Tasks → Generate tasks.md
Execute → Run transforms, monitor, review diffsDiscovery finds opportunities. Assessment produces detailed findings. Requirements come from the assessment — NOT from discovery.
You MUST NOT create requirements without an assessment report. You MUST NOT start execution without requirements.md and tasks.md.
Resuming a prior session
Check for .atx/context.json (workspace-relative). NEVER read ~/.aws/atx/kiro-power-context.json.
This check is an internal bookkeeping operation. The user must never see it happen. Do not announce the check, do not narrate what you are doing. No phrases like "checking for prior sessions", "let me check", "check for a prior session", "context file". On a fresh install, the first visible output must be the intent question — no preamble of any kind.
- No context found: Proceed directly to intent. Produce no user-visible output for this step.
- Context found: If the context has an active job (
assessment.jobIdor entries inexecution.activeJobIds), try to refresh live state from the service, but do so invisibly: - Check auth first (no-auth-required). If sign-in is NOT configured, skip the refresh entirely — do not attempt service calls. Use local context only.
- If sign-in is configured, fetch each resource your resume message depends on — at minimum the job itself and all pending user tasks. Surface every pending task to the user; do not cherry-pick one and omit the others.
BLOCKINGHITL tasks hold up progress even when the job status is active;NON_BLOCKINGtasks still need attention but don't stall the job. Name every pending task; flag blocking ones. Don't infer one resource from another. - If any call fails for any reason, silently fall back to local context. Do NOT reveal your reasoning about the refresh to the user — no "sign-in isn't configured so I'll skip", no "the service isn't reachable". The user should see only the resume message. Do NOT demand auth or block the flow.
Then tell the user about their prior session. Frame the offer explicitly as a continuation of that same session — not a new one. The message should make clear:
- This is the specific session they previously worked on. Mention the phase reached, workspace/job identifiers if relevant.
- Refresh succeeded → speak in present tense about live state ("your assessment job is running", "I need your input on X to continue"). If there is a pending HITL task, surface it — don't bury it under "your job is running."
- Refresh failed or was skipped → use prior-session framing: "last time", "when you paused", "previously", "your last session had finished assessment." Do NOT present-tense claims about job state — local context may be stale. Offer sign-in as the path to current status ("sign in to see the latest status"), not as a gate.
- Resume = continue where you left off, reusing the existing assessment report, workspace, and prior progress.
- Start fresh = discard the prior session (local artifacts deleted) and begin a brand-new migration.
Use language like "continue where you left off" or "pick up from where you stopped" — not ambiguous phrasing like "start a similar session." If user chooses start fresh, delete .atx/context.json, .atx/discovery.json, .atx/assessment-report/, and .atx/specs/, then proceed to intent. Otherwise follow the resume logic in workflow reference.
Determining user intent
If Step A/B routed the request to continuous modernization, skip this entire section. continuous modernization has its own self-contained onboarding flow — hand off directly to continuous-modernization-guide. Its own first prompt (Mode selection: Local vs. AWS Infrastructure) is the user's first visible question. Do NOT show the generic intent menu first, and do NOT mix in non-continuous modernization options like "Browse My Jobs" or "Start a Specific Transform" — those are AWS Transform top-level capabilities, not continuous modernization features.
For every other route — VMware, SQL, Mainframe, and .NET (modernize or assessment-for-modernization) — use the generic intent menu below. The menu's options (Discover Workspace, Browse Jobs, Start Specific Transform, Analyze for findings) are how those workloads enter the standard MANDATORY workflow's Discovery → Scope → Assessment phases.
Generic intent menu
Ask the user: "What would you like to focus on?" The first user-visible action in this phase is the question — no auth-probing tool calls precede it, no auth lecture precedes it.
With projects: [Discover This Workspace] [Browse My Jobs] [Start a Specific Transform] [Analyze for findings] No projects: [Browse My Jobs] [Open a Project Folder] [Start from Scratch] [Analyze for findings]
Custom vs continuous modernization routing. When the user's intent is clear, route to the correct skill set using the decision table in continuous-modernization reference. Key rule: named transformation
- no prior continuous modernization findings → Custom. Analysis/reporting/remediation of existing
findings → continuous modernization. When in doubt → continuous modernization.
Just-in-time auth. Once the user picks an intent, the next tool that action needs may require auth. If so, prompt for auth then, framed around the action the user just chose ("to browse your jobs, sign in to AWS Transform"). Which auth each MCP tool needs is reported by the MCP server — read it from the tool's description, get_status, or the error the tool returns. CLI transforms use AWS credentials only — do NOT prompt for sign-in for CLI-only intents, even when sign-in is unconfigured. If the user picks something that needs no service call (e.g., "Open a Project Folder"), do not probe auth.
See auth reference for the MCP-vs-CLI auth split and how to present sign-in options.
Discovery
Fast scan (~10 sec). Three things happen in parallel:
1. Scan the workspace — detect languages, frameworks, file types, and dependencies present in the project. 2. Query available agents — call list_resources with resource: "agents" (MCP). Skip if sign-in is not configured or the user's intent is CLI-only. This is a paginated API — fetch all pages to get the complete set. The results contain two levels:
- Orchestrator agents — top-level agents you create jobs with. Each orchestrator may have sub-agents that provide deeper workload-specific capabilities.
- Sub-agents — invoked through their orchestrator, not directly. They represent specialized skills within a workload type.
- Some agents may not belong to a known orchestrator — treat these as standalone capabilities.
3. List available transformation definitions — call atx custom def list (CLI) to get the current set and what they transform. Skip if CLI is not available or the user's intent is MCP-only.
For the "Discover This Workspace" intent, Discovery is where sign-in is first required (other intents like "Browse My Jobs" need sign-in even earlier, per the just-in-time rule — handle those there). If list_resources returns NOT_CONFIGURED, prompt the user to sign in for the auth system needed — do not demand both.
Then match workspace signals against orchestrator capabilities and available transformation definitions. Before selecting an orchestratorAgent for any workload, read the matched workload's reference file — it may specify the exact agent to use. Save the matched results to .atx/discovery.json — include the orchestrator → sub-agent hierarchy so later steps know what deeper capabilities are available.
See workflow reference for the workspace scanning framework.
Discovery is NOT assessment. Discovery identifies opportunities and matches them to available agents. Assessment produces the detailed findings.
Scoping (GATE 1)
For each matched workload type, read ALL reference files with its prefix (e.g., [dotnet](references/dotnet.md)). These contain the workload's capabilities, workflow, agent details, example requirements, and known limitations. The file prefix comes from the agent match in Discovery — not from a hardcoded list.
Show migration table, then let the user select with multiSelect:
| Risk | Why | Component | Current | Target | AWS Target | Recommended Approach |Always explain risk in plain language in the "Why" column — use the user-facing phrases from the Risk Classification table in workflow reference. Never show a bare HIGH/MED/LOW label without explanation.
User selects what to modernize.
Assessment
This is NOT optional. Run the workload's assessment BEFORE creating requirements.
Tell the user: "I'll assess your workload. The assessment report drives the migration plan."
How assessment runs depends on the workload's reference files. Each workload type defines its own assessment approach — the agent to use, the objective format, and how to collect results. Consult the matched workload's reference files for specifics.
General pattern for agent-based assessment:
1. Confirm the plan — tell the user what you will do (create workspace, create job with which agent, what the objective is). WAIT for approval before calling any tools. 2. Create/select workspace 3. Create job with a clear objective — the workload's reference files define what a good objective looks like 4. Start the job (already started by create_job; use control_job to restart if stopped) 5. Send a detailed follow-up message with project specifics 6. Ask before uploading — ask how the user wants to share source code. WAIT. Then upload with categoryType: "CUSTOMER_INPUT". 7. Handle agent requests (checkpoints, decisions) — always present to user, WAIT for user response 8. When assessment completes, download the report: get_resource resource="artifact" 9. Save report to .atx/assessment-report/
Rule: NEVER batch workspace creation, job creation, and uploads into a single turn without user confirmation at each decision point.
Use the orchestrator agent or transformation definition identified during Discovery. The match comes from list_resources (with resource: "agents") and atx custom def list, not a hardcoded mapping. When creating a job, specify the orchestrator — sub-agents are invoked by the orchestrator as needed.
Update .atx/context.json with phase: "assessed", workspace ID, job ID.
Requirements (from assessment report)
Now create .atx/specs/requirements.md using the assessment report — NOT discovery findings.
- Read
.atx/assessment-report/for detailed findings - Load workload reference files for context
- Draft requirements grounded in the assessment (specific blockers, LOC, complexity, migration paths)
- Each requirement says WHO handles it: AWS Transform CLI / Managed Agents / IDE
- Multi-module: group by module with Module Overview table
- See workflow reference for format
Do NOT create tasks.md yet.
Show requirements summary and let the user choose: [Looks Good] [Edit] [Add Component]
Approval (GATE 2)
Ask the user: "Requirements finalized. Ready to create the execution plan?" [Create Plan] [Edit More]
Task generation
Generate tasks.md from approved requirements:
- Module Status table + per-module sections
- Sized: max 100 files/task
- Parallel groups verified
- Review-diffs after every code change
- See workflow reference for format
Present options: [Start Execution] [Review Tasks] [Modify]
Execution
See workflow reference for full details.
How execution runs depends on the workload's reference files. Each workload type defines its own execution tooling — which agent or CLI command to use, how to parallelize, and how to collect results. Consult the matched workload's reference files.
General pattern for agent-based execution:
When creating new jobs, always:
1. Clear objective in create_job — what to transform, from what, to what 2. Detailed follow-up message via send_message — project specifics, discovery findings, blockers 3. Upload artifacts if agent needs code — ask user first, categoryType: "CUSTOMER_INPUT"
Every agent request → user decides (NEVER auto-handle)
When the AWS Transform agent asks for input, needs files, or hits a checkpoint:
1. Read the task/message 2. Present to user 3. WAIT for user response 4. Relay user's decision back to agent
Uploading artifacts to agents
Always use categoryType: "CUSTOMER_INPUT" when uploading files to an agent:
upload_artifact(
workspaceId="...", jobId="...",
content="/path/to/source.zip",
fileType="ZIP",
categoryType="CUSTOMER_INPUT"
)| categoryType | When to Use |
|---|---|
CUSTOMER_INPUT | Uploading files TO the agent (source code, configs, data) |
CUSTOMER_OUTPUT | Downloading files FROM the agent (reports, migrated code) |
HITL_FROM_USER | User responses to agent HITL tasks |
See workflow reference for agent request handling patterns.
Progress
Review diffs after every code change. User must approve. Update tasks.md checkboxes + .atx/context.json after every step.
---
Context persistence (.atx/context.json)
Save .atx/context.json IMMEDIATELY after completing each phase — before presenting results to the user. Every phase transition must have a context save between them. Top-level keys: phase, discovery, assessment, spec, workStyle, execution, updatedAt. See workflow reference for the full schema.
Resume: read phase, pick up from that phase.
---
Constraints
- MUST use product, capability, and step names exactly as defined in this document. Never paraphrase or invent terminology. When describing this skill's capabilities, use: "Migrate, modernize, and upgrade codebases — .NET, mainframe COBOL, VMware, databases, and language/SDK upgrades — using AWS Transform CLI and Managed Agents, directly from your IDE."
- MUST present user choices as an explicit selectable list — never bury options in prose or proceed on an inferred answer
- MUST run CLI commands in background — never block the conversation
- MUST discover agents dynamically via
list_resourceswithresource: "agents"(paginated) — do not hardcode agent names - MUST create jobs with orchestrator agents — sub-agents are invoked by the orchestrator, not directly
- MUST refer to resources by name, not ID. When referencing a workspace, job, agent, or artifact in user-facing messages, use its human-readable name. Never surface raw UUIDs in prose. If a resource has no name, use a descriptive phrase ("your .NET modernization job") rather than the ID.
- MUST NOT expose internal mechanics to the user — do not name tools (get_status, list_resources), do not cite step numbers, do not reference files you are reading, and do not narrate what you are about to do. Just do it silently and present the outcome in user terms.
- MUST NOT mix workflow descriptions with actual questions in the same numbered list, and never use count language like "two questions" when some items are informational steps rather than questions. Keep what-I-will-do separate from what-I-need-from-you.
- MUST NOT frame HITL checkpoints, agent questions, or pending decisions as coming from "the web app", "the webapp", "the web UI", or a third-party "the agent is asking / the agent needs / the agent wants". The user is working with you in the IDE — you own the interaction. Present every checkpoint as your own first-person request, not a relayed message from elsewhere. Wrong: "The web app is asking how you want to deploy the landing zone." / "The agent is now asking about the replication subnet configuration." Right: "The next step is to choose how to deploy the landing zone." / "I need the replication subnet configuration to continue."
- MUST NOT explain what this skill does
- MUST NOT create requirements from discovery — wait for assessment
- MUST NOT skip from discovery to execution
- MUST NOT modify code, upgrade dependencies, or run analysis manually — always use AWS Transform tooling
- MUST NOT probe
--helpto figure out a CLI invocation that the reference files already document. The capability-specific reference files inreferences/(e.g.continuous-modernization-source.md,continuous-modernization-analysis.md,continuous-modernization-remediation.md,custom-cli-reference.md) contain the canonicalatx ct …andatx custom …commands with every required flag and example invocations — read the matching file and lift the command verbatim. The orchestrating files (continuous-modernization-guide.md,continuous-modernization-setup.md) explicitly point at them ("Use the/sourceskill for the exact commands").--helpis a fallback used ONLY when (a) no reference file covers the capability, or (b) a documented command demonstrably fails because the installed CLI version diverges from the reference. Treat--helpprobes the user can see as a signal that the agent didn't read its own skill — that is the failure mode this rule prevents. - MUST NOT make decisions on behalf of the user
- MUST NOT editorialize or use subjective language — no "interesting", "fascinating", "notably", "impressive", "remarkable". State findings as facts.
- MUST NOT prompt for authentication before the user has declared an intent. Auth prompts come from the tool a chosen action needs, framed around that action.
- MUST NOT overclaim freshness. If you did NOT fetch a resource this turn, lead with "last I checked" (past tense throughout) and offer to refresh. Never promise proactive surfacing ("I'll let you know when…") unless actively polling — make the reactive model explicit.
- MUST NOT infer one resource's state from another — each MCP resource (job, tasks, artifacts) is its own source of truth. A job in an active state does NOT imply no pending user tasks. Fetch each resource directly when relevant. See workflow reference.
- MUST NOT mix unrelated transformation goals in the same chat without warning. On every shift to a different goal, suggest the user start a new chat session (they start it themselves). Keep re-offers terse. If the user declines, proceed to answer their question about the other job — do not refuse or redirect back to the original goal. Just avoid mixing cached state (e.g., don't apply VMware findings to the .NET question).
- MUST store state in
.atx/context.json
---
Reference
Core
| Topic | File |
|---|---|
| Authentication (sign-in, AWS credentials, CLI credentials, errors) | references/auth.md |
| Tools (MCP tools, CLI commands, connectors, HITL, troubleshooting) | references/tools.md |
| Workflow (discovery, transforms, execution, planning, context, display) | references/workflow.md |
Workload Types
| Workload | Files |
|---|---|
| .NET | references/dotnet*.md |
| SQL/Database | references/sql*.md |
| Mainframe | references/mainframe*.md |
| VMware | references/vmware*.md |
| continuous modernization | references/continuous-modernization*.md |
Each workload type has a root reference file with its capabilities, workflow, and agent details. Additional files with the same prefix provide deeper guidance (e.g., continuous-modernization-setup.md, continuous-modernization-discovery.md).
Authentication
There are two independent auth paths:
- AWS Transform (MCP tools) — workspaces, jobs, tasks, artifacts, connectors, agents. The MCP server is authoritative: its tool descriptions,
get_statusresponse, and error messages describe supported methods, current state, and recovery. - Custom transformations (AWS Transform CLI) — the
atxCLI, which uses standard AWS credentials. Noatx authcommand, no MCP involvement.
The paths do not block each other. A custom CLI intent proceeds with AWS credentials alone; an MCP intent does not require the CLI. Per the skill instructions, prompt for auth just-in-time for the chosen action — do not probe or demand both.
Signing in
When sign-in is needed, get_status returns a message on the unconfigured connection that enumerates the currently-supported options. Present every option from that message — do not drop any, do not add any, do not reorder for emphasis. The MCP server is authoritative for which options are valid at a given moment (some options may be conditionally unavailable).
Details the MCP message does not include, collect from the user only for the option they pick:
- Cookie mode — need
originandsessionCookie. The cookie comes from the browser: log in to the AWS Transform tenant URL → DevTools (F12) → Application → Cookies →aws-transform-session→ copy Value. - SSO mode — need
startUrl(looks likehttps://d-xxxxxxxxxx.awsapps.com/start, from IAM Identity Center) andidcRegion. - AWS Credentials — no interactive detail to gather.
AWS_PROFILElives in the MCP client's env block; the MCP picks it up on restart.
When a session expires or a cookie is invalid, follow the recovery guidance in the MCP's error message.
AWS Transform CLI auth
The CLI uses standard AWS credentials. There is no atx auth command — auth is whatever the AWS SDK / CLI provider chain resolves.
aws sso login --profile my-profile
export AWS_PROFILE=my-profile
export AWS_REGION=us-east-1Verify: AWS_REGION=us-east-1 atx custom def list --json.
Common CLI-side conditions:
AccessDeniedException→ AWS credentials expired. Re-runaws sso loginor refresh env vars.command not found: atx→ CLI not installed. Use MCP-based transforms instead, or install the CLI.
Environment variables (MCP client config)
Pre-set in mcp.json to skip an interactive configure call:
| Variable | Description |
|---|---|
ATX_REGION | AWS region (default us-east-1) |
ATX_AUTH_MODE | cookie or sso |
ATX_TENANT_URL | Tenant URL (cookie mode) |
SESSION_COOKIE | aws-transform-session=<value> (cookie mode) |
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "CFNRead",
"Effect": "Allow",
"Action": [
"cloudformation:DescribeStacks",
"cloudformation:DescribeStackEvents",
"cloudformation:DescribeStackResources",
"cloudformation:DescribeStackDriftDetectionStatus"
],
"Resource": "arn:aws:cloudformation:*:*:stack/atx-*/*"
},
{
"Sid": "CFNValidateTemplate",
"Effect": "Allow",
"Action": "cloudformation:ValidateTemplate",
"Resource": "*"
},
{
"Sid": "EC2Desc",
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"ec2:DescribeImages",
"ec2:DescribeVpcs",
"ec2:DescribeSubnets",
"ec2:DescribeSecurityGroups",
"ec2:DescribeKeyPairs",
"ec2:DescribeRouteTables",
"ec2:DescribeNatGateways",
"ec2:DescribeInternetGateways"
],
"Resource": "*",
"Condition": { "StringEquals": { "aws:ResourceAccount": "${aws:PrincipalAccount}" } }
},
{
"Sid": "EC2PowerState",
"Effect": "Allow",
"Action": ["ec2:StartInstances", "ec2:StopInstances"],
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": { "StringEquals": { "ec2:ResourceTag/atx-remote-infra": "true" } }
},
{
"Sid": "SSMRead",
"Effect": "Allow",
"Action": [
"ssm:GetCommandInvocation",
"ssm:ListCommands",
"ssm:ListCommandInvocations",
"ssm:DescribeInstanceInformation",
"ssm:DescribeSessions"
],
"Resource": "*",
"Condition": {
"StringEquals": { "aws:ResourceAccount": "${aws:PrincipalAccount}" }
}
},
{
"Sid": "SSMTgt",
"Effect": "Allow",
"Action": ["ssm:SendCommand", "ssm:StartSession"],
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": { "StringEquals": { "ssm:resourceTag/atx-remote-infra": "true" } }
},
{
"Sid": "SSMDocs",
"Effect": "Allow",
"Action": "ssm:SendCommand",
"Resource": "arn:aws:ssm:*::document/AWS-RunShellScript"
},
{
"Sid": "S3Data",
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject", "s3:ListBucket"],
"Resource": [
"arn:aws:s3:::atx-source-code-*",
"arn:aws:s3:::atx-source-code-*/*",
"arn:aws:s3:::atx-ct-output-*",
"arn:aws:s3:::atx-ct-output-*/*"
],
"Condition": { "StringEquals": { "aws:ResourceAccount": "${aws:PrincipalAccount}" } }
},
{
"Sid": "KMSEncryptDecrypt",
"Effect": "Allow",
"Action": ["kms:Encrypt", "kms:Decrypt", "kms:GenerateDataKey"],
"Resource": "arn:aws:kms:*:*:key/*",
"Condition": {
"StringEquals": { "aws:ResourceAccount": "${aws:PrincipalAccount}" },
"ForAnyValue:StringEquals": { "kms:ResourceAliases": "alias/atx-encryption-key" }
}
},
{
"Sid": "SM",
"Effect": "Allow",
"Action": ["secretsmanager:GetSecretValue", "secretsmanager:DescribeSecret"],
"Resource": "arn:aws:secretsmanager:*:*:secret:atx/*",
"Condition": { "StringEquals": { "aws:ResourceAccount": "${aws:PrincipalAccount}" } }
},
{
"Sid": "SMList",
"Effect": "Allow",
"Action": "secretsmanager:ListSecrets",
"Resource": "*",
"Condition": { "StringEquals": { "aws:ResourceAccount": "${aws:PrincipalAccount}" } }
},
{
"Sid": "SchedLifecycle",
"Effect": "Allow",
"Action": [
"scheduler:CreateSchedule",
"scheduler:DeleteSchedule",
"scheduler:GetSchedule",
"scheduler:UpdateSchedule"
],
"Resource": "arn:aws:scheduler:*:*:schedule/atx-control-tower/*",
"Condition": { "StringEquals": { "aws:ResourceAccount": "${aws:PrincipalAccount}" } }
},
{
"Sid": "SchedGroupRead",
"Effect": "Allow",
"Action": "scheduler:GetScheduleGroup",
"Resource": "arn:aws:scheduler:*:*:schedule-group/atx-control-tower",
"Condition": { "StringEquals": { "aws:ResourceAccount": "${aws:PrincipalAccount}" } }
},
{
"Sid": "SchedList",
"Effect": "Allow",
"Action": ["scheduler:ListSchedules", "scheduler:ListScheduleGroups"],
"Resource": "*",
"Condition": { "StringEquals": { "aws:ResourceAccount": "${aws:PrincipalAccount}" } }
},
{
"Sid": "IAMPassEC2InstanceRole",
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::*:role/atx-transform-role*",
"Condition": {
"StringEquals": {
"iam:PassedToService": "ec2.amazonaws.com",
"aws:ResourceAccount": "${aws:PrincipalAccount}"
}
}
},
{
"Sid": "IAMPassSchedulerRole",
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::*:role/AtxSchedulerInvocationRole",
"Condition": {
"StringEquals": {
"iam:PassedToService": "scheduler.amazonaws.com",
"aws:ResourceAccount": "${aws:PrincipalAccount}"
}
}
},
{
"Sid": "IAMReadRoles",
"Effect": "Allow",
"Action": ["iam:GetRole", "iam:ListAttachedRolePolicies", "iam:ListRolePolicies", "iam:GetRolePolicy"],
"Resource": "arn:aws:iam::*:role/*",
"Condition": { "StringEquals": { "aws:ResourceAccount": "${aws:PrincipalAccount}" } }
},
{
"Sid": "IAMReadInstanceProfile",
"Effect": "Allow",
"Action": "iam:GetInstanceProfile",
"Resource": "arn:aws:iam::*:instance-profile/*",
"Condition": { "StringEquals": { "aws:ResourceAccount": "${aws:PrincipalAccount}" } }
},
{
"Sid": "STS",
"Effect": "Allow",
"Action": "sts:GetCallerIdentity",
"Resource": "*"
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "STSIdentity",
"Effect": "Allow",
"Action": "sts:GetCallerIdentity",
"Resource": "*"
},
{
"Sid": "SecurityAgentApi",
"Effect": "Allow",
"Action": [
"securityagent:ListAgentSpaces",
"securityagent:CreateCodeReview",
"securityagent:StartCodeReviewJob",
"securityagent:ListCodeReviewJobsForCodeReview",
"securityagent:ListFindings",
"securityagent:BatchGetFindings",
"securityagent:StartCodeRemediation"
],
"Resource": "arn:aws:securityagent:*:*:agent-space*",
"Condition": {
"StringEquals": {
"aws:ResourceAccount": "${aws:PrincipalAccount}"
}
}
},
{
"Sid": "S3SecurityAgentBucketRead",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::kct-security-agent-*",
"arn:aws:s3:::kct-security-agent-*/*"
],
"Condition": {
"StringEquals": {
"s3:ResourceAccount": "${aws:PrincipalAccount}"
}
}
},
{
"Sid": "S3SecurityAgentUpload",
"Effect": "Allow",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::kct-security-agent-*/security-scans/*",
"Condition": {
"StringEquals": {
"s3:ResourceAccount": "${aws:PrincipalAccount}"
}
}
},
{
"Sid": "IAMPassSecurityAgentRole",
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::*:role/security-agent-*",
"Condition": {
"StringEquals": {
"iam:PassedToService": "securityagent.amazonaws.com",
"aws:ResourceAccount": "${aws:PrincipalAccount}"
}
}
}
]
}
name: analysis
Analysis
Telemetry
When running atx ct analysis run or atx ct remediation create, always include --telemetry.
Format: --telemetry "agent=<agent>,executionMode=<mode>"
agent-- the AI assistant driving this session (lowercase, no spaces). Use the real assistant name -- e.g. kiro, claude, amazonq, copilot.executionMode--local
If the user explicitly asks to disable telemetry, omit --telemetry for the rest of the session.
Choose Compute (Before Running)
Explicit intent overrides repo count. If the user's prompt contains words like "remotely", "on AWS", "on EC2", "on Fargate", "in the cloud", or "remote execution", route to the corresponding execution skill regardless of how many repos are in scope:
- Mentions EC2 / "on an instance" → follow continuous-modernization-ec2-execution
- Mentions Batch / Fargate / "serverless" → follow continuous-modernization-batch-execution
- Mentions "remotely" / "on AWS" / "in the cloud" (no specific compute) → ask which: EC2 or Batch (Fargate)
Otherwise, for analyses with more than 9 repos, ask the customer:
"Do you want to run this locally, set up an EC2 instance in your AWS account, or submit to AWS Batch (Fargate)?"
- Local -- proceed with the commands below
- EC2 -- follow continuous-modernization-ec2-execution
- Batch -- follow continuous-modernization-batch-execution
Commands
# Run analysis (returns immediately with analysis ID)
atx ct analysis run --type <tech-debt-quick|tech-debt-comprehensive|security|agentic-readiness|modernization-readiness|custom> --source <name> [--repo <source>::<slug>] --telemetry "agent=<AGENT>,executionMode=local"
# Run and wait for completion
atx ct analysis run --type <tech-debt-quick|tech-debt-comprehensive|security|agentic-readiness|modernization-readiness|custom> --source <name> [--repo <source>::<slug>] --wait --telemetry "agent=<AGENT>,executionMode=local"
# Run custom analysis with a specific transformation definition
atx ct analysis run --type custom --transformation-name <TD-name> --source <name> --repo <source>::<slug> --wait --telemetry "agent=<AGENT>,executionMode=local"
# Run custom analysis with configuration (file://, JSON, or key=value)
atx ct analysis run --type custom --transformation-name <TD-name> -g "additionalPlanContext=Focus on auth module" --source <name> --repo <source>::<slug> --wait --telemetry "agent=<AGENT>,executionMode=local"
# Get details (JSON for parsing)
atx ct analysis get --id <id> --json
# List all
atx ct analysis list --json
# Filter on the server-side index (fast). Combine as needed.
atx ct analysis list --status <pending|running|complete|cancelled|failed> --json
atx ct analysis list --type <tech-debt-quick|tech-debt-comprehensive|security|agentic-readiness|modernization-readiness|custom> --json
atx ct analysis list --status complete --type security --json
# Category is filtered client-side (does not reduce the fetch); only narrows what's printed.
atx ct analysis list --category "Tech Debt" --json
# Cancel or delete
atx ct analysis cancel --id <id>
atx ct analysis delete --id <id> [--cascade-findings]Custom Analysis
The custom type runs any transformation definition (TD) against a repository. Unlike other analysis types, custom analysis does not generate findings -- it executes the TD directly.
Required flags for `--type custom`:
--transformation-name <name>-- Name of the TD in the registry
Optional flags:
-g, --configuration <config>-- Configuration passed directly to the TD. Accepts:- Key-value:
"additionalPlanContext=Upgrade to Java 17,buildCommand=mvn clean test" - JSON:
'{"additionalPlanContext":"Upgrade to Java 17"}' - File path:
"file:///path/to/config.json"
Constraints:
--transformation-nameis only valid with--type custom-gis only valid with--type custom- Custom analysis will not generate findings
TD Discovery and Recommendation
When the user asks to run a custom analysis or mentions a capability not covered by built-in types (e.g., "generate sequence diagrams", "check code quality", "run compliance scan"), use TD discovery to find the right transformation:
Workflow
1. List available TDs: Run atx custom def list to fetch all available transformation definitions (both AWS-managed and customer-owned custom TDs). 2. Match intent to TD: Based on the user's description, match their intent against TD names and descriptions. 3. Recommend and confirm: Present the matched TD(s) to the user with a brief description. Wait for confirmation before executing. 4. Execute: Run atx ct analysis run --type custom --transformation-name <matched-TD> --source <s> --repo <r> --wait
When to use TD discovery vs built-in types
- If the user's request clearly maps to a built-in type (
tech-debt-quick,tech-debt-comprehensive,security,agentic-readiness,modernization-readiness), use that type directly -- do NOT use custom. - If the request mentions a specific capability not covered by built-in types, or asks about custom/customer-owned TDs, use TD discovery.
- If the user explicitly names a TD, skip discovery and run it directly with
--type custom --transformation-name <TD>.
Repo slug rules
When passing --repo to analysis run:
- Qualified slug (
<source>::<repo>): always works, doesn't need--source. - Bare repo name (
<repo>): only works if--source <name>is also supplied. - Bare `--repo` without `--source`: hard error (
Unqualified repo slug(s)). Don't generate this combination. - Multiple repos: must all share the same source. A run that mixes repos from different sources is rejected with
repos span multiple sources.
Prefer qualified slugs so the source is unambiguous.
Status Values
When polling with atx ct analysis get --id <id> --json, the status field is lowercase:
running-- in progresscomplete-- finished (check findings)cancelled-- user cancelledfailed-- error occurred
Note: It's complete, NOT COMPLETED or completed.
Artifacts
After an analysis completes, its report artifacts can be listed and retrieved:
# List all artifacts for an analysis
atx ct analysis list-artifacts --id <analysis-id> --json
# Get content of a specific artifact
atx ct analysis get-artifact --id <analysis-id> --repo <source>::<slug> --name <artifact-name>Artifact names by analysis type
| Analysis Type | Artifact Names |
|---|---|
| tech-debt-comprehensive | report, technical-debt-report/summary, technical-debt-report/outdated-components, technical-debt-report/maintenance-burden, technical-debt-report/remediation-plan |
| agentic-readiness | ara (per repo); _portfolio_ara (portfolio-level) |
| modernization-readiness | mod (per repo); _portfolio_mod (portfolio-level) |
After Analysis Completes
Once an analysis finishes, retrieve its findings by analysis ID and summarize for the user:
# Get findings produced by a specific analysis
atx ct findings list --analysis-id <analysis-id> --json
# List artifacts to see available reports
atx ct analysis list-artifacts --id <analysis-id> --json
# Read a specific report
atx ct analysis get-artifact --id <analysis-id> --repo <source>::<slug> --name reportWhen an analysis returns 0 findings
A 0 findings result does NOT automatically mean the repo is clean. Each analysis type has its own scope. Do NOT report "clean" without running the right follow-up.
| Type | What 0 findings means | What to do next |
|---|---|---|
tech-debt-quick | Metadata files didn't expose any stale versions. Inconclusive -- quick scan only inspects manifests. | Tell the user the result is inconclusive (metadata-only). Offer to run tech-debt-comprehensive for a code-level analysis. |
tech-debt-comprehensive | Bedrock did not surface tech-debt issues. Repo is likely well-maintained, but other dimensions weren't checked. | Offer security for CVEs, agentic-readiness for AI-readiness, and modernization-readiness for modernization opportunities. Mention these are separate scans. |
security | Security Agent didn't surface CVEs or vulnerable patterns. | Verify the Security Agent is healthy (atx ct setup security-agent --status). If healthy, offer tech-debt-comprehensive for non-security issues. |
agentic-readiness | Repo did not show AI-readiness gaps at the framework level. | Offer modernization-readiness for cloud/infrastructure modernization or tech-debt-comprehensive for general code health. |
modernization-readiness | Repo did not show modernization opportunities (infrastructure, application, data, security, operations dimensions). | Offer agentic-readiness for AI-integration scope or tech-debt-comprehensive for general code health. |
Sanity check before reporting "clean"
If an analysis returns 0 findings on a repo that's obviously stale (Java 8, Node 14, Python 2, .NET Framework, an old pom.xml from 4+ years ago), do NOT report the repo as clean. Treat it as a signal that the analysis type was wrong for the question and offer a follow-up.
Listing analyses
atx ct analysis list exposes three filters. Pick the narrowest combination the question allows.
| Filter | Where it runs | Allowed values |
|---|---|---|
--status | server-side (GSI-backed, fast) | pending, running, complete, cancelled, failed |
--type | server-side (GSI-backed, fast) | tech-debt-quick, tech-debt-comprehensive, security, agentic-readiness, modernization-readiness, custom |
--category | client-side (does not reduce the fetch) | "Tech Debt", "Security", "Agentic Readiness" |
Recommended shapes:
- "What completed analyses do we have?" →
atx ct analysis list --status complete --json - "What security analyses ran?" →
atx ct analysis list --type security --json - "Find completed security runs" →
atx ct analysis list --status complete --type security --json - One specific run →
atx ct analysis get --id <id> --json(point lookup; cheaper than list).
--category is a client-side grouping; e.g. "Tech Debt" matches both tech-debt-quick and tech-debt-comprehensive. Use it when the user wants both subtypes together.
--status and --type accept only the canonical values above. Off-canonical input (e.g. --status completed, --type tech-debt) returns an INVALID_INPUT error.
Discovery
Prerequisites
Check if the server is running with atx ct status --health. If any command fails with a connection error, use the server skill to start the server.
Local sources: path is set at source add time
For local sources, the directory path is provided when the source is first added (atx ct source add --provider local --name <name> --path <dir>). It's stored on the source and reused automatically by subsequent discovery scan --source <name> calls — no --path needed at scan time.
Prerequisite: The source must have been added with --path first. If discovery scan errors with Source "<name>" has no rootPath configured, this machine doesn't have a local rootPath yet for that source (typically because the source was originally added on another machine — rootPath is machine-specific). Resolve by running atx ct source add --provider local --name <name> --path <dir> on this machine, OR by passing --path <dir> to the scan command (which will set and store the rootPath locally).
Override: Pass --path <new-dir> to discovery scan ONLY when you want to overwrite the stored path. This silently changes the source's rootPath. Confirm with the user before passing --path to a previously-registered local source.
Path must be a parent directory: The path (whether at source add or discovery scan) must point to a directory that _contains_ git repos as subdirectories — not to a repo itself. The scanner looks for child directories with .git. If the path points directly at a single repo, the scan returns 0 repos silently. If a user reports 0 repos found, verify their path points to the parent (e.g. /home/user/repos) not a repo directly (e.g. /home/user/repos/my-app).
Commands
# Scan a local source (path was set at `source add` time and is reused automatically)
atx ct discovery scan --source <name>
# Override the stored rootPath (overwrites the source's path -- confirm with user first)
atx ct discovery scan --source <name> --path <new-dir>
# Scan a GitHub source (use the bare name from `source add --name`)
atx ct discovery scan --source <name>
# Check scan status
atx ct discovery status --source <name>After discovery completes
When discovery finds many repos, offer to label a group of repos for targeted analysis: "Want to label a group of repos to focus your analysis? For example, you can label repos by team, priority, or migration wave, then run analysis on just that group." Use the /source skill's repository commands to apply labels. This is optional — skip if the user wants to analyze everything.
name: findings
Findings
Telemetry
When running atx ct analysis run or atx ct remediation create, always include --telemetry.
Format: --telemetry "agent=<agent>,executionMode=<mode>"
agent— the AI assistant driving this session (lowercase, no spaces). Use the real assistant name — e.g. kiro, claude, amazonq, copilot.executionMode—local
If the user explicitly asks to disable telemetry, omit --telemetry for the rest of the session.
# List with JSON output (machine-readable). Always pass --json from agents.
atx ct findings list --json
# Filter by repo, source, severity, type, status, analysis, or fix transform
atx ct findings list \
--repo <source>::<slug> \
--source <name> \
--severity <high|medium|low> \
--min-severity <high|medium|low> \
--type <analysis-type> \
--status <open|dismissed|obsolete> \
--analysis-id <id> \
--fix-transform <transform-name>
# Severity flags (mutually exclusive -- pass at most one):
# --severity <level> Exact match. e.g. --severity high returns only high findings.
# --min-severity <level> Threshold. e.g. --min-severity medium returns medium AND high.
# For "show me findings at least <level>" prompts, use --min-severity.
# Get a single finding by ID
atx ct findings get --id <finding-id>
# Update a finding (status, notes, dismiss)
atx ct findings update --id <finding-id> --status <open|dismissed> --reason "dismiss reason" --notes "notes"
# Batch update multiple findings
atx ct findings batch-update --ids <id1,id2,...> --status <open|dismissed> --reason "reason"
# Delete a finding (must be dismissed or obsolete)
atx ct findings delete --id <finding-id>Status set
open, dismissed, obsolete. Transitions a user can drive: open ↔ dismissed. obsolete is a terminal state set by the system when a re-analysis no longer produces the finding — users do not transition into or out of it.
Filter shapes — pick the narrowest one
Filtering at the CLI is materially faster than pulling everything and filtering after the fact. Each shape below is backed by a server-side index. Combinations that don't match one of these degrade to a full account scan with in-memory filtering and get slow on accounts with thousands of findings.
| User intent | Filter shape |
|---|---|
| Findings from one analysis run | --analysis-id <id> (alone or combined with anything) |
| Live findings on one repo | --repo <slug> --status <s> |
| Account-wide triage | --status <s> (optionally + --severity <level> for one level, or + --min-severity <level> for a threshold) |
| One repo, one analysis type | --repo <slug> --type <t> (single type only) |
| Everything under one source | --source <name> (alone) |
| Auto-fixable by a known transform | --fix-transform <name> (alone or combined) |
Anti-patterns
- Calling
atx ct findings list --jsonwith no filters and post-filtering in the model. Always filter at the CLI. - Per-repo loops when a single
--sourcefilter would cover the whole batch. - Omitting
--status openwhen the user only cares about live findings —dismissedandobsoletepile up over time. - Passing
--typeand--analysis-idtogether when--analysis-idalone already pins the result set to one run. - "Auto-fixable" without a transform name → narrow with
--type tech-debt-quickfirst.tech-debt-quickfindings carry an ATX-transform fix;securityfindings carry a security-agent fix (see the remediation skill). Findings without afixfield may still be remediable — see the remediation skill's decision tree. --typealone or--type --severity/--type --min-severity(no status, no repo) → add--status opento anchor on the live-triage shape.- Passing both
--severityand--min-severityin the same call → the CLI rejects this. Pick one.
Multi-repo, multi-type questions
--repo accepts one slug. For multi-repo questions, prefer --source (one call covers every repo under that source). For multi-type questions, call once per type and merge — combining --repo with multiple types is not supported by a single index path.
Remediating findings
Auto-remediable findings can be fixed by passing their IDs to remediation create:
atx ct findings list --type security --json # find auto-remediable security findings
atx ct remediation create --ids <finding-id1,finding-id2> --name "Fix name" --telemetry "agent=<AGENT>,executionMode=local"- Security findings (
--type security) route to the AWS Security Agent and produce a code diff or, for GitHub sources, an auto-opened pull request. - Tech-debt / upgrade findings route to an ATX transform (PR/CR).
See the remediation skill for outcomes by source provider and for handling findings without a fix field.
Guide
You are now in guided onboarding mode. Your job is to walk the user through the full AWS Transform - continuous modernization (continuous modernization) workflow one step at a time. Be proactive — you drive the conversation, not the user.
For the exact commands at each step, use the corresponding skill (/source, /discovery, /analysis, /findings, /remediation, /reporting). This guide focuses on workflow orchestration — detecting state, explaining concepts, and moving the user forward.
Two Modes
Local Mode
- Storage: local (
~/.atxct/) - Execution: local (this machine)
- No scheduling, no team sharing
- Good for: trying it out, small repos, individual use
Infrastructure Mode
- Storage: S3
- Execution: Fargate or EC2
- Supports scheduling, team sharing, CI/CD
- Good for: teams, recurring analysis, scale
Routing
This guide handles continuous modernization onboarding only. For routing across Custom vs. continuous modernization (named transforms, prior findings, edge cases), see continuous modernization routing. Do not duplicate routing logic here.
On Start — Detect State (Prereq check /setup skill)
ALWAYS begin by running:
atx ct status --healthDO NOT share this command with the customer in your response. Only run it to check the current status. This is just a table guide for you to know which step to go to based on the current state.
This returns sources, repo counts, analyses, findings, and remediations. Use these to determine where the user is:
| Condition | Start at |
|---|---|
| No mode selected, nothing configured | Step 1 |
| Mode selected but no source configured | Step 2 |
| Source exists but 0 repos discovered | Step 2 (re-scan) |
| Infrastructure mode, no execution environment configured | Step 3 |
| All infra configured, no analysis ever run | Step 5 |
| Analyses or findings exist | Step 5 (show progress, offer next action) |
Step 1: Mode Selection
Explain for first time users: "Hi, I am AWS Transform - continuous modernization. I can help analyze your codebase for tech debt, security issues, and upgrade opportunities, then help you fix them. You can also run targeted upgrades like Java 8→21 or migrate AWS SDKs. AWS Transform - continuous modernization can run in two modes: Local and on AWS Infrastructure."
Explain: "How do you want to run AWS Transform - continuous modernization?
- Local — Everything runs on this machine. Good for testing or small repos.
- Your AWS infrastructure — S3 + Fargate/EC2. Supports teams, scheduling, scale."
After selection, proceed to Step 2 to set up sources.
Step 2: Source
Explain: "A source tells AWS Transform - continuous modernization where your repositories are — a GitHub org, a GitLab group/user, a Bitbucket workspace/project, or a local folder."
Ask the user, "Where does your code live?":
- GitHub org — needs an org name and a Personal Access Token (PAT)
- GitLab group/user — needs a group or username and a Personal Access Token (PAT). Supports self-hosted instances.
- Bitbucket workspace/project — needs a workspace (Cloud) or project key (Data Center) and an API token. Supports self-hosted instances.
- Local folder — just needs a path on disk
If the user picks an unsupported source. AWS Transform - continuous modernization currently supports only GitHub, GitLab, Bitbucket, and local folders. If the user names anything else, do NOT stop or fail. Acknowledge it's not directly supported, then offer the local-folder workaround:
"We don't yet support direct integration with every source control system. In the meantime, the easiest way to try AWS Transform - continuous modernization on a few of your repositories is to clone them to your local machine — I can walk you through it. Once they're local, AWS Transform - continuous modernization will analyze them and, when you run a remediation, apply the fixes directly to the local files. From there, you can diff and push back to your repository the way you normally would."
Wait for them to confirm. If they agree, restart Step 2 with Local folder. If they want to skip for now, follow the "Let them skip" rule.
Use the /source skill for the exact commands to add a source.
For local folders: the /discovery skill scans the path you provide; never guess or use the current working directory.
If the user doesn't have a GitHub PAT, explain: "You'll need a Personal Access Token with repo scope. Create one at GitHub → Settings → Developer settings → Personal access tokens. For analysis only, read-only is fine. For auto-fix PRs (remediation), you'll need write access."
If the user doesn't have a GitLab PAT, explain: "You'll need a Personal Access Token with api scope. Create one at GitLab → Settings → Access Tokens → Personal Access Tokens. The api scope covers reading projects, pushing branches, and creating Merge Requests for remediation."
If the user doesn't have a Bitbucket token, explain: "For Bitbucket Cloud, go to https://id.atlassian.com/manage-profile/security/api-tokens and click 'Create API token with scopes'. Select these scopes: read:repository:bitbucket, write:repository:bitbucket, read:pullrequest:bitbucket, write:pullrequest:bitbucket. You'll also need your Bitbucket account email (for API auth, pass via --email) and your Bitbucket username (for git clone/push, pass via --username — visible in your clone URLs at bitbucket.org). For Bitbucket Data Center (self-hosted), create an HTTP Access Token in your project/repo settings and pass --url with your instance URL."
If Infrastructure mode, explain: "As next steps, you need to set up your infrastructure and environment.", proceed to Step 3. If Local mode, explain: "As next steps, you can run different types of analysis", move to Step 4.
After success, move to Step 3 (Infrastructure mode) or Step 4 (Local mode).
Step 3: Setup Execution Environment (Infrastructure mode only)
This step only runs in Infrastructure mode. Local mode runs on this machine automatically.
Explain: "Execution environment is used for analysis (detecting tech debt, security issues, upgrade opportunities) and remediation (running transforms that generate fixes; PR creation uses the GitHub API)."
Explain: "Where should analysis and remediations run?
- Fargate (recommended) — Managed containers. Scales automatically.
- EC2 — Your own instance. Good for existing build servers."
If EC2, follow the /ec2-execution skill (existing instance: provide instance ID or IP; new instance: launch with continuous modernization runtime pre-installed). If Fargate, follow the /batch-execution skill (creates ECS cluster, task definition, IAM roles).
After completion, move to Step 4.
Step 4: Analysis
Local Mode Summary
Show a summary of the status of the current setup if running in local mode:
Setup complete.
✓ Mode: Local
✓ Source: GitHub (acme-corp) -- 127 repos
✓ Execution: This machineInfrastructure Mode Summary
Show a summary of the status of the current setup if running in infrastructure mode:
Setup complete.
✓ Mode: Infrastructure
✓ Source: GitHub (acme-corp) -- 127 repos
✓ Execution: FargateSelect and Start an Analysis
Render this menu as plain numbered markdown text in your response and wait for the user to type a choice. Do NOT route it through any structured choice/picker tool (e.g., `AskUserQuestion` in Claude Code, or any equivalent multi-select/option UI in other harnesses) — those tools impose option caps that silently drop Agentic Readiness and Modernization Readiness. All six options below MUST appear verbatim.
What do you want to do next?
1. Tech Debt -- Quick
Outdated dependencies and easy wins.
2. Tech Debt -- Comprehensive
Deeper analysis, more findings.
3. Security analysis
Vulnerabilities and CVEs.
4. Agentic Readiness
Analyze how ready your repos are for AI agents (frameworks, APIs, docs).
5. Modernization Readiness
Analyze modernization opportunities (infrastructure, application, data, security, operations).
6. Run remediation
Skip analysis and go straight to an upgrade (e.g., Java 8→21, AWS SDK migrations).Use the /analysis skill for the exact commands. Show progress while it runs. After completion, summarize findings by severity:
Analysis complete
Found **N findings** across M repos:
- **X high** -- fix these first
- **Y medium**
- **Z low**
What would you like to do next?
• List all findings (uses /findings)
• Schedule continuous analysis (Infrastructure mode)
• Auto-remediate high-severity issues
• Auto-remediate everything
• Later -- Save for next timeRemediation Selected
Remediation requires:
1. Execution environment — already configured in Step 3 (Infrastructure) or local. 2. GitHub write access — to create branches and PRs. If the token from Step 2 was read-only, prompt the user to update it with repo scope. 3. GitLab write access — to push branches and create Merge Requests. The token needs api scope. 4. Bitbucket write access — to push branches and create Pull Requests. Cloud needs API token with write:repository:bitbucket + write:pullrequest:bitbucket scopes. Data Center needs HTTP Access Token with write permissions.
After token is sufficient, list available remediations grouped by language (e.g., Java: java8-to-java21, aws-sdk-v1-to-v2; Python: python39-to-python312, boto2-to-boto3; Node.js: node18-to-node22, aws-sdk-v2-to-v3).
Use the /remediation skill for the exact commands. After execution, show summary (repos upgraded, repos needing manual review) and offer to open PRs.
Scheduling Selected
Scheduling requires Infrastructure mode. If user is in Local mode, explain: "Scheduling requires Infrastructure mode (S3 + Fargate/EC2). Local mode runs on-demand only — no background jobs. Switch to Infrastructure mode to enable continuous analysis, continuous remediation, and team notifications."
If already in Infrastructure mode:
- Recurring analysis — ask cadence (Daily / Weekly / Custom cron). Sets up an EventBridge rule.
- Continuous remediation — monitors for new findings and auto-fixes them. Requires recurring analysis and GitHub write access. Offers severity thresholds (high → auto-fix immediately; medium → auto-fix batched daily; low → log only).
When User Wants to Exit Onboarding
If user says "cancel", "stop", "later", "skip setup", or wants to do something else:
Setup paused.
Progress saved:
✓ Source: GitHub (acme-corp) -- 127 repos
○ Execution: Not configuredLet them exit. Pick up where they left off if they want to proceed with an action.
Completion
When all steps are done, show a recap of what was accomplished in this session. Use the /reporting skill to generate an HTML report.
Rules
1. One question at a time. Don't ask multiple things in one message. 2. Explain briefly, then ask. 1-2 sentences of context max. 3. Offer defaults. Have a recommended option. Make it easy to proceed. 4. Show commands. Always display the atx ct command you're running so the user learns the CLI. 5. Handle errors plainly. Say what failed, offer a fix or alternative:
- Connection error → "The AWS Transform - continuous modernization server isn't running. Starting it now:
atx ct server" - Invalid token → "That token didn't work. Make sure it has
reposcope." - No repos found → "No repos found in that source. Double-check the org name or path."
6. Let them skip. "skip", "later", "not now" — move on. 7. Let them go back. If they want to redo a step, accommodate. 8. Show progress. For long operations, show status. 9. End with action. Finish by doing something, not just "setup complete". 10. Save progress. If user cancels or errors out, let them resume.
name: remediation
Remediation
Before offering remediation
When the user wants to remediate specific findings, fetch each one with atx ct findings get --id <id> and inspect its fix field before presenting options.
When using --transformation-name, ask the user if they have additional instructions (e.g. a target version or specific guidance) before running. If they do, pass them via -g "additionalPlanContext=<instructions>".
- `fix` is set — the finding is auto-remediable via
--idsalone. - `fix` is null and `recommendation` names a transformation definition — offer
--ids --transformation-name <name-from-recommendation>. - `fix` is null and no `recommendation` — use Transformation Definition Discovery for Remediation to find a matching transformation definition.
Telemetry
When running atx ct analysis run or atx ct remediation create, always include --telemetry.
Format: --telemetry "agent=<agent>,executionMode=<mode>"
agent— the AI assistant driving this session (lowercase, no spaces). Use the real assistant name — e.g. kiro, claude, amazonq, copilot.executionMode—local
If the user explicitly asks to disable telemetry, omit --telemetry for the rest of the session.
# Create from finding IDs (uses each finding's fix.transform_name)
atx ct remediation create --ids <id1,id2> --name "Fix name" --telemetry "agent=<AGENT>,executionMode=local"
# Create from finding IDs with a custom TD override (ignores finding's fix field)
atx ct remediation create --ids <id1,id2> --transformation-name <TD-name> --telemetry "agent=<AGENT>,executionMode=local"
# Create directly on a repo with a custom TD (no findings required)
atx ct remediation create --transformation-name <TD-name> --repo <source>::<slug> --telemetry "agent=<AGENT>,executionMode=local"
# Create with configuration passed to the TD
atx ct remediation create --transformation-name <TD-name> --repo <source>::<slug> -g "additionalPlanContext=Upgrade to Node.js 22" --telemetry "agent=<AGENT>,executionMode=local"
# Create with local execution (runs ATX transform on the server instead of GitHub Actions)
atx ct remediation create --ids <id1,id2> --name "Fix name" --local --telemetry "agent=<AGENT>,executionMode=local"
# List all
atx ct remediation list
# Check status
atx ct remediation status --id <id>
# Retry failed
atx ct remediation retry --id <id>
# Delete
atx ct remediation delete --id <id>Security Remediation
Security findings (from atx ct analysis run --type security) are auto-remediable with the same remediation create command as any other finding — no --transformation-name is needed. Security findings carry a security-agent fix, which routes to the AWS Security Agent code-remediation API instead of an ATX transform; the fix is generated server-side.
# 1. Find the security findings to remediate
atx ct findings list --type security --json
# 2. Create a remediation from one or more security finding IDs
# (same command as any other remediation)
atx ct remediation create --ids <security-finding-id> --name "Fix SQL injection"
# 3. Check status -- the result is a code diff or, for GitHub sources, a pull request
atx ct remediation status --id <remediation-id>Outcomes by source provider
The result link surfaces in remediation status and in the remediation record's execution_artifacts. What you get depends on the repo's source provider:
| Source provider | Per-repo status | Artifact | Meaning |
|---|---|---|---|
| github | pr_open | pull_request_link | AWS Transform - continuous modernization (continuous modernization) applies the diff on the scanned commit and opens a pull request automatically. |
| gitlab / bitbucket / local | diff_ready | code_diff_link | A presigned URL to a unified diff. No PR is opened — apply the diff yourself. |
- For GitHub sources, the diff is applied on a fresh clone pinned to the scanned commit and pushed as a pull request (idempotent per finding — re-running updates the same PR).
- For gitlab, bitbucket, and local sources, security remediation stays diff-only. GitHub is the only provider that gets an auto-opened PR from a security diff. (This differs from tech-debt/transform remediation, where GitLab opens a Merge Request and Bitbucket opens a Pull Request — security diffs are not pushed to those providers.)
- The PR step is fail-soft: if opening the PR fails, the usable diff is preserved (status stays
diff_ready,code_diff_linkset) and the reason is recorded inexecution_artifacts.pr_bridge_error. A bridge failure never discards a good diff.
Requirements
- The
AWSSecurityAgentWebAppPolicyIAM policy already required to runanalysis --type securityalso grants the remediation permission — no additional setup is needed beyondatx ct setup security-agent. - The finding must come from a security analysis whose code review is still resolvable. If it has aged out, the finding carries no fix (
fix: null) and is manual-only — re-run the security analysis to make it remediable again.
Custom Transformation Definition Remediation
Remediation supports running any transformation definition directly, with or without existing findings.
Three modes:
1. Findings-based (existing): --ids <finding-ids> — uses each finding's fix.transform_name to determine which transformation definition to run on each repo.
2. Findings + transformation definition override: --ids <finding-ids> --transformation-name <name> — uses the repos from the findings but runs the specified transformation definition instead of the finding's fix.transform_name. Findings without a fix field are accepted (they would normally be rejected).
3. Direct transformation definition on repo (no findings): --transformation-name <name> --repo <source>::<slug> — runs the transformation definition directly on the specified repo without requiring any findings. Repos must be discovered first (atx ct discovery scan).
Configuration (-g)
The -g/--configuration flag passes configuration directly to the transformation definition. Accepts three formats:
- Key-value:
"additionalPlanContext=Upgrade to Node.js 22,buildCommand=npm test" - JSON:
'{"additionalPlanContext":"Upgrade to Node.js 22"}' - File path:
"file:///path/to/config.json"
Only valid with --transformation-name.
Constraints
- At least one of
--idsor--transformation-nameis required --repocannot be used together with--ids(repos are derived from findings)--repois required when--transformation-nameis used without--ids-gis only valid with--transformation-name- Repos must be discovered (
atx ct discovery scan) before remediation can target them
Transformation Definition Discovery for Remediation
When the user asks to remediate with a custom transformation definition, or a finding has no fix field and no recommendation that mentions a transformation definition, use transformation definition discovery to find the right transformation definition. If a finding already has a recommendation naming a transformation definition, skip discovery and use that name directly.
Workflow
1. List available transformation definitions: Run atx custom def list to fetch all available transformation definitions. 2. Match intent: Based on the user's description of what they want to fix, match against transformation definition names and descriptions. 3. Recommend and confirm: Present the matched transformation definition(s) to the user. Wait for confirmation. 4. Ask for additional instructions: Ask the user if they have additional instructions (e.g. a target version or specific guidance) before running. If they do, pass them via -g "additionalPlanContext=<instructions>". 5. Execute: Run atx ct remediation create --transformation-name <matched-name> --repo <source>::<slug> (with -g if the user provided additional instructions).
Options
--local flag (remediation create)
When --local is passed, the ATX transform runs directly on the server against a cloned copy of the repository instead of dispatching a GitHub Actions workflow. This is useful for:
- GitHub-sourced repos where you want faster feedback without waiting for CI
- Environments where GitHub Actions workflows are not configured or available
- Testing transforms locally before committing to a full workflow run
The execution mode is persisted on the remediation record (compute_mode = 'local'), so subsequent retry and resume operations automatically honour the original intent without needing to re-specify the flag.
Reporting
Generate a single self-contained HTML report that walks through everything AWS Transform - continuous modernization has done in this account: sources connected, repos discovered, analyses run, findings produced, remediations launched (with PR URLs). Claude assembles the HTML inline from the data it gathered and opens it in the browser.
The report is a static snapshot: the HTML has all data baked in as JS consts, so it's portable (emailable, openable offline) and reflects the moment the report was generated.
Prerequisites
- Server running:
atx ct status --healthreturnshealthy. If not, use theserverskill to start it.
Data sources
Populate the report from the live atx ct server.
atx ct source list --json
atx ct repository list --json
atx ct analysis list --json
atx ct findings list --json
atx ct remediation list --jsonRaw response shapes
The five commands do NOT return the same envelope. Read each carefully — repository list wraps results in {"items": [...]}; the other four return a flat array. All field names are snake_case.
`source list --json` → flat array:
[{
"source": "...",
"provider": "github",
"identifier": "...",
"oidcConfigured": false,
"githubAppConfigured": false
}]`repository list --json` → object with items array:
{
"items": [
{
"id": "<source>::<slug>",
"slug": "<source>::<slug>",
"full_name": "...",
"default_branch": "main",
"language": null,
"private": false,
"archived": false,
"has_workflow": false,
"assessed": false,
"source": "...",
"labels": []
}
]
}`analysis list --json` → flat array. Note: there is NO findings array on an analysis row — the count must be joined from findings.json.
[ { "id": "01K...", "status": "complete|running|failed|cancelled|pending|null",
"analysis_type": "security|tech-debt|...", "category": "Security",
"repos": ["<source>::<slug>", ...],
"started_at": "2026-...", "completed_at": "2026-...", "failure_reason": null } ]`findings list --json` → flat array:
[ { "id": "01K...", "analysis_id": "01K..." | "manual:01K...",
"repo": "<source>::<slug>", "analysis_type": "...", "severity": "high|medium|low",
"category": "...", "title": "...", "description": "...",
"status": "open|dismissed|obsolete", // tech-debt
"metadata": { "status": "ACTIVE|RESOLVED" }, // security
"file_refs": ["path/to/file.java#L1-L10"],
"fix": { "kind": "atx-transform", "transform_name": "AWS/...", "effort": "Low" } | null } ]`remediation list --json` → flat array. repos is an OBJECT keyed by slug, NOT an array. Statuses are lowercase. PR URL is repos[<slug>].execution_artifacts.pr_url.
[ { "id": "01K...", "name": "...", "transform_name": "...",
"status": "succeeded|failed|in_progress|pending|cancelled|...", // lowercase
"started_at": "...", "completed_at": "...", "finding_ids": [...],
"repos": {
"<source>::<slug>": {
"status": "succeeded|failed|...", // lowercase
"transform_name": "...", "finding_id": "...",
"execution_artifacts": { "pr_url": "https://..." },
"error": "..." }
} } ]Normalization
Findings. findingId=id, repositoryId=repo, severity, analysisType=analysis_type, category, title, fileRefs=file_refs, fix={transformName: fix.transform_name} (only if set). Status: for security analyses use metadata.status === 'ACTIVE' → open; for everything else use the top-level status (default open if missing).
Analyses. id, analysisType=analysis_type, status, repos, startedAt=started_at, completedAt=completed_at, failureReason=failure_reason. To compute findingsCount, build a map first: findingsByAnalysisId = groupBy(findings, f => f.analysis_id). Manual findings carry analysis_id of the form "manual:<id>" — also key by the unprefixed <id> so manual analyses match. Then findingsCount = (findingsByAnalysisId[analysis.id] || []).length. Drop analyses with status `null` (the literal string) — these are integ-test artifacts that don't belong in the report.
Remediations. Convert repos (object) to repoStatuses (array):
// raw: r.repos = { "<slug>": { status, execution_artifacts: { pr_url }, error } }
// normalized: r.repoStatuses = [{ slug, status, executionRefs: { prUrl }, error }, ...]
const repoStatuses = Object.entries(r.repos || {}).map(([slug, rs]) => ({
slug,
status: rs.status,
executionRefs: { prUrl: rs.execution_artifacts?.pr_url },
error: rs.error,
}));Top-level fields: id, name, transformName=transform_name, status (lowercase), repos = Object.keys(raw.repos), findingIds=finding_ids, startedAt=started_at, completedAt=completed_at.
Scoping with --repo <source>::<slug>
If --repo <source>::<slug> was passed, scope the report to that repo:
- Replace
findings list --jsonwithfindings list --repo <source>::<slug> --json. - Filter analyses client-side to those whose
repos[]includes the slug. - Filter remediations client-side to those whose
reposinclude the slug.
If a list is empty (no remediations yet, no analyses yet), skip that section entirely — don't render an empty placeholder.
Flow
Step 1: Gather data
Verify server health, then run the CLI calls above to load the five entity arrays (sources, repositories, analyses, findings, remediations). Normalize per the shape rules above so the renderer can stay simple.
Step 2: Assemble the HTML
Generation runs in a subagent — never inline in the main loop. Producing this report is iterative: write a Python generator, run it, hit a JSON-shape mismatch or a Chart.js misconfig, fix, rerun. When that work happens inline, every Write/Edit/Bash retry is visible to the user and the run reads as broken. Delegating to a single subagent keeps all of it private — the user only sees the API calls (Step 1) and the final HTML (Step 3).
Save the raw JSON before dispatching. Persist the five Step 1 outputs to ~/.atxct/shared/reports/raw/<UNIX-TIMESTAMP>/ as sources.json, repositories.json, analyses.json, findings.json, remediations.json (mkdir -p first). The subagent reads them off disk, not from the prompt — JSON for a real account is too large to pass inline.
Dispatch one subagent. Inputs:
- The five JSON paths above.
- Output path:
~/.atxct/shared/reports/continuous-modernization-report-<UNIX-TIMESTAMP>.html(mkdir -pfirst). - A pointer to this skill — it reads "Raw response shapes," "Normalization," and "Sections" as its spec.
- Approach hint: write a Python generator (more reliable HTML escaping than inline JS templates), run it, validate the HTML file is non-empty and opens, then return.
The subagent's return value is ONE of:
{"path": "<absolute path>", "summary": "<one line worth highlighting, e.g. '1 analysis failed', '3 PRs ready for review'>"}{"error": "<one sentence reason>"}— only after exhausting reasonable retries (3–4).
Anything else it learned mid-run — intermediate errors, retry counts, scripts written and discarded, JSON-shape surprises — is dropped on the floor and never relayed to the parent or the user.
HTML output requirements (the subagent must satisfy these):
- The
<title>element and the main<h1>MUST both be exactlyAWS Transform - continuous modernization Report— note "continuous modernization" is lowercase, "AWS Transform" stays capitalized. Do not paraphrase or substitute the product name. - Chart.js loaded via CDN:
<script src="https://cdn.jsdelivr.net/npm/chart.js@4"></script> - All CSS inlined in a
<style>block - All data inlined as JS
constdeclarations (SOURCES,REPOSITORIES,ANALYSES,FINDINGS,REMEDIATIONS) — JSON-stringified, then safe-escaped before embedding: replace</with<\/(a finding's text containing literal</script>will otherwise close the data block and break the page) and strip U+2028 / U+2029 (valid in JSON, illegal as JS string literals). Verify by counting</script>in the output — expected exactly 2 (Chart.js CDN closer + inline data closer); more means a payload broke containment. - No
fetch()calls — the report must open offline
Use a clean modern look: light theme, system font stack, generous whitespace, ~1100px max-width centered. Severity colors: high #dc2626, medium #f59e0b, low #10b981.
Step 3: Open the report
open ~/.atxct/shared/reports/continuous-modernization-report-<timestamp>.htmlTell the user the path and what's in the report.
Step 4: Clean up the raw JSON dir
The HTML report has all data baked in — once Step 3 succeeds, the raw JSON files at ~/.atxct/shared/reports/raw/<UNIX-TIMESTAMP>/ are no longer needed:
rm -rf ~/.atxct/shared/reports/raw/<UNIX-TIMESTAMP>/Sections (top to bottom)
Each section renders only if its data is non-empty.
Snapshot header
KPI cards across the top, one number per entity:
[ N sources ] [ N repos ] [ N analyses ] [ N open findings ] [ N remediations ]No chart. Counts pulled from the lengths of each list (open findings = findings.filter(f => f.status === 'open').length).
Sources
Chart: horizontal bar — repos per source. Cap the chart at top 15 sources by repo count
Drilldown table — top 25 sources by repo count, not all of them. Note the total count above the table and link to atx ct source list for the full set.
| Name | Provider | Identifier | Repos |
|---|
Fields (normalized): name (raw: source), provider, identifier, repos_count (computed from repository list).
Repositories
Chart: doughnut — language distribution (group by language, count repos). Cap at top 12 languages; bucket the tail under "other" if needed. Treat missing language as "unknown".
No table by default — repo lists get too long. Mention that atx ct repository list shows the full table.
Fields (raw → normalized): slug, language, default_branch → defaultBranch, has_workflow, source.
Analyses
Drop analyses with `status === "null"` (literal string) before charting or counting. These are integ-test artifacts and would dominate the chart.
Chart: stacked bar by analysis_type, segments = status (complete, running, failed, cancelled, pending).
Tooltip configuration is mandatory: stacked bars in this chart can have segments that are pixel-thin (e.g., agentic-readiness with 3 entries next to tech-debt with 7,000). Default Chart.js hover requires the cursor to land inside the segment, which is unusable at that scale. Apply:
options: {
interaction: { mode: 'index', intersect: false },
plugins: {
tooltip: {
mode: 'index',
intersect: false,
filter: (item) => item.parsed.y > 0, // hide zero-count rows
itemSort: (a, b) => b.parsed.y - a.parsed.y, // largest first
},
},
scales: { x: { stacked: true }, y: { stacked: true, beginAtZero: true } },
}Hovering anywhere over a column then surfaces every non-zero segment, sorted by count.
Drilldown table — most recent 10 by startedAt desc:
| ID (short) | Type | Status | Repos | Findings | Duration |
|---|
- Short ID: first 8 chars of
id. - Findings count: looked up from the precomputed
findingsByAnalysisIdmap (NOT a field on the analysis row). - Duration:
completedAt - startedAtformatted (e.g. "2m 14s"). Blank if still running. - For
failedrows, renderfailureReasonas a tooltip or expandable row.
Fields (raw → normalized): id, analysis_type → analysisType, status, repos, started_at → startedAt, completed_at → completedAt, failure_reason → failureReason. findingsCount is computed via the join described in Normalization.
Findings
Two charts side-by-side:
1. Bar — severity counts. Use status === 'open' only. Only include severity buckets that have at least one finding — don't render zero-count columns. Iterate ['high','medium','low'] in that order, filter to non-zero, then plot. 2. Doughnut — analysis-type split (quick-scan, tech-debt, security, agentic-readiness, custom, manual). Same rule: only include types with at least one finding.
Severity enum is `high | medium | low`. There is no `critical`.
Two drilldown tables:
Top risks — group open findings by title, sort by repo count desc, take top 10:
| Title | Severity | Repos affected | Auto-fix? |
|---|
Auto-fix? = whether fix.transformName is set on any finding in the group.
Top auto-fix transforms — group findings whose fix.transformName is set, by transform name:
| Transform | Findings | Repos | Auto Remediable |
|---|
Built-in? = whether the transform name starts with AWS/. Customer-namespace transforms (anything else) render as ❌.
Fields: findingId, repositoryId, severity, status, analysisType, category, title, fileRefs, fix.transformName.
Remediations
Statuses are lowercase (succeeded, completed, complete, failed, in_progress, pending, cancelled, running) — never pattern-match against uppercase.
Trends chart (cumulative line)
Replace any "by aggregate status" bar with a cumulative line chart over time. Three series:
1. Total created — every remediation, keyed by startedAt date. 2. Succeeded with PR — remediations whose top-level status is in {succeeded, complete, completed} AND at least one repo has a non-null executionRefs.prUrl. Keyed by completedAt date (fall back to startedAt if missing). This is the strict definition of success — a transform can be marked completed without producing a PR (e.g., target version already met, or PR-publish step failed after a clean run). Only "with PR" represents real code in flight, so it's the only success line worth charting. 3. Failed — remediations with top-level status === "failed". Keyed by completedAt date (fall back to startedAt).
Bucket by ISO date (startedAt.slice(0, 10)), accumulate day by day, sort labels ascending.
const SUCCESS = new Set(['succeeded', 'complete', 'completed']);
const hasPR = r => (r.repoStatuses || []).some(rs => rs.executionRefs?.prUrl);
// per-day buckets: { created, succeededWithPR, failed }
// then cumulative running totals across sorted daysChart configuration:
type: 'line', three datasets in this order: Total created (blue, filled area), Succeeded with PR (green), Failed (red).interaction: { mode: 'index', intersect: false }and matching tooltip mode so a single hover surfaces all three series for that day.- Y-axis:
beginAtZero: true, ticks formatted withNumber.toLocaleString(). - X-axis: ISO date strings,
maxRotation: 0,autoSkip: true. - Legend at bottom.
Below the chart, render a one-line summary: date range, succeeded-with-PR count and rate, failed count.
Recent remediations with PRs
Cap at 15 most recent (by startedAt desc) where at least one repo has a PR URL. Note the total remediation count below.
Drilldown — one card per remediation:
<Name> · <transformName> · <aggregate status>
N repos: X succeeded · Y failed · Z in progress
PRs:
• <repo-slug> → <prUrl>
• <repo-slug> → <prUrl>
...
Failures:
• <repo-slug>: <error>PR URLs come from repoStatuses[<repoSlug>].executionRefs.prUrl (also accept transform_pr_url for older entries). Render as <a href="..."> so they're clickable.
Fields: id, name, transformName, status (aggregate), repos, repoStatuses (per-repo: status, executionRefs.prUrl, error, startedAt, completedAt), findingIds.
Tone
Data-driven. The HTML is the deliverable. After Step 3, your reply is ONLY:
1. The output path. 2. A 1–2 sentence summary, sourced from the subagent's summary field (e.g. "1 analysis failed", "3 PRs ready for review").
Never relay subagent iteration state to the user. No retry counts, no "I fixed an issue with X," no narration of intermediate scripts or errors. The visible surface across the whole run is: the Step 1 API calls, the Step 3 open command, and these one or two sentences. Nothing in between.
If the subagent returned {"error": ...}, surface that one sentence — don't try to redo the work inline (that would re-leak every retry).
Security Agent Setup
This skill covers the security agent lifecycle with a clear split between admin (infrastructure provisioning) and executor (runtime analysis) roles.
⚠️ MANDATORY: Permission Consent (MUST be first interaction)
CRITICAL: Before ANY security agent setup or analysis steps, present this consent message and wait for a response.
"To run security analysis, the executor role needs access to: SecurityAgent APIs (for code review and findings), the security agent S3 bucket (for uploading source code to scan), and iam:PassRole for the security agent role. Do you have these permissions configured?"
- If the customer says yes → proceed with the executor flow.
- If the customer says no → respond with: "If you don't have sufficient permissions you may encounter errors during the flow. Your administrator can set up the required resources using the Admin Setup commands below." Then proceed with the workflow.
Record the customer's response -- if they later file a bug about permission errors, we refer to their choice here.
---
Admin Setup (Manual Terminal Commands)
These commands create IAM roles and deploy CloudFormation stacks, so they require admin/role-creation permissions (`iam:CreateRole`, `iam:PutRolePolicy`, `iam:PassRole`, `cloudformation:CreateChangeSet`). Run them with an admin identity. Read-only or runtime credentials are enough for everything afterward.
The agent MUST NOT execute these commands using agentic tools. Instead, present them as instructions for the customer or their administrator to copy and run.
The admin provisions the security agent infrastructure: an IAM role, a managed policy, and an S3 bucket, all deployed via a CloudFormation stack.
Tell the customer:
"This deploys the security agent infrastructure (IAM role, S3 bucket, CloudFormation stack). It requires admin/role-creation permissions. Run it with an admin identity. Read-only or runtime credentials are enough for everything afterward."
>
For reference, the executor policy this skill expects is in https://github.com/awslabs/agent-plugins/blob/main/plugins/aws-transform/skills/aws-transform/references/AWSTransformSecurityAgentExecutorAccess.json
# Ensure atx ct is installed and up to date
INSTALLED=$(atx ct --version 2>/dev/null | head -1)
LATEST=$(curl -fsSL "https://transform-cli.awsstatic.com/index.json" 2>/dev/null | grep -o '"latest"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"latest"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/')
echo "Installed: ${INSTALLED:-not found}, Latest: ${LATEST:-unknown}"
# If not installed or outdated:
curl -fsSL "https://transform-cli.awsstatic.com/install.sh" | bash
source ~/.bashrc
# Start the server if not running
atx ct server &
sleep 5
# Deploy security agent infrastructure (creates IAM role, S3 bucket, CloudFormation stack)
atx ct setup security-agentWhat Admin Setup Creates
| Resource | Name Pattern | Purpose |
|---|---|---|
| CloudFormation stack | kct-security-agent-<suffix> | Manages all resources atomically |
| IAM role | security-agent-kct-agent-space-<suffix> | Role the security agent service assumes |
| IAM managed policy | kct-security-agent-<suffix> | Permissions attached to the role |
| S3 bucket | kct-security-agent-<suffix> | Stores source code zips for scanning |
Admin Setup for EC2/Batch Job Roles
When using security analysis on EC2 or Batch, the admin must also attach executor permissions to the compute role. Present these commands as instructions:
"The compute role needs security agent permissions added. This modifies IAM policies, so it requires admin/role-creation permissions. Run these with an admin identity:"
For Batch (ATXBatchJobRole):
# Get security agent config values
SEC_BUCKET=$(jq -r '.s3Bucket' ~/.atxct/shared/security_agent_config.json)
SEC_AGENT_ROLE_ARN=$(jq -r '.role_arn // .roleArn' ~/.atxct/shared/security_agent_config.json)
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
# 1. Security Agent API access
aws iam put-role-policy --role-name ATXBatchJobRole \
--policy-name AtxCtSecurityAgentAPI \
--policy-document "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":[\"securityagent:ListAgentSpaces\",\"securityagent:CreateAgentSpace\",\"securityagent:CreateCodeReview\",\"securityagent:StartCodeReviewJob\",\"securityagent:ListCodeReviewJobsForCodeReview\",\"securityagent:ListFindings\",\"securityagent:BatchGetFindings\",\"securityagent:StartCodeRemediation\"],\"Resource\":\"arn:aws:securityagent:*:*:agent-space*\",\"Condition\":{\"StringEquals\":{\"aws:ResourceAccount\":\"${ACCOUNT_ID}\"}}}]}"
# 2. S3 access for security agent bucket
aws iam put-role-policy --role-name ATXBatchJobRole \
--policy-name AtxCtSecurityAgentS3Access \
--policy-document "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":[\"s3:PutObject\",\"s3:GetObject\",\"s3:ListBucket\"],\"Resource\":[\"arn:aws:s3:::${SEC_BUCKET}\",\"arn:aws:s3:::${SEC_BUCKET}/*\"]}]}"
# 3. PassRole for security agent role
aws iam put-role-policy --role-name ATXBatchJobRole \
--policy-name AtxCtSecurityAgentPassRole \
--policy-document "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":\"iam:PassRole\",\"Resource\":\"${SEC_AGENT_ROLE_ARN}\",\"Condition\":{\"StringEquals\":{\"iam:PassedToService\":\"securityagent.amazonaws.com\"}}}]}"For EC2 (stack-managed role):
SEC_BUCKET=$(jq -r '.s3Bucket' ~/.atxct/shared/security_agent_config.json)
SEC_AGENT_ROLE_ARN=$(jq -r '.role_arn // .roleArn' ~/.atxct/shared/security_agent_config.json)
STACK_NAME="<the-ec2-stack-name>"
REGION="${AWS_REGION:-us-east-1}"
ROLE_NAME=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --region $REGION \
--query 'Stacks[0].Outputs[?OutputKey==`RoleArn`].OutputValue' --output text | awk -F/ '{print $NF}')
# 1. Security Agent API access
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
aws iam put-role-policy --role-name "$ROLE_NAME" \
--policy-name AtxCtSecurityAgentAPI \
--policy-document "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":[\"securityagent:ListAgentSpaces\",\"securityagent:CreateAgentSpace\",\"securityagent:CreateCodeReview\",\"securityagent:StartCodeReviewJob\",\"securityagent:ListCodeReviewJobsForCodeReview\",\"securityagent:ListFindings\",\"securityagent:BatchGetFindings\",\"securityagent:StartCodeRemediation\"],\"Resource\":\"arn:aws:securityagent:*:*:agent-space*\",\"Condition\":{\"StringEquals\":{\"aws:ResourceAccount\":\"${ACCOUNT_ID}\"}}}]}"
# 2. S3 access to the security agent bucket
aws iam put-role-policy --role-name "$ROLE_NAME" \
--policy-name AtxCtSecurityAgentS3Access \
--policy-document "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":[\"s3:PutObject\",\"s3:GetObject\",\"s3:ListBucket\"],\"Resource\":[\"arn:aws:s3:::${SEC_BUCKET}\",\"arn:aws:s3:::${SEC_BUCKET}/*\"]}]}"
# 3. PassRole for security agent role
aws iam put-role-policy --role-name "$ROLE_NAME" \
--policy-name AtxCtSecurityAgentPassRole \
--policy-document "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":\"iam:PassRole\",\"Resource\":\"${SEC_AGENT_ROLE_ARN}\",\"Condition\":{\"StringEquals\":{\"iam:PassedToService\":\"securityagent.amazonaws.com\"}}}]}"Check Admin Setup Status
atx ct setup security-agent --statusReturns: configured, setup_in_progress, failed, or not_configured.
Delete (Teardown)
atx ct setup security-agent --delete---
Executor Flow (Agent-Driven)
This is what the agent does at runtime after admin setup is complete. The agent MAY execute these steps using agentic tools.
Step 1: Verify Security Agent is Configured
Check that the security agent config file exists:
cat ~/.atxct/shared/security_agent_config.jsonIf the file does NOT exist: Try to reconstruct it from the existing CloudFormation stack before asking the customer to re-run admin setup. This allows any team member with AWS account access to self-service without needing the original admin.
Reconstruct Config from Existing Stack
# Find the security agent stack (tagged during admin setup)
STACK_NAME=$(aws cloudformation describe-stacks \
--query "Stacks[?Tags[?Key=='atx-remote-infra' && Value=='true']].StackName" \
--output text --no-cli-pager --region us-east-1)
# If not found by tag, try prefix match
if [ -z "$STACK_NAME" ]; then
STACK_NAME=$(aws cloudformation list-stacks \
--stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE \
--query "StackSummaries[?starts_with(StackName,'kct-security-agent-')].StackName" \
--output text --no-cli-pager --region us-east-1)
fi
echo "Found stack: ${STACK_NAME:-none}"If a stack is found, extract the config and write it locally:
# Extract parameters and outputs from the stack
ACCOUNT_ID=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --region us-east-1 \
--query "Stacks[0].Parameters[?ParameterKey=='AccountId'].ParameterValue" --output text --no-cli-pager)
AGENT_SPACE_NAME=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --region us-east-1 \
--query "Stacks[0].Parameters[?ParameterKey=='AgentSpaceName'].ParameterValue" --output text --no-cli-pager)
S3_BUCKET=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --region us-east-1 \
--query "Stacks[0].Parameters[?ParameterKey=='S3Resource'].ParameterValue" --output text --no-cli-pager)
ROLE_ARN=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --region us-east-1 \
--query "Stacks[0].Outputs[?OutputKey=='RoleArn'].OutputValue" --output text --no-cli-pager)
AGENT_SPACE_ID=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --region us-east-1 \
--query "Stacks[0].Outputs[?OutputKey=='AgentSpaceId'].OutputValue" --output text --no-cli-pager)
# Write the config file
mkdir -p ~/.atxct/shared
cat > ~/.atxct/shared/security_agent_config.json << EOF
{
"agentSpaceId": "${AGENT_SPACE_ID}",
"agentSpaceName": "${AGENT_SPACE_NAME}",
"s3Bucket": "${S3_BUCKET}",
"roleArn": "${ROLE_ARN}",
"accountId": "${ACCOUNT_ID}",
"stackName": "${STACK_NAME}",
"configuredAt": "$(date -u +%Y-%m-%dT%H:%M:%S.000Z)"
}
EOF
cat ~/.atxct/shared/security_agent_config.jsonIf no stack is found: Tell the customer:
"Security agent is not configured and no existing stack was found in this account. An administrator needs to run the initial setup:"
>
```bash
atx ct setup security-agent
```
>
"Once complete, let me know and I'll continue."
Do NOT proceed until the config file exists.
Step 2: Read Config Values
SEC_BUCKET=$(jq -r '.s3Bucket' ~/.atxct/shared/security_agent_config.json)
SEC_AGENT_ROLE_ARN=$(jq -r '.role_arn // .roleArn' ~/.atxct/shared/security_agent_config.json)
AGENT_SPACE_NAME=$(jq -r '.agentSpaceName' ~/.atxct/shared/security_agent_config.json)
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)Step 3: Verify Executor Permissions (Read-Only Check)
For EC2/Batch compute roles, verify the required inline policies exist:
aws iam get-role-policy --role-name <ROLE_NAME> --policy-name AtxCtSecurityAgentAPI 2>&1
aws iam get-role-policy --role-name <ROLE_NAME> --policy-name AtxCtSecurityAgentS3Access 2>&1
aws iam get-role-policy --role-name <ROLE_NAME> --policy-name AtxCtSecurityAgentPassRole 2>&1If any returns `NoSuchEntity`: Do NOT add the policy. Instead, tell the customer:
"The compute role is missing security agent permissions. This requires admin/role-creation privileges to fix. Run the following with an admin identity:"
Then show the relevant commands from the Admin Setup section above.
Step 4: Sync Config to Compute (EC2 only)
For EC2, sync the security agent config into the container(s):
aws s3 cp ~/.atxct/shared/security_agent_config.json \
s3://atx-source-code-${ACCOUNT_ID}/temp/security_agent_config.json
ssm_run "aws s3 cp s3://atx-source-code-${ACCOUNT_ID}/temp/security_agent_config.json /tmp/sa.json && \
for c in \$(sudo docker ps --filter name=atx-ct --format '{{.Names}}'); do \
sudo docker cp /tmp/sa.json \$c:/home/atxuser/.atxct/shared/security_agent_config.json && \
sudo docker exec \$c chown 1000:1000 /home/atxuser/.atxct/shared/security_agent_config.json; \
done"
aws s3 rm s3://atx-source-code-${ACCOUNT_ID}/temp/security_agent_config.jsonStep 5: Proceed with Analysis
Once permissions are verified, proceed with the normal analysis flow using --type security.
The executor IAM policy required for runtime is documented in AWSTransformSecurityAgentExecutorAccess.json in the ATXControlTowerPolicies package.
---
Error Handling
| Error | Cause | Resolution |
|---|---|---|
Access denied calling Security Agent API | Missing AtxCtSecurityAgentAPI policy on compute role | Admin must add the policy (see Admin Setup) |
s3:PutObject access denied | Missing AtxCtSecurityAgentS3Access policy | Admin must add S3 policy |
iam:PassRole denied | Missing AtxCtSecurityAgentPassRole policy | Admin must add PassRole policy |
| Config file not found | Admin setup never ran | Admin must run atx ct setup security-agent |
not_configured status | Setup failed or never completed | Admin must re-run setup |
---
IAM Policy Reference
| Policy | File | Purpose | Who Uses It |
|---|---|---|---|
| Full admin + executor | AWSTransformSecurityAnalysisAccess.json | All permissions including CFN, CreateRole, CreateBucket | Administrator (setup) |
| Executor only | AWSTransformSecurityAgentExecutorAccess.json | Runtime permissions only: SecurityAgent API, S3 read/upload, PassRole | Compute role (EC2/Batch job role) |
Server
Supported Regions
AWS Transform - continuous modernization is available in these regions only:
| Region | Code |
|---|---|
| US East (N. Virginia) | us-east-1 |
| Europe (Frankfurt) | eu-central-1 |
| Asia Pacific (Mumbai) | ap-south-1 |
| Asia Pacific (Sydney) | ap-southeast-2 |
| Asia Pacific (Tokyo) | ap-northeast-1 |
| Europe (London) | eu-west-2 |
| Asia Pacific (Seoul) | ap-northeast-2 |
| Canada (Central) | ca-central-1 |
Region Selection
Before starting the server, ask the user which region they want to use if they haven't already specified one, (render this menu as plain numbered markdown text in your response and wait for the user to type a choice; do NOT route it through any structured choice/picker tool like AskUserQuestion in Claude Code, or any equivalent multi-select/option UI in other harnesses):
"Which AWS region do you want to use? AWS Transform - continuous modernization supports: us-east-1, eu-central-1, ap-south-1, ap-southeast-2, ap-northeast-1, eu-west-2, ap-northeast-2, ca-central-1."
If the user provides a region not in the supported list, let them know it isn't supported and suggest us-east-1 as the default:
"That region isn't supported by AWS Transform - continuous modernization. Would you like to use us-east-1 (US East, N. Virginia) instead?"Once confirmed, set ATX_REGION to the chosen region.
Start
AWS_REGION=$ATX_REGION atx ct server &Stop
pkill -f "atx ct server"Restart
pkill -f "atx ct server"; AWS_REGION=$ATX_REGION atx ct server &Check if running
atx ct status --healthSetup
CRITICAL Prerequisites
Use `atx ct` (with a space) when invoking AWS Transform - continuous modernization (continuous modernization) commands. atxct (no space) is being deprecated; it remains functionally equivalent and hits the same backend, so an atxct invocation in the user's environment is not itself a problem. Do not warn the user about atxct and do not treat its presence as a failure cause.
Step 1: Install or update atx ct
Run this single command to check install status AND version in one shot:
INSTALLED=$(atx ct --version 2>/dev/null | head -1)
LATEST=$(curl -fsSL "https://transform-cli.awsstatic.com/index.json" 2>/dev/null | grep -o '"latest"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"latest"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/')
echo "Installed: ${INSTALLED:-not found}, Latest: ${LATEST:-unknown}"If INSTALLED is empty OR LATEST is newer than INSTALLED → reinstall:
curl -fsSL https://transform-cli.awsstatic.com/install.sh | bash
source ~/.bashrc # or ~/.zshrcIf both are the same → atx ct is up to date, proceed to Step 2.
Verify: atx ct --help must show CT subcommands.
Step 2: Start the server
The atx ct CLI requires a running server. Before any other command, start it:
atx ct server &
sleep 5
atx ct status --healthIf atx ct status --health returns a connection error, the server isn't running. Check atx ct server output for errors.
After installation, restart your shell or run source ~/.bashrc (or ~/.zshrc) to update PATH.
Security Agent
See continuous-modernization-security-agent.md for the full security agent setup (admin) and runtime verification (executor) flow.
Quick reference (admin commands, run manually in terminal):
# Set up security agent
atx ct setup security-agent
# Check status
atx ct setup security-agent --status
# Remove
atx ct setup security-agent --deleteBehavior
- If
atx ctis not installed, install it using the curl command above before proceeding. - If
atx ctis installed but a newer version is available, reinstall it using the same curl command. - If already configured, returns the existing config immediately.
- If not configured, kicks off async provisioning and returns immediately. Use
--statusto check progress. --statuschecks current state:configured,setup_in_progress,failed, ornot_configured.--deletetears down AWS resources (CloudFormation stack, S3 bucket, config).- Requires valid AWS credentials (
aws sts get-caller-identitymust succeed). - If credentials are expired, ask the user to refresh them first (
ada credentials update).
Status
Prerequisites
Check if the server is running with atx ct status --health. If any command fails with a connection error, use the server skill to start the server.
Commands
atx ct status [--source <name>]Results Synthesis
Generate a single summary file after bulk transformations complete.
Output
Write one file: ~/.aws/atx/custom/atx-agent-session/transformation-summaries/transformation-summary-$SESSION_TS.md
mkdir -p ~/.aws/atx/custom/atx-agent-session/transformation-summariesImportant: Do NOT use heredoc (cat << EOF) to write this file — heredoc blocks can hang in shell environments. Use a command (ex. printf '%s') to write the content.
Template
# AWS Transform Summary
> Completed: <timestamp>
> Repositories: <total> | Succeeded: <count> | Failed: <count>
## Results
| Project | Transformation | Status | Notes |
| ------- | --------------------- | ---------------- | ------------ |
| <name> | <transformation-name> | Succeeded/Failed | <brief note> |
## Failed Transformations
### <project-name>
- **TD**: <td-name>
- **Error**: <one-line error summary>
- **Suggested Fix**: <recommendation>
## Next Steps
1. Review changes in each transformed repo
2. Run tests and deployPresentation
Tell the user:
Results: <succeeded>/<total> succeeded, <failed> failed
Summary: ~/.aws/atx/custom/atx-agent-session/transformation-summaries/transformation-summary-$SESSION_TS.mdFor remote mode executions, also include the CloudWatch dashboard link:
REGION=${AWS_REGION:-${AWS_DEFAULT_REGION:-$(aws configure get region 2>/dev/null)}}
REGION=${REGION:-us-east-1}
echo "CloudWatch Dashboard: https://${REGION}.console.aws.amazon.com/cloudwatch/home#dashboards/dashboard/ATX-Transform-CLI-Dashboard"Related skills
FAQ
What migrations does AWS Transform support?
It transforms .NET Framework to .NET 8/10, mainframe COBOL to Java, VMware VMs to EC2, SQL Server to Aurora, and upgrades Java, Python, Node.js, and AWS SDK versions.
When should I not use it?
Do not use it for infrastructure provisioning, CI/CD pipelines, or general coding tasks.