Skip to content

Name each generated SDK with BAML's package_name; move to BAML 0.25.1 - #6

Merged
rossirpaulo merged 4 commits into
mainfrom
rossirpaulo/generated-package-name
Nov 6, 2026
Merged

rossirpaulo merged 4 commits into
mainfrom
rossirpaulo/generated-package-name

Conversation

@rossirpaulo

@rossirpaulo rossirpaulo commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Adopts BAML's package_name generator 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) and examples/coexistence/run.sh. scripts/generate.sh also 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-level baml_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.

Language package_name Result
Python alien_sdk._generated the wheel holds only alien_sdk/; _gen.py imports the SDK relatively
Go alienapi package alienapi, sdk_import_path = ".../go/alienapi"
Rust alien_api crate alien_api
TypeScript generated generated/ (built to dist/generated)
  • Facades import the new names, including the alien_sdk.platform / alien_sdk.manager re-exports from Adopt BAML's new generated names; typed Python facade (TASK-111); re-export pydantic models (TASK-116) #4.
  • The genops tools no longer hard-code the name. Go's reads the one module package the facade imports (so the facade's hand-written files must import exactly one package of the module; the README says so). Rust's reads the facade's one path dependency. Python's already followed _gen.py. bench/run.py reads package_name from baml.toml.
  • The wheel leaves out BAML's bookkeeping files (.gitignore, .baml-generator-output*). The generated package is listed as artifacts by file type, because a directory artifact would pull those files in and exclude can't remove them.
  • scripts/generate.sh removes old sdk/*/baml_sdk output, which BAML only warns about, and only if baml generate created it (it has BAML's ownership marker). Otherwise it stops with an error.

Moving to BAML 0.25.1

  • BAML_PIN is 0.25.1 and BAML_COMMIT_PIN is unset. Every manifest and lockfile uses the 0.25.1 runtime packages, and the Cargo lockfiles take baml_bridge from crates.io again.
  • The toolchain check also accepts wrapper 0.3's --version output (baml-cli 0.25.1), since Homebrew now ships wrapper 0.3.1.
  • The README drops the temporary canary-build setup it said to remove before sharing with Alien. 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 now describe 0.25.1.
  • pnpm-workspace.yaml exempts the 0.25.1 bridge packages from pnpm's minimum release age, because they were published today.
  • The BAML release itself: 0.25.1 is on npm, PyPI, crates.io and the Go proxy. Its canary channel promotion was skipped because of a release-workflow bug (fix: Read the toolchain version from wrapper 0.3's --version output in the release docs job baml#5556), so baml toolchain update on 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-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 instead 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

rossirpaulo and others added 2 commits November 4, 2026 23:31
…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]>
rossirpaulo and others added 2 commits November 5, 2026 21:46
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]>
@rossirpaulo rossirpaulo changed the title Name each generated SDK with BAML's package_name; Python SDK inside alien_sdk Name each generated SDK with BAML's package_name; move to BAML 0.25.1 Nov 6, 2026
@rossirpaulo
rossirpaulo merged commit f2c3307 into main Nov 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant