bedrock-migrate
One command migrates a Python repository's inference from a supported provider to Amazon Bedrock — same model, new host. It scans the repository, rewrites the inference calls, adds a small runtime helper, and opens a pull request.
- Hosted providers (Fireworks, Together AI, OpenRouter, Groq, Mistral AI, xAI, DeepSeek) migrate to Bedrock's OpenAI-compatible Chat Completions API — no Bedrock SDK required
- Model IDs are rewritten to their Bedrock IDs (e.g.
accounts/fireworks/models/kimi-k3→global.moonshotai.kimi-k3, orus.moonshotai.kimi-k3with--us-only) - Fine-tuned models, dedicated deployments, and non-inference APIs are detected and left untouched
Requirements
- Python 3.9+
- A git repository for the branch/commit/PR flow (or
--no-gitto skip git entirely) - To open the PR: the
ghCLI or a git credential helper with a GitHub token - At deploy time: an AWS role with
bedrock:InvokeModelandbedrock:InvokeModelWithResponseStreamfor each migrated inference profile
Installation
pip install bedrock-migrate
Or run it once without installing:
uvx bedrock-migrate migrate --pr
# or
pipx run bedrock-migrate migrate --pr
Quick start
cd path/to/your-repo
bedrock-migrate migrate --pr
On a git repository with a clean working tree, this checks out the branch bedrock-migrate, rewrites every migratable inference call site, adds the helper/config/dependencies, writes a migration report, pushes the branch, and opens a pull request.
Commands
bedrock-migrate scan [PATH] [--json]
bedrock-migrate migrate [PATH] [options]
PATH defaults to the current directory.
scan — report without changing anything
Lists every inference touchpoint and how it would be handled:
bedrock-migrate scan . --json
migrate — apply the migration
| Option | Effect |
|---|---|
--pr |
push the branch and open a pull request |
--us-only |
target us. inference profiles instead of each model's default profile |
--region <REGION> |
default region recorded in f2b.json (default us-east-1) |
--map SRC=TGT |
map a source model ID to a Bedrock model ID (repeatable; use PROVIDER:SRC=TGT to disambiguate the provider) |
--json |
machine-readable output on stdout |
--no-git |
skip branch/commit/push (no git required) |
What it migrates
| Call site | Before | After |
|---|---|---|
| Model ID | accounts/fireworks/models/kimi-k3 |
KIMI_K3 (global.moonshotai.kimi-k3) |
| OpenAI client | OpenAI(base_url="https://api.fireworks.ai/inference/v1") |
get_llm_client() |
| Async OpenAI | AsyncOpenAI(base_url=...) |
get_async_llm_client() |
| Fireworks SDK | Fireworks(...) / AsyncFireworks(...) |
get_llm_client() / get_async_llm_client() |
| Fireworks LLM | LLM(model=...) |
get_llm_client().bind(KIMI_K3) |
| LangChain | ChatFireworks(...) |
ChatOpenAI(..., **langchain_kwargs()) |
| Raw HTTP | requests.post("https://api.fireworks.ai/...") |
flagged for review; helper client suggested |
Model coverage is data-driven: any source ID in spec/models.json is rewritten to its Bedrock target (for example meta-llama/Llama-3.3-70B-Instruct-Turbo → us.meta.llama3-3-70b-instruct-v1:0). The LiteLLM spelling fireworks_ai/accounts/fireworks/models/kimi-k3 is rewritten too.
What it leaves alone
These are detected, left untouched, and listed in the report and f2b.json:
- Fine-tuned / uploaded models —
accounts/<account>/models/<name>where<account>is notfireworks - Models Bedrock does not host — they stay on their source provider
- Dedicated deployments — Baseten, Modal, Replicate (migrate only with an explicit
--map) - Non-inference APIs —
fine_tuning,datasets,deployments,rerank,embeddings,batch,audio,image_generation - LoRA adapters
Files it adds to your repository
| File | Purpose |
|---|---|
llm_client.py |
runtime helper, co-located with the migrated files |
f2b.json |
per-model backend routing (repo root) |
requirements.txt |
adds openai and aws-bedrock-token-generator (boto3 only if a model routes to converse) |
BEDROCK_MIGRATION.md |
full change log, what was left alone, IAM policy, rollback |
How the runtime helper works
llm_client.py keeps the OpenAI shape, so migrated call sites do not change:
from llm_client import get_llm_client, KIMI_K3
client = get_llm_client()
resp = client.chat.completions.create(model=KIMI_K3, messages=[...])
Each model is routed at runtime by f2b.json:
| Backend | Meaning |
|---|---|
openai-compatible |
Bedrock's OpenAI-compatible Chat Completions API (default) |
converse |
Bedrock Converse API via boto3, OpenAI shape translated on the fly |
a provider id (e.g. fireworks) |
keep that model on its source provider (passthrough / rollback) |
Bedrock requests authenticate with a short-lived token generated from the ambient AWS credentials (aws-bedrock-token-generator). The default backend uses the OpenAI-compatible endpoint (/openai/v1) rather than the Converse API, so no Bedrock SDK is required. Blocked and unmapped model IDs are recorded in f2b.json at migration time and stay on their source provider.
Classification and exit codes
Each finding is classified MIGRATE, BLOCK, or REVIEW. REVIEW items — for example a client whose base_url is assembled at runtime, or a model ID built from an f-string — need a decision before deploy and are listed in the report and in the JSON review_items field.
| Exit code | Meaning |
|---|---|
0 |
migration applied (and PR opened with --pr) |
2 |
invalid command line |
20 |
nothing to migrate, or already migrated |
30 |
environment problem (not a directory, dirty working tree, or checkout failed) |
JSON output
scan --json and migrate --json each emit one JSON document:
{
"version": "0.0.2",
"repo": "/abs/path/to/repo",
"language": "python",
"branch": "bedrock-migrate",
"pr_url": "https://github.com/acme/repo/pull/12",
"findings": [
{
"class": "MIGRATE",
"file": "app/llm.py",
"line": 14,
"kind": "openai_client",
"detail": "OpenAI(base_url=fireworks) -> get_llm_client()"
}
],
"checks": [],
"review_items": [],
"exit_code": 0
}
checks is reserved for future automatic verification and is empty today.
Rollback
Set F2B_BACKEND=<source-provider> (for example F2B_BACKEND=fireworks) to route back to the source provider with no code change.
Idempotency
Running migrate on an already-migrated repository is a no-op and exits 20.
For AI coding agents
An agent driving this CLI should read AGENTS.md — the full contract: commands, flags, exit codes, the JSON schema, and the f2b.json routing config. TL;DR: run scan --json first, then migrate --json.
License
Apache-2.0
Release files for bedrock-migrate 0.0.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| bedrock_migrate-0.0.2.tar.gz | 24.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| bedrock_migrate-0.0.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 54.2 kB
Release files / bedrock_migrate-0.0.2.tar.gz
| Download URL | bedrock_migrate-0.0.2.tar.gz |
|---|---|
| Size | 24.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
33e6fdb7fcedb2330340da515987e44fa3df8c57b1dd74bdeff37b4e2ed0d909
|
|
BLAKE2b-256 checksum How to use checksums |
d8a523a129e255e9ab3eea3c490f387a88964fe1ca0de42c5efff5bbd4d312c5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|
Release files / bedrock_migrate-0.0.2-py3-none-any.whl
| Download URL | bedrock_migrate-0.0.2-py3-none-any.whl |
|---|---|
| Size | 29.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b851f01bb4c4048f4b2cfa1756317fba285c65b0c405c00dffcc0fa4c37ec8b0
|
|
BLAKE2b-256 checksum How to use checksums |
245f8528bc072d4d9dadce08c82e71c0160e5677756f99c9c6890b3c7203e498
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|