Repository navigation
Name each generated SDK with BAML's package_name; move to BAML 0.25.1 - #6
Merged
Merged
Conversation
…lien_sdk Every generated package used to be `baml_sdk`. Installing the Python SDK wrote a top-level `baml_sdk/`, which any other BAML-generated SDK in the same environment overwrote, or was overwritten by (TASK-122). BAML's new `package_name` generator setting names each SDK, set in baml/baml.toml (placeholder names; Alien picks the real ones): - Python: `alien_sdk._generated`. The alien-sdk wheel now holds only `alien_sdk/`; `_gen.py` imports the generated SDK relatively. - Go: package `alienapi` (sdk_import_path .../go/alienapi). - Rust: crate `alien_api`. - TypeScript: directory `generated/` (dist/generated). The genops tools no longer hard-code the name: Go's reads the one module package the facade imports, Rust's the facade's one path dependency (with the `toml` crate), and Python's already followed `_gen.py`. bench/run.py reads package_name from baml/baml.toml. generate.sh removes stale sdk/*/baml_sdk output, which BAML only warns about. The coexistence repro now builds the real wheel, checks it holds only alien_sdk, installs it with a second SDK (top-level baml_sdk) in both orders, checks every installed file of both against its RECORD hash, and uninstalls each again. Two SDKs in one process still share one runtime (the one started last owns it; TASK-121): docs/gaps.md B4 now splits the fixed install collision from that open problem. In Python the shared runtime also holds the owner's type map, so a call through the other SDK with a generated-class argument now fails with a TypeError rather than silently running the other project's function. BAML_COMMIT_PIN moves to cf9b6339 (package_name, on top of canary 8eb462d8 with #5526 and #5527); sdk/rust/Cargo.lock and bench/rust/Cargo.lock follow. Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Pin BAML a227dbf39d (package_name with the review fixes). - generate.sh removes an old sdk/*/baml_sdk only if baml generate created it. - The wheel leaves out BAML's bookkeeping files in alien_sdk/_generated/. - README: the Go facade imports exactly one package of the module. Co-Authored-By: Claude Opus 5.5 <[email protected]>
meefs
pushed a commit
to meefs/baml
that referenced
this pull request
Nov 5, 2026
…me (BoundaryML#5532) ## Why Every generated SDK is a package named `baml_sdk`. In Python that's a top-level package in site-packages, so two libraries that each ship a BAML-generated SDK overwrite each other on install, and uninstalling one deletes the other's code. Alien hit this (they ship `alien-sdk` and their users also use BAML), and they want their SDK to carry their own name. ## What changes A new optional generator setting, `package_name`, names the generated SDK in the target language's terms and picks its directory under `output_dir`. **Omitting it leaves every generator's output byte-for-byte unchanged** (default `baml_sdk`). This PR accepts it for Python, as a dotted import path. Go, Rust and TypeScript follow in the stacked PR; every other target rejects the setting for now. ```toml [generator.python] output_type = "python/pydantic" output_dir = "src" # the import root package_name = "my_app._generated" # written to src/my_app/_generated ``` BAML creates missing parent directories but never writes or edits `my_app/__init__.py`. ### Generated Python no longer names its own package So the same output imports correctly at any path: - `_typemap.py` and `_function_registry.py` derive module paths from their own `__name__` (`_SDK_PACKAGE = __name__.rpartition(".")[0]`), built once per module as constants. - Only the root `__init__.py` resolves the `experimental` and `trace` shortcuts; it no longer compares `__name__` with `"baml_sdk"`. ### Safety A configurable directory makes the output writer riskier: it overwrites colliding files and replaces the root `.gitignore` with `*`. So when `package_name` is set, `baml generate` refuses an existing, non-empty directory that lacks the writer's ownership marker (`.baml-generator-output-root`). This also applies under `--output-dir`. Leftovers such as `__pycache__` and `.DS_Store` don't count, nor does a `.gitignore` identical to the one BAML writes (a fresh clone of a project that commits it holds only that file). The error names the entry that blocks it. Every named destination is checked before any generator writes, so a refusal never leaves a partial run. Without `package_name`, behaviour is unchanged. When a renamed SDK leaves earlier `<output_dir>/baml_sdk` output behind, `baml generate` warns that it's no longer updated. It never deletes it. ### Validation Each segment must be an ASCII identifier, not a Python keyword, and not a reserved Windows file name (`con`, `aux`, `COM1`, ...). The top-level segment can't shadow the runtime or its dependencies (`baml_bridge`, `pydantic`, `pydantic_core`, `typing_extensions`, `google`) or a standard-library module (`typing`, `json`, `asyncio`, ...). Nested names such as `my_app.pydantic` are fine. ### Not in scope - **One process still holds one BAML program.** Two generated SDKs imported into the same process replace each other's program. This PR fixes the install collision, not the runtime one (TASK-121), and the README says so. - `baml-bridge` is still pinned to an exact version, so two SDKs built with different BAML versions still can't be installed together. - Older CLIs only warn about the unknown `package_name` key and generate `baml_sdk`. ## Tests - `baml_cli`: validation (keywords, runtime shadowing, Windows names, nested names allowed), output location, the ownership guard (including under `--output-dir` and with leftovers only), the stale-output warning, and unchanged output without the setting. - `sdk_tests`: `test_relocated_package_python_only.py` loads the generated SDK nested in an application package and as a copy under another name, each in a fresh interpreter, and exercises both type-map directions and the root-only `trace`/`experimental` shortcuts. - Keyword docs (`baml describe generator`) and the Python SDK README document the setting. ## Review Fable 5.1 and GPT-6 Astra (extra high) reviewed both PRs. No directional changes; their findings are applied (the guard under `--output-dir`, runtime-shadowing names, Windows names, leftovers). Stacked PR: BoundaryML#5533 (Go, Rust and TypeScript). Adopted in BoundaryML/alien-baml-sdk#6. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> <!-- coderabbit-ai-generated:v1 --> ## Summary by CodeRabbit * **New Features** * Python SDKs can be generated under a custom package name, including nested import paths. The default remains `baml_sdk`. * Generated Python SDKs can be imported from their package location without relying on a fixed package name. * `--output-dir` selects the exact destination for generated files, overriding configured output locations and package-name nesting. * **Bug Fixes** * Generation now avoids overwriting unrelated files in an occupied destination and warns when a previous default output location will no longer be updated. * Custom package names are validated, and unsupported targets report a diagnostic. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
BAML 0.25.1 has package_name (BAML #5532, #5533) and every other change the SDKs took from canary, so the scripts use the published release again: BAML_PIN 0.25.1, BAML_COMMIT_PIN unset, every manifest and lockfile on the 0.25.1 runtime packages, and crates.io's baml_bridge in the Cargo lockfiles. - The toolchain check also accepts wrapper 0.3's `baml-cli <version>` output (Homebrew now ships wrapper 0.3.1). - The README drops the temporary canary-build setup; building against an unreleased BAML commit stays as an optional section. - docs/runtime.md, docs/gaps.md, docs/errors.md and the conformance and coexistence READMEs describe 0.25.1. - pnpm-workspace.yaml excludes the 0.25.1 bridge packages from pnpm's minimum release age, which they are younger than. Verified with scripts/verify.sh --phase 2 and examples/coexistence/run.sh against the published 0.25.1, and generate.sh with wrapper 0.2.4 and 0.3.1. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adopts BAML's
package_namegenerator setting (BoundaryML/baml#5532 and #5533, TASK-122), and moves the repository to the published BAML 0.25.1, which has it. The scripts no longer need a local BAML build.Verified against the published 0.25.1 with no local BAML build:
scripts/verify.sh --phase 2(48 checks pass) andexamples/coexistence/run.sh.scripts/generate.shalso runs with both the 0.2.4 and 0.3.1 Homebrew wrappers.scripts/verify.sh --phase 2 # ==> BAML 0.25.1 (release)Why
Every generated package was
baml_sdk. Installing the Python SDK wrote a top-levelbaml_sdk/, which any other BAML-generated SDK in the same environment overwrote (or was overwritten by), and uninstalling one deleted the other's code. Alien also wants its SDKs to carry its own names.What changes
Each SDK is named in
baml/baml.toml. The names are placeholders; Alien picks the real ones.package_namealien_sdk._generatedalien_sdk/;_gen.pyimports the SDK relativelyalienapialienapi,sdk_import_path = ".../go/alienapi"alien_apialien_apigeneratedgenerated/(built todist/generated)alien_sdk.platform/alien_sdk.managerre-exports from Adopt BAML's new generated names; typed Python facade (TASK-111); re-export pydantic models (TASK-116) #4._gen.py.bench/run.pyreadspackage_namefrombaml.toml..gitignore,.baml-generator-output*). The generated package is listed as artifacts by file type, because a directory artifact would pull those files in andexcludecan't remove them.scripts/generate.shremoves oldsdk/*/baml_sdkoutput, which BAML only warns about, and only ifbaml generatecreated it (it has BAML's ownership marker). Otherwise it stops with an error.Moving to BAML 0.25.1
BAML_PINis 0.25.1 andBAML_COMMIT_PINis unset. Every manifest and lockfile uses the 0.25.1 runtime packages, and the Cargo lockfiles takebaml_bridgefrom crates.io again.--versionoutput (baml-cli 0.25.1), since Homebrew now ships wrapper 0.3.1.docs/runtime.md,docs/gaps.md,docs/errors.mdand the conformance and coexistence READMEs now describe 0.25.1.pnpm-workspace.yamlexempts the 0.25.1 bridge packages from pnpm's minimum release age, because they were published today.baml toolchain updateon canary doesn't offer it yet. Installing the exact version, which the scripts do, works.Coexistence
The coexistence example now builds the real wheel, checks it holds only
alien_sdk, installs it next to a second SDK (top-levelbaml_sdk) in both orders, checks every installed file of both against its RECORD hash, and uninstalls each again.Two SDKs in one process still share one runtime (the one started last owns it; TASK-121).
docs/gaps.mdB4 now splits the fixed install collision from that open problem. In Python the shared runtime also holds the owner's type map, so a call through the other SDK with a generated-class argument now fails with aTypeErrorinstead of silently running the other project's function.Review
Fable 5.1 and GPT-6 Astra (extra high) reviewed this together with the BAML PRs. No directional changes. Applied here: the guarded stale cleanup, the wheel exclude, and the Go genops note.
🤖 Generated with Claude Code