The demo repo
I built a small throwaway repo called drift-and-debt — three services, three languages, each written to look like a few years of "we'll fix it later":
lambda-python/— a cost-reporting Lambda on boto3 1.17 (2021-era), with hardcoded AWS keys, a SQL query built with string concatenation, aneval()call on user input, and a wildcard IAM policynode-service/— a reporting proxy on Node 12 (end of life), using the deprecatedrequestlibrary, blocking file I/O on every request, and a reflected XSS holejava-module/— a reporting utility usingVectorandHashtable, string-concatenated SQL, and an O(n²) total calculation nobody ever noticed
None of this runs anywhere. It exists to be scanned. If it looks familiar, it's because most of us have inherited a repo exactly like one of these three at some point — the difference is I put all three flavors of drift in one place on purpose.
Installing the Power
The AWS Transform Power's listing in Kiro describes it plainly: migrate, modernize, and upgrade codebases — .NET Framework to .NET 8/10, mainframe COBOL to Java, VMware to EC2, SQL Server/Oracle/MySQL to Aurora, and Java/Python/Node.js version upgrades or SDK migrations. It's a wide net — most teams won't touch half of what's in that tag list, but it tells you the Power isn't scoped to one narrow use case.
Kiro's own disclaimer on the same page is worth reading before you install anything: third-party Powers operate independently from the core Kiro service, and Kiro doesn't test or evaluate them across all use cases. Fair enough — you're about to hand this thing access to a real AWS account, so it's the right kind of caution to see up front rather than buried in a terms page.
I told Kiro I'd just installed it and wanted to use it. Instead of jumping straight in, it checked its own MCP configuration first, then explained the shape of the tool before touching anything: Discovery → Scope → Assessment → Requirements → Tasks → Execution, with an approval gate at each step.
That structure matters more than it sounds like it should. It means the agent isn't quietly making decisions in the background while I'm looking at something else — every stage is a checkpoint I can stop at. It noticed drift-and-debt sitting in the workspace and offered three starting points: discover the workspace, browse existing jobs, or jump straight to a known transform target. I picked discovery, since that's the honest starting point for any codebase you haven't looked at properly in a while.
Local discovery, no cloud connection needed
Kiro read all three components directly — cost_reporter.py, requirements.txt, iam-policy.json, server.js, package.json, ReportUtil.java — and built a findings table before touching AWS at all:
| Component | Language | Key signals |
|---|---|---|
lambda-python/ | Python 3 | boto3 1.17, hardcoded credentials, SQL injection, eval() on user input, MD5 hashing, wildcard IAM |
node-service/ | Node 12 | Express 4.16, deprecated request library, sync file I/O, XSS, callback pyramids |
java-module/ | Java | Raw JDBC with SQL injection, Vector/Hashtable, O(n²) logic, no resource management |
lambda-python and node-service came back HIGH risk, java-module MEDIUM. That's a reasonable call — the java module is a self-contained utility class, so a bug there has a smaller blast radius than a live Lambda handling cost data or an internet-facing proxy service.
What stood out to me here wasn't the individual findings — I planted all of them, so of course it found them. It's that a local scan, with zero cloud connection, correctly triaged severity across three completely different languages using nothing but static analysis of the files sitting in the workspace. That's already most of what a developer would spend a morning doing by hand, done in the time it took me to ask the question.
Connecting to AWS Transform
To go further — matching these findings against real orchestrator agents rather than just describing them — Kiro needed an actual connection to AWS Transform. It asked for an IAM Identity Center start URL and region.
I gave it the AWS Transform application URL instead of an IdC start URL — an easy mistake if you haven't set up Identity Center recently. Kiro caught it immediately, recognized the URL pattern didn't match what an IdC start URL looks like, and proposed an alternative on its own: authenticate with a session cookie instead, and walked me through pulling the exact cookie value from the browser's dev tools.
Before that got sorted, it also gave an honest fallback: keep going with local findings only, and reconnect whenever I was ready. Discovery had already been saved to disk, so nothing from the earlier scan was at risk of getting lost while I fixed the auth.
Once the cookie auth worked, Kiro queried the live AWS Transform service and pulled back the actual orchestrator agent catalog — not a curated list built for a demo. Alongside agents relevant to my repo, like runtime-upgrade and framework-migration, it also surfaced ones with nothing to do with Python, Node, or Java — a .NET assessment agent, a no-op test agent used for internal testing. Seeing irrelevant agents in the response was oddly reassuring. It meant I was looking at a real catalog query, not a hand-picked set of results shaped to look impressive.
It matched the three components against three relevant orchestrator agents — Runtime Version Upgrade, Framework Migration, and API/SDK Upgrade — and then asked which one I wanted to modernize, and waited.
I also opened the actual AWS Transform web console at this point, mostly out of curiosity about whether it would show the same state. It did — same account, same session, greeted by name. That settled a question I'd been curious about going in: the console isn't a separate, more capable path that Kiro Power is a lightweight alternative to. It's a second window into the same account and the same job state. Whatever you can do by clicking through the web app, I was doing conversationally from the editor.
Picking Node.js and choosing an execution path
I picked the Node.js service to actually modernize, since it had the clearest mix of runtime, dependency, and security issues to fix in one pass.
Trying the CLI path first, Kiro checked its own changelog — confirming support for nodejs-version-upgrade, nodejs-aws-sdk-v2-to-v3, and a dozen other transformation definitions — then hit a real platform constraint: the AWS Transform CLI needs WSL and doesn't run on native Windows, which is what I was on.
Rather than stopping there, it laid out two real options: set up WSL and continue with the CLI, or skip local tooling entirely and use the Managed Agents path instead — cloud-side assessment and remediation via the Runtime Version Upgrade agent, no local CLI required. I went with Managed Agents, mostly because setting up WSL mid-demo felt like a detour from the actual point of the exercise.
Setting up the job
Kiro laid out the plan before doing anything: create a workspace, create a job using the Runtime Version Upgrade agent targeting Node 20, upload the node-service/ source, then follow up with project details.
Before calling create_workspace, it stopped and asked permission — showing the exact MCP server, the tool name, and the arguments it wanted to send, and waited for an explicit trust/run decision rather than firing blind. The same gate showed up again later for upload_artifact. Every action that would actually touch my AWS account went through this same checkpoint, not just the first one.
The workspace showed up live in the AWS Transform console a moment later — same name, zero jobs at that point — which confirmed this wasn't a local simulation dressed up to look connected.
The job itself came back with status ASSESSING and a real job ID. Its very next move — sending a follow-up message with project specifics — got rejected outright: INSTRUCTIONS_REQUIRED, a protocol-level error requiring it to load the job's workflow instructions before doing anything else. I liked that this failed loudly instead of silently. AWS Transform is clearly enforcing a specific sequence on its side, not just trusting whatever the agent sends next.
Once past that, AWS Transform matched the job against real, named transformation definitions: AWS/nodejs-version-upgrade, which has a built-in parameter for the target version, and AWS/security-issue-fixer, tied explicitly to CWE-79 for the XSS finding and CWE-798 for the hardcoded secret. Naming the actual CWE class rather than saying "security issues" is a small detail, but it's the kind of specificity that tells you the underlying analysis is doing real work rather than pattern-matching keywords. It asked whether to run the runtime upgrade first or combine it with the security fixes. I told it to combine both in one pass, targeting Node 20 — no reason to split something this small into two jobs.
Uploading the source
Since there was still no CLI available on this machine, the agent needed the actual source code uploaded to the job rather than pulling it itself from anywhere.
It gave a real choice here too: upload the node-service folder directly, or point it at a git repository it could clone. It even showed me the git-clone-plus-CLI command sequence it would have used had I set up WSL earlier, purely so I could see what that alternate path looked like. I picked direct upload. The same trust gate from earlier showed up again before the upload ran, listing the real local file path and tagging both files as CUSTOMER_INPUT.
The assessment
The agent came back with a genuinely detailed report — not a one-line "found some issues" summary. Current state: Node 12 (EOL), Express 4.16.4, request 2.88.0 (unmaintained since 2020), roughly 50 lines of code across a single file, low complexity. Ten numbered issues, split cleanly across runtime and dependencies, code patterns, and security.
The transformation plan underneath it had real before-and-after mappings rather than vague descriptions: fs.appendFileSync becomes fs.promises.appendFile, the nested fs.readFile callback pyramid becomes async/await, request gets swapped for axios or native fetch, and the hardcoded API key moves to an environment variable.
It closed with an honest risk note, which is the part I'd trust most from any assessment tool: low blast radius given the single-file scope, no breaking API changes expected between the current and target Express versions, but no existing tests in this repo — so manual verification would be needed after the fact regardless of how clean the diff looked. That's not a caveat a marketing page would include. It's the kind of line you only get from something actually reasoning about the specific code in front of it.
*Repo: drift-and-debt — a deliberately broken polyglot demo built to test this. The console-side GitHub connection and auto-opened PR flow are a separate piece — coming next.*