The situation
A platform team maintains a mid-sized codebase: a few dozen services, a shared internal SDK, and a house style that every new file is expected to follow. They want to add code assistance in several places. Developers want in-editor completions and a chat window that knows the repo. A migration project needs a service translated from Java to Kotlin. The support rota wants a bot that explains a failing stack trace and drafts a fix. And a reviewer wants a first pass over each pull request that flags the obvious problems before a human looks.
They have two shapes of answer on AWS and they keep conflating them. One is to call a capable foundation model on Amazon Bedrock and build the feature themselves: their own prompts, their own retrieval, their own surface in whatever tool they choose. The other is to adopt the managed assistant purpose-built for coding, which already ships in-IDE completions, a chat pane, and agentic tasks, so there is nothing to build. On AWS that product is Kiro, an agentic development environment, an IDE and a CLI, built around spec-driven development.
The instinct is to pick one for everything. That is the trap. The completions-in-the-editor job and the review-bot-in-the-pipeline job want different things, and one of them is a product you install while the other is a feature you write.
What actually matters
The first thing worth naming is the difference between adopting an assistant and building a feature. Kiro is a finished product: it lives in the IDE and the terminal, does inline completions and multi-turn chat, plans work from a specification, and takes on agentic tasks that span several files, a version upgrade included. If what you want is developers getting help while they work, you are buying that, not building it, and building it would be reconstructing a product AWS already ships. If what you want is code assistance welded into your own application, a custom review comment on a pull request, a fix drafted inside your support tool, then Kiro’s surfaces are the wrong shape and you want a model you drive yourself on Bedrock.
Second is how much the output has to know your code specifically. A general foundation model is excellent at language mechanics: idiomatic syntax, common libraries, translating between languages, explaining an error. What it does not know is your internal SDK, your naming conventions, the helper that every service is supposed to call instead of rolling its own. Ungrounded, it will invent plausible APIs that do not exist in your repo, which is worse than useless because it looks right. Grounding the model in the real codebase with retrieval, so the prompt carries the actual signatures and the actual house patterns, is what turns generic-but-fluent into useful-here. Kiro has its own repo-awareness story; a custom Bedrock feature needs you to build the retrieval.
Third is context. A single-function completion needs almost none. Reviewing a whole file, translating a service, or reasoning across several modules needs a lot of code in the window at once, so the model’s context length becomes a real constraint. Whole-file and multi-file work wants a model with a large context window; a tight completion does not, and paying for a huge context you never fill is just cost.
Fourth is determinism. Code generation is one of the places where you usually want the boring, expected answer, not a creative one, so a low temperature earns its place: it makes the output more repeatable and less inclined to wander into an unusual construction. Explanation and brainstorming can tolerate more variety; the code that gets committed should not.
And the axis that outranks the rest, generated code is untrusted until it is checked. A model will produce code that compiles and reads well and is quietly wrong, or worse, quietly insecure: a hardcoded credential, a SQL string built by concatenation, a dependency with a known vulnerability. Never run generated code unchecked. It goes through the same gates as human-written code, static analysis and dependency scanning, and it is evaluated by running the tests, not by measuring how similar the text looks to a reference. A snippet that scores well on string similarity and fails the test suite is a failure; a snippet that looks nothing like the reference and passes every test is a success. Text similarity measures the wrong thing for code.
What we’ll filter on
- Build or adopt, are you writing code assistance into your own application, or giving developers an assistant in their editor?
- Repo grounding, does the output have to use your real internal APIs and conventions, or is generic-but-correct enough?
- Context need, single function, whole file, or across several modules at once?
- Determinism, does this path want the repeatable expected answer, or room to explore?
- Validation, how is the generated code checked, scanned, and test-run before anyone trusts it?
The landscape
A general foundation model on Bedrock. A capable model called through the Bedrock API handles the full spread of code tasks: generation, completion, explanation, translation between languages, and review. You own the prompt, the temperature, the surface, and the integration, which is exactly what you want when the feature lives inside your own application rather than an editor. The cost is that you build everything around the call, and out of the box the model knows programming in general but not your repo in particular.
A foundation model plus retrieval (RAG over the codebase). The same Bedrock model, but the prompt is assembled from a retrieval step that pulls in the relevant real code: the actual function signatures, the internal SDK usage, the house pattern for this kind of file. Now generation uses APIs that exist instead of inventing them, and new code matches how the codebase already does things. This is the difference between a fluent stranger and someone who has read your repo. It is more to build, an index over the code, a retrieval step in the request, and it is what makes a custom feature actually fit your project.
Kiro. The managed-assistant option: an agentic development environment (an IDE and a CLI) built around spec-driven development, where the assistant plans against a specification and works across files. It covers completions, chat about the code and about AWS, and multi-file agent tasks, with a version upgrade or a service migration run as a planned job rather than one completion at a time. You adopt rather than build, time-to-value is short, and the trade is the standard finished-product one: its surfaces are the ones it ships, a developer’s assistant rather than a component you weld into your own product’s back end.
Large-context models for whole-file and repo work. Within the Bedrock choice, model selection matters for the size of the job. Translating a service or reviewing a full file means holding a lot of code in the window at once, so a model with a large context window is the enabling piece; for single-line completion it is capacity you pay for and never use.
The guardrail and evaluation layer around all of it. Independent of which model or product, generated code passes through review, static analysis, and dependency and secret scanning before it runs, and it is evaluated by executing tests rather than scoring text similarity. Amazon Bedrock Guardrails can filter the model’s inputs and outputs at the content level, but code-specific safety is the job of your existing code-scanning tools; the model does not get a pass on the checks a human contributor would face.
Side by side
| Approach | Build or adopt | Knows your repo | Big-context jobs | Own-app surface | Ready in-IDE |
|---|---|---|---|---|---|
| Bedrock foundation model | Build | ✗ (generic) | Model-dependent | ✓ | ✗ |
| Bedrock model + codebase RAG | Build | ✓ | Model-dependent | ✓ | ✗ |
| Kiro | Adopt | ✓ (managed) | ✓ | ✗ | ✓ |
| Large-context model on Bedrock | Build | Via RAG | ✓ | ✓ | ✗ |
Reading the table against the team’s four jobs: in-editor completions and chat are the managed assistant, adopt Kiro and move on. The pull-request review bot and the stack-trace-explaining support bot live inside the team’s own tools, so they are Bedrock features, grounded with retrieval over the repo. The Java-to-Kotlin migration can go either way, a spec-driven agent task in Kiro, or a large-context Bedrock model driven file by file if the migration needs bespoke handling.
The picks in depth
In-editor help is the managed assistant. Completions as developers type, a chat pane that answers questions about the code and about AWS, and version upgrades run as planned agent tasks are exactly what the assistant ships. Rebuilding that on raw Bedrock would mean reconstructing an editor integration and a completion loop that already exist as a supported product. Adopt Kiro, point it at the repositories, and the time-to-value is a setup task rather than a build.
The review bot and the support bot are custom Bedrock features. Both live inside the team’s own systems, a comment on a pull request, a reply in the support tool, so there is no editor surface to reuse; the value is in the integration you write. Call a capable model on Bedrock, and ground it with retrieval so the review understands the internal SDK and the fix drafts against APIs that exist. Run these at low temperature: a code review and a suggested fix want the repeatable, expected answer, not an inventive one. Put Bedrock Guardrails on the content boundary if the input includes untrusted text, and keep the model’s output on the untrusted side of the fence until it has passed the same scanning a human’s code would.
Grounding is what separates useful from plausible. The failure mode of an ungrounded model on a private codebase is confident invention: it calls client.fetchUser() because that is what a hundred public projects do, and your SDK spells it users.get(). Retrieval over the codebase fixes this by putting the real signatures and the real house patterns in front of the model at generation time. Without it, a custom code feature spends its life being corrected; with it, the output fits the project. This is the same discipline as giving the model the right context instead of a longer instruction: the retrieval and the schema around the call decide as much as the wording does.
Validation is test execution, not text similarity. However the code is produced, the gate is the same. Static analysis and dependency and secret scanning catch the insecure patterns, the hardcoded credential, the vulnerable library, that read fine to a human skimming a diff. And quality is measured by running the tests: generated code that passes the suite is good regardless of how little it resembles a reference solution, and code that matches a reference closely but fails a test is not. Any evaluation harness for a code feature runs the code; it does not diff the strings.
A worked example: the pull-request review bot
The team wants a bot that comments on each pull request with a first-pass review before a human looks. It is inside their own pipeline, triggered by the PR event, posting through the code-host API, so it is a Bedrock feature, not an assistant surface.
The naive build sends the diff to a general model with “review this code” and posts whatever comes back. It reads well and it is frequently wrong about this repo: it flags the internal retry helper as a missing error check because it has never seen the helper, and it suggests a validation call that does not exist in the SDK. Plausible, and useless.
The grounded build assembles the prompt from retrieval. The changed files trigger a lookup that pulls in the real signatures they touch, the internal SDK functions in play, and the house convention for this kind of change, and those go into the context alongside the diff. Now the review is against the code as it actually is: it stops inventing the missing check because it can see the retry helper, and it references APIs that exist. The call runs at low temperature so two runs over the same diff give the same review rather than two different opinions. If the diff carries untrusted content, a Guardrails policy filters the boundary.
Then the safety gate, which is separate from the model entirely. The bot’s own suggestions, and the human’s code, both pass static analysis and secret and dependency scanning before anyone acts on them; a suggested fix that introduces a concatenated SQL string is caught by the scanner, not trusted because the model proposed it. And when the team wants to know whether the bot is any good, they do not score its comments against a golden review. They take a corpus of pull requests with known issues and measure how many real problems it flags and how many false alarms it raises, running the code where a suggestion is a change. The review bot is evaluated the way the code is: by what happens when you run it.
What’s worth remembering
- Two different projects hide under “code generation”: adopting the managed assistant (Kiro) and building a feature on a Bedrock foundation model. Decide which one the job actually is before choosing a model.
- In-editor completions, chat, and agent-run version upgrades are what the managed assistant ships; rebuilding them on raw Bedrock recreates a product that already exists.
- Code assistance inside your own application, a PR-review comment or a fix in your support tool, has no editor surface to reuse, so it is a custom Bedrock feature you write.
- A general foundation model knows programming but not your repo; ungrounded on a private codebase it invents plausible APIs that do not exist.
- Grounding the model with retrieval over the codebase, real signatures and house patterns in the prompt, is what turns fluent-but-generic into useful-here.
- Whole-file review, translation, and multi-module work need a large context window; a single-function completion does not, so do not pay for context you never fill.
- Code generation usually wants a low temperature, the repeatable expected answer, not a creative one; save the variety for explanation and brainstorming.
- Generated code is untrusted until checked: never run it unscanned, and put it through the same static analysis and dependency and secret scanning as human-written code.
- A model produces code that compiles, reads well, and is quietly insecure; the security gate is your existing code-scanning tools, and the model does not get a pass on them.
- Evaluate code features by executing tests, not by text similarity: passing the suite is success however little it resembles a reference, and matching a reference while failing a test is not.