Observed since 20 Oct, 21:20 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Pure-Python library and CLI for injecting GBA ROMs into 3DS CIA files, with custom Home Menu icons, banners, and sound.
A pure-Python library and CLI for injecting Game Boy Advance ROMs into installable 3DS CIA files — a free, open-source alternative to NSUI/vcoven — with custom Home Menu icons, animated banners, sound, and box art.
Everything is implemented from scratch in Python, cross-checked against public documentation (3dbrew, GBATEK) and the real behavior of existing open-source tools (bannertool, 3dstool, vcoven, pyctr, SPICA). No C/C++ binaries are bundled or shelled out to.
agbcia takes a GBA ROM and produces a .cia file you can install on a
real (or emulated) 3DS/2DS with any standard CIA installer. It supports two
independent ways of getting the GBA game to actually run once installed:
AGB_FIRM) — exactly the mechanism Nintendo's own GBA VC
releases use. This needs a one-time-extracted boot logo asset from a
GBA VC CIA you already own (see Getting the assets you'll need).Either way, you get to set your own title name, icon, animated banner, and banner sound — the same customization NSUI/vcoven-style injectors offer, built independently and kept in pure Python.
inject
step.boot9.bin/boot9_prot.bin).Published on PyPI:
# As a standalone CLI tool (recommended for most users):
pipx install agbcia
# or, with uv:
uv tool install agbcia
# As a library, into your own project:
uv add agbcia
pip install agbcia
To install straight from the repository instead (e.g. an unreleased
commit on main), replace agbcia above with
git+https://github.com/marco-zanella/agbcia.
To work on agbcia itself, see Development instead.
# One-time: extract the AGB_FIRM boot logo from a donor GBA VC CIA you own.
agbcia footer extract-logo --donor-cia donor.cia --boot9 boot9.bin --output logo.bin
# Native/Virtual Console-style mode:
agbcia inject native \
--rom game.gba --icon icon.png --banner-image banner.png --banner-sound banner.wav \
--boot-logo logo.bin --title-name "My Game" \
--title-id 0004000000f09900 --output game.cia
# Homebrew-emulator mode (no donor CIA/boot logo needed):
agbcia inject homebrew \
--rom game.gba --icon icon.png --banner-image banner.png \
--emulator-core mgba-3ds-forwarder.cia --title-name "My Game" \
--title-id 0004000012345678 --output game.cia
--title-id is always mandatory — agbcia never invents one for you (see
Command reference for why, and for the range it must
fall in for native mode).
Every command also accepts --help for the same information Typer
generates directly from the code, which is always the authoritative
source if this section and the CLI ever disagree.
agbcia inject nativeBuilds a complete AGB_FIRM/Virtual Console-style CIA.
| Flag | Required | Description |
|---|---|---|
--rom | yes | The GBA ROM to inject. |
--icon | yes | Home Menu icon image. |
--banner-image | yes | Home Menu banner image. |
--boot-logo | yes | Already-extracted AGB_FIRM boot logo (agbcia footer extract-logo). |
--title-name | yes | Display title shown on the Home Menu. |
--title-id | yes | 16-hex-digit title ID. Must be in Nintendo's real GBA VC range: 0004000000F???00 (only the F??? nibbles are free — see below). |
--output | yes | Where to write the finished .cia. |
--long-title | no | Long description shown on the bottom screen. Defaults to --title-name. |
--publisher | no | Publisher name shown on the bottom screen. Default: Homebrew. |
--banner-sound | no | Banner sound (WAV). A short silence is used if omitted. |
--donor-banner | no | A real GBA VC banner extracted from a donor CIA's ExeFS, to patch --banner-image onto instead of this project's own flat template. See The donor-banner feature. |
--bottom-badge | no | Bottom-screen badge image, patched onto a --donor-banner's own badge texture. Only applies alongside --donor-banner; left blank if omitted. |
--box-shell-color | no | RRGGBB hex color, patched onto a --donor-banner's box-shell texture. Only applies alongside --donor-banner; left as the donor's own color if omitted. |
--save-type | no | Override the auto-detected save type: none, eeprom, sram, flash512, or flash1m. |
--rtc / --no-rtc | no | Override the auto-detected real-time-clock presence. |
--product-code | no | Override the auto-derived product code (derived from the ROM's game code, e.g. CTR-P-BPEE; falls back to CTR-P-AGBC if the ROM has no 4-character game code). |
--title-version | no | TMD title version, default 0. Bump this on a reinstall over the same title ID — some installers/Application Manager treat an unchanged version as already up to date and skip replacing the installed content. |
Why --title-id has to fall in a specific range: the 3DS decides
whether to boot a title through AGB_FIRM's GBA-save-compatible path from
the title ID's own numeric value, not just its NCCH content. Title IDs
outside 0004000000F???00 fail to launch even with an otherwise
byte-for-byte correct CIA, so agbcia rejects them up front instead of
letting you find out on a console.
agbcia inject homebrewBuilds a complete CIA around an existing forwarder/emulator core. Same
flags as native above, except:
| Flag | Required | Description |
|---|---|---|
--emulator-core | yes, instead of --boot-logo | A full, already-working forwarder/emulator .cia (e.g. a compiled mGBA-3DS build). Its own .code/extended header are reused verbatim. |
--title-id | yes | 16-hex-digit title ID. Homebrew mode has no range restriction — it never boots through AGB_FIRM. |
--boot9 | no | Your ARM9 bootROM dump. Only needed if --emulator-core happens to be an encrypted donor CIA (rare). |
The GBA ROM is embedded into the built title's own RomFS, at a fixed path
(rom.gba) that this project defines as its own contract — the
--emulator-core binary itself has to be written to read the ROM from
there. This is not a wider 3DS/homebrew standard.
agbcia footer buildBuilds the GBA VC footer (the tail AGB_FIRM reads after a ROM, describing
ROM size and save type) standalone — already done automatically inside
inject native.
| Flag | Required | Description |
|---|---|---|
--rom | yes | The GBA ROM. |
--output | yes | Where to write the footer. |
--save-type | no | Override the auto-detected save type. |
agbcia footer extract-logoExtracts the AGB_FIRM boot logo from a donor CIA — a one-time step whose
output gets reused for every future inject native run.
| Flag | Required | Description |
|---|---|---|
--donor-cia | yes | A donor GBA Virtual Console CIA you own. |
--boot9 | yes | Your ARM9 bootROM dump (boot9.bin/boot9_prot.bin). |
--output | yes | Where to write the extracted boot logo. |
agbcia banner buildBuilds a complete CBMD banner standalone — already done automatically
inside inject. Useful for previewing a banner without a full ROM/CIA
build.
| Flag | Required | Description |
|---|---|---|
--image | yes | Banner image. |
--output | yes | Where to write the banner. |
--sound | no | Banner sound (WAV). A short silence is used if omitted. |
agbcia icon buildBuilds a complete SMDH icon standalone — already done automatically inside
inject.
| Flag | Required | Description |
|---|---|---|
--image | yes | Icon image. |
--title-name | yes | Display title used across every language slot. |
--output | yes | Where to write the icon. |
--save-data / --no-save-data | no | Whether the title uses save data (sets FLAG_SAVE_DATA). Default: --no-save-data. |
agbcia rom info / detect-save-type / detect-rtcInspect a GBA ROM without building anything. Each takes the ROM path as a plain positional argument (no flag).
agbcia rom info game.gba
# title: MY GAME
# game_code: BPEE
# maker_code: 01
# checksum_valid: True
# save_type: flash1m
# rtc_present: True
agbcia rom detect-save-type game.gba # -> flash1m
agbcia rom detect-rtc game.gba # -> True
agbcia cia infoShows a CIA's single content's NCCH header fields — works on any CIA, not just this project's own output.
agbcia cia info game.cia
# title_id: 0004000000f09900
# product_code: CTR-P-BPEE
# no_crypto: True
# crypto_method: 0x0
# exheader: present
# exefs: present
# romfs: present
# logo region: present
agbcia keys verifyChecks that a file is a genuine boot9 dump agbcia can use.
agbcia keys verify boot9.bin
# valid boot9 dump (prot)
By default, inject's banner is this project's own flat, non-animated
CBMD template with your image glued onto it — simple, and works
everywhere, but visually plain next to a real GBA VC title's rotating 3D
box.
Pass --donor-banner (extracted from a real GBA VC title's own CIA — see
below) and agbcia instead reuses that donor's entire banner scene byte
for byte (its 3D mesh, skeleton, rotation animation, materials, and
shaders), patching only:
--donor-banner);--bottom-badge), left blank
if omitted, instead of showing the donor's own game's name;--box-shell-color), left as the
donor's own color if omitted.--box-shell-color is intentionally solid-color-only, not an arbitrary
image: the box-shell texture's UV mapping wraps around the whole 3D box in
a panoramic, non-obvious way (most of the texture stretches across the
sides, a thin strip covers the top/bottom, and the front is nearly
degenerate since it's covered by the box-art decal anyway) — a flat color
renders correctly there, but a photo or logo would come out visibly warped
around every rounded edge.
Any real GBA VC banner can be used as the donor, independent of which ROM you're actually injecting.
None of the following are provided by this project — they're either your own hardware's key material or something you dump from a title you legitimately own, exactly once, and then reuse locally forever after.
boot9.bin/boot9_prot.bin (your console's ARM9 bootROM dump):
needed to extract a boot logo for native mode, and to decrypt an
encrypted homebrew donor CIA. Dumped from a real console you own, using
standard, widely-documented 3DS homebrew tools (e.g. boot9strap +
a dumping homebrew app). agbcia keys verify checks a dump is usable.agbcia footer extract-logo.banner entry from
any real GBA VC donor CIA's ExeFS (e.g. with
ctrtool or
3dstool) and pass the resulting file to
--donor-banner. See The donor-banner feature.src/agbcia/
formats/ generic 3DS container formats: CIA, NCCH, ExeFS, RomFS, TMD,
ticket, SMDH, CBMD/CGFX, CWAV (read + write)
crypto/ AES/RSA/SHA, keys.bin parsing, key derivation
banner/ banner/icon/sound authoring
gba/ GBA-specific logic (footer, save-type/RTC detection, AGB_FIRM,
emulator-core packaging)
inject/ high-level pipeline, public API surface
cli/ Typer CLI, thin wrapper over the above
formats/, crypto/, and banner/ are deliberately GBA-agnostic; gba/
depends on them, never the reverse.
uv sync --all-extras --dev
uv run pytest
uv run ruff check .
uv run ruff format --check .
uv run mypy src
The same four checks run in CI on every push/PR (see
.github/workflows/ci.yml).
--box-shell-color sets a flat color only, not an arbitrary image (see
The donor-banner feature for why).No third-party binaries are bundled or shelled out to, but getting the byte-level format details right leaned heavily on public documentation and existing open-source implementations:
agbcia.crypto.test_pki, used across the 3DS homebrew ecosystem to produce genuinely-valid, non-Nintendo signatures on self-built CIAs.gbafix — the GBA header checksum formula reference.GPL-3.0-or-later — see LICENSE.
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.1.3 | 11 Aug 2026 | 3 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 21:20 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:c92c6d98c11a2ce6c06c57c35c160dd0b336942ad41f0e59c5cf71ae257ca6fb