Skip to content

Overhaul BAML language release pipeline - #3639

Merged
rossirpaulo merged 10 commits into
canaryfrom
paulo/baml-language-release-pipeline
Jun 3, 2026
Merged

rossirpaulo merged 10 commits into
canaryfrom
paulo/baml-language-release-pipeline

Conversation

@rossirpaulo

@rossirpaulo rossirpaulo commented Jun 2, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Overhauls the BAML language release path around the new wrapper/toolchain split.

  • adds the baml wrapper crate plus shared baml_release and stamped baml_version crates
  • replaces the alpha release workflows with a channel-aware release graph, PyPI publish workflow, dry-run manifests, and wrapper-only Homebrew/AUR publishing paths
  • moves language/toolchain version authority to baml_language/release.toml and scripts/baml-language-version
  • makes the VSIX platform-neutral, launches baml lsp through the wrapper, and adds LSP/playground compatibility metadata
  • adds curl/PowerShell installers, package-manager artifact generation scripts, and in-repo docs for install/release/toolchain behavior

Validation

  • pre-commit hooks passed, including:
    • cargo fmt
    • cargo stow
    • cargo clippy --workspace --all-targets --all-features -- -D warnings
    • YAML checks
  • actionlint .github/workflows/release-baml-language.yml .github/workflows/publish-python-pypi.yml .github/workflows/build-python-sdk.reusable.yaml
  • cargo check --manifest-path baml_language/Cargo.toml -p baml -p baml_release -p baml_cli
  • cargo test --manifest-path baml_language/Cargo.toml -p baml_release
  • scripts/baml-language-version check
  • scripts/baml-wrapper-version check
  • typescript2/app-vscode-ext: ./node_modules/.bin/tsc --noEmit

Release Follow-ups

Before enabling production publishes:

  • update or validate the PyPI trusted publisher binding for .github/workflows/publish-python-pypi.yml
  • verify scripts/install.ps1 on Windows/PowerShell
  • confirm production GitHub Actions secrets/OIDC paths for PyPI, AWS, Homebrew, and AUR
  • review whether the included TASK/* planning files should remain in the branch

Summary by CodeRabbit

  • New Features

    • New standalone baml wrapper/launcher with toolchain commands, self-update, IDE VSIX installer, per-project VS Code clients, and protocol/handshake compatibility.
  • Installers & Packaging

    • POSIX and Windows installers; Homebrew/AUR formula and packaging artifact generators; packaging adjusted to ship the wrapper binary.
  • Documentation

    • Expanded install, toolchain, release, maintainer, failure-modes, command-surface, migration, and merge-to-canary guides.
  • CI / Releases

    • Channel-aware release pipelines, release-plan stamping/manifest generation, reusable workflow inputs added, legacy alpha workflows removed; SDKs bumped to 0.11.0.

@vercel

vercel Bot commented Jun 2, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
beps Ready Ready Preview, Comment Jun 3, 2026 3:34pm
promptfiddle Ready Ready Preview, Comment Jun 3, 2026 3:34pm
promptfiddle2 Ready Ready Preview, Comment Jun 3, 2026 3:34pm

Request Review

@coderabbitai

coderabbitai Bot commented Jun 2, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 9c11c030-163e-4459-9536-184cea563904

📥 Commits

Reviewing files that changed from the base of the PR and between 4a5f660 and 4b0d3ae.

📒 Files selected for processing (2)
  • .github/workflows/build-python-sdk.reusable.yaml
  • .github/workflows/publish-python-pypi.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/publish-python-pypi.yml

📝 Walkthrough

Walkthrough

Adds canonical version stamping, a baml_release manifest/fetcher library, a new baml wrapper CLI with toolchain lifecycle and self-update, IDE/VSIX protocol and per-project clients, channel-aware release workflows and reusable build stamping, installers/package artifacts, TASK docs, and test/infra updates.

Changes

Wrapper and Release Pipeline Overhaul

Layer / File(s) Summary
Specifications and handoff docs
TASK/*, TASK/docs/*
Adds TASK docs (commands, failure modes, open questions, prior art, user paths, maintainer guides, merge playbook).
Canonical version model & stamping
baml_language/crates/baml_version/*, scripts/baml-language-version, baml_language/release.toml
Adds baml_version constants and rewrites release planning/stamping to produce release-plan.json and stamp multiple surfaces.
Release artifact fetcher & manifest model
baml_language/crates/baml_release/*
New crate with manifest types, supported-targets, checksum parsing/verification, safe archive validation/extract, and install logic with exclusive locks and tests.
Wrapper CLI and toolchain state
baml_language/crates/baml/*
Adds baml wrapper binary: selector resolution, manifest caching/TTL, toolchain install/use/update/list/uninstall, and self-update with atomic replace.
CLI IDE install and pack integration
baml_language/crates/baml_cli/src/ide_command.rs, .../pack_command.rs, .../main.rs
Adds baml-cli ide install (wrapped by baml ide install), editor discovery, active-VSIX install, direct-invocation warning, and delegates pack host fetching/validation to baml_release.
IDE client routing & protocol compatibility
typescript2/app-vscode-ext/src/*, baml_language/crates/bex_project/src/bex_lsp/*, pkg-playground/*, baml_language/crates/baml_lsp_server/src/*
Refactors extension to per-project LanguageClients, advertises toolchain/version/protocol/capabilities, adds WebSocket Hello handshake and playground compatibility gating.
Release workflows & reusable inputs
.github/workflows/release-baml-language.yml, .github/workflows/ci.yaml, .github/workflows/*build-*.reusable.yaml, .github/workflows/publish-python-pypi.yml
Adds channel-aware release workflow, updates CI canary/nightly validation, and forwards release_plan_json/source_sha into reusable build/publish workflows with early “Stamp release plan” steps.
Manifests, package artifacts, installers
scripts/baml-release-manifests, scripts/baml-package-manager-artifacts, scripts/install.sh, scripts/install.ps1, packaging/aur/*, tools/pkg_boundaryml_com/*
Generates toolchain/wrapper manifests, Homebrew/AUR artifacts, updates AUR PKGBUILDs to package the wrapper, adds POSIX/PowerShell installers with checksum/atomic replace and index update.
Supporting test & infra updates
baml_language/crates/baml_lsp2_actions_tests/*, .github/actions/setup-node/action.yml, various SDK files
Normalizes test expectation comparisons, minor test fixes, removes restrictive action input choices, and updates SDK/version constants across bridges and packages.

Sequence Diagram (release flow)

sequenceDiagram
  participant Planner as scripts/baml-language-version
  participant ReleaseWF as release-baml-language.yml
  participant BuildSDK as build-*-sdk.reusable
  participant PublishPyPI as publish-python-pypi.yml
  participant Host as pkg.boundaryml.com

  ReleaseWF->>Planner: plan / compute / stamp
  ReleaseWF->>BuildSDK: pass release_plan_json + source_sha
  BuildSDK->>BuildSDK: stamp release-plan.json
  ReleaseWF->>PublishPyPI: pre-check & publish wheels
  ReleaseWF->>Host: upload manifests & install scripts
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • BoundaryML/baml#3547: Overlaps on release workflow and packaging logic; both touch alpha-era release workflow handling.
  • BoundaryML/baml#3451: Related to scripts/baml-language-version parsing and version computation changes.
  • BoundaryML/baml#3529: Related to baml pack/pack host fetching behavior that this PR delegates into baml_release.

Poem

"I stamped the plan and chased a wheel,
Hopped through manifests, checksum and seal.
Toolchains tucked, VSIX in tow,
Wrapper hops — releases go.
Rabbity builds — a merry squeal!"

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch paulo/baml-language-release-pipeline

@vercel
vercel Bot temporarily deployed to Preview – beps June 2, 2026 16:26 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps June 2, 2026 16:35 Inactive
@github-actions

github-actions Bot commented Jun 2, 2026 •

Copy link
Copy Markdown

Binary size checks passed

✅ 7 passed

Artifact Platform File Gzip Gated on Baseline Delta Status
✅ baml-cli Linux 🔒 17.4 MB 7.4 MB file 24.1 MB -6.7 MB (-27.7%) OK
✅ packed-program Linux 🔒 12.7 MB 5.4 MB file 15.1 MB -2.4 MB (-16.1%) OK
✅ baml-cli macOS 🔒 13.3 MB 6.4 MB file 18.2 MB -4.9 MB (-27.0%) OK
✅ packed-program macOS 🔒 9.7 MB 4.7 MB file 11.5 MB -1.8 MB (-16.0%) OK
✅ baml-cli Windows 🔒 14.3 MB 6.6 MB file 19.6 MB -5.4 MB (-27.3%) OK
✅ packed-program Windows 🔒 10.2 MB 4.7 MB file 12.2 MB -2.0 MB (-16.7%) OK
✅ bridge_wasm WASM 11.6 MB 🔒 3.3 MB gzip 3.9 MB -580.9 KB (-15.0%) OK

🔒 = the size this artifact is GATED on (ceiling + delta). Binaries gate on file size (installed binary); WASM gates on gzip (download size). The other size is shown for information only.


Generated by cargo size-gate · workflow run

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
typescript2/app-vscode-ext/src/extension.ts (2)

194-226: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

knownProjects is global but now mutated per-client, breaking the multi-project model.

With per-project clients, every client overwrites the single global knownProjects on baml/listProjects (Line 223), and any client's Stopped transition clears it entirely (Line 204). With two BAML projects open, the status-bar tooltip will reflect only the last client to fire a notification, and stopping one project's server wipes the project list for the still-running ones.

Consider keying project lists per client (e.g. Map<projectRoot, string[]>) and aggregating for the tooltip, and on Stopped only removing that client's entry.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@typescript2/app-vscode-ext/src/extension.ts` around lines 194 - 226, The
global knownProjects array is being overwritten per-client and cleared on any
client's Stopped state; change knownProjects to a Map keyed by the
client/project root (e.g. Map<string, string[]>) so each client stores its own
project list, modify the 'baml/listProjects' handler to set
knownProjects.set(clientIdOrProjectRoot, params.projects ?? []), change the
onDidChangeState Stopped branch to remove only that client's entry
(knownProjects.delete(clientIdOrProjectRoot)) instead of clearing everything,
and update refreshTooltip() to aggregate across all Map values when rendering
the status-bar tooltip; use the client instance or its projectRoot as the unique
key to locate per-client entries.

312-317: ⚠️ Potential issue | 🟠 Major

Normalize projectPath from baml/listProjects before clients.get() in baml.openPlayground.

ListProjects sends project identifiers from projects.keys(); those roots are computed by get_baml_project_root(), which returns the baml_src/ directory itself when the project path’s filename is baml_src. The extension’s clients map is keyed by findBamlProjectRoot(), which only resolves to the nearest directory containing baml.toml (or workspace root). So clicking a tooltip entry where projectPath is a baml_src/... path won’t match any key and incorrectly shows “BAML Language Server is not running.” Update baml.openPlayground (or findBamlProjectRoot) to resolve/normalize server-provided project paths to the same key format used in clients.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@typescript2/app-vscode-ext/src/extension.ts` around lines 312 - 317, The
command handler registered as 'baml.openPlayground' is using the raw
server-provided projectPath to look up clients in the clients Map, but server
paths from baml/listProjects may point at baml_src/ and therefore won't match
keys created by findBamlProjectRoot(); fix by normalizing the incoming
projectPath with the same resolution logic used for client keys (call
findBamlProjectRoot(projectPath) or otherwise strip/resolve baml_src to the
project root) before doing clients.get(projectPath), so the lookup and the
activeClient() fallback use the same canonical project root; update the handler
around clients.get(...) (or update findBamlProjectRoot to accept server paths)
to perform this normalization.
🧹 Nitpick comments (7)
baml_language/crates/baml_cli/src/ide_command.rs (1)

26-32: ⚡ Quick win

Enforce --cursor/--code mutual exclusivity at clap parse time

IdeInstallArgs::resolve_editor currently does a runtime check (if self.cursor && self.code { ... }) and returns an anyhow! error after dispatch. Declaring the conflict in the clap derive surfaces the error during argument parsing with the standard usage message.

♻️ Example using conflicts_with
 #[derive(Args, Clone, Debug)]
 pub(crate) struct IdeInstallArgs {
-    #[arg(long)]
+    #[arg(long, conflicts_with = "code")]
     pub cursor: bool,
     #[arg(long)]
     pub code: bool,
 }

Then remove the self.cursor && self.code guard from resolve_editor.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@baml_language/crates/baml_cli/src/ide_command.rs` around lines 26 - 32, Add a
clap-level conflict so the parser rejects using both flags: annotate the
IdeInstallArgs fields to declare mutual exclusivity (use the clap attribute like
conflicts_with on the cursor and/or code fields) and then remove the runtime
check in IdeInstallArgs::resolve_editor that returns an anyhow error for
self.cursor && self.code; keep resolve_editor focused on resolving the Editor
and rely on clap to enforce the conflict at parse time.
baml_language/crates/bex_project/src/bex_lsp/protocol.rs (1)

1-10: 💤 Low value

Protocol constants/capabilities are duplicated across Rust and TypeScript.

These values mirror compat.ts (BAML_LSP_PROTOCOL_*) and the capability array in extension.ts (Line 172). They must be bumped in lockstep; a mismatch silently breaks compatibility negotiation. Consider a comment cross-referencing the TS counterpart, or a generated/shared source if this grows.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@baml_language/crates/bex_project/src/bex_lsp/protocol.rs` around lines 1 -
10, The protocol constants (BAML_LSP_PROTOCOL_VERSION,
BAML_PLAYGROUND_PROTOCOL_VERSION, MIN_SUPPORTED_VSCODE_LSP_PROTOCOL,
MIN_SUPPORTED_PLAYGROUND_PROTOCOL) and the CAPABILITIES array are duplicated in
TypeScript (compat.ts and extension.ts) and must be kept in sync; update this
Rust file by adding a clear comment above these declarations pointing to the
exact TypeScript counterparts (compat.ts for BAML_* values and extension.ts for
the capabilities list) and include a short TODO/instruction that any change here
must be mirrored in those TS files (or consider centralizing generation later)
so future maintainers will update both places atomically.
baml_language/crates/bex_project/src/bex_lsp/multi_project/request.rs (1)

80-89: ⚡ Quick win

Pin the initialize metadata with a unit test.

This experimental.baml payload plus server_info.version is now an IDE compatibility contract. A small unit test around server_capabilities() / on_request_initialize() would catch accidental key-name or version-source drift before it breaks the extension or playground wiring. As per coding guidelines, "Prefer writing Rust unit tests over integration tests where possible".

Also applies to: 148-152

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@baml_language/crates/bex_project/src/bex_lsp/multi_project/request.rs` around
lines 80 - 89, Add a unit test that pins the initialize metadata by asserting
the exact experimental.baml JSON payload and the server version returned by
server_capabilities() / on_request_initialize(); locate the experimental payload
construction in the multi-project initialize logic (the block that sets
experimental: Some(serde_json::json!({...}))) and the functions
server_capabilities() and on_request_initialize() and create a test that calls
those functions (or constructs the same payload path) and compares the resulting
JSON object and server_info.version against a hard-coded expected value to
detect accidental key/name or version-source drift; ensure the test lives
alongside the module as a standard Rust #[cfg(test)] unit test and fails on any
change to keys, values, or version constants.
.github/workflows/release-baml-language.yml (1)

66-69: ⚡ Quick win

Consider adding persist-credentials: false to checkout steps.

Multiple checkout steps in this workflow do not set persist-credentials: false. While the workflow does upload artifacts that could potentially include the .git directory, the default behavior of actions/checkout (persist-credentials: true) leaves the GitHub token in the git config, which could be extracted from artifacts or subsequent steps.

For defense-in-depth, consider adding persist-credentials: false to all checkout actions unless git operations (push/commit) are explicitly needed in that job. The jobs that do need credentials (publish-homebrew, publish-aur) appear to use dedicated secrets rather than the default token.

Also applies to: 160-160, 205-205, 255-255, 364-364, 467-467, 502-502, 552-552

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release-baml-language.yml around lines 66 - 69, Update
every actions/checkout@v4 step to include persist-credentials: false unless that
job intentionally needs GitHub token; specifically locate the checkout steps
(the uses: actions/checkout@v4 occurrences around the shown diff and also at the
other occurrences noted) and add the persist-credentials: false key alongside
ref and fetch-depth so the checkout does not leave the default token in the
checked-out repo; leave checkout entries in jobs that explicitly require
pushing/committing unchanged if they truly need credentials.
.github/workflows/publish-python-pypi.yml (1)

33-36: 💤 Low value

Optional: Workflow-level id-token: write may be redundant.

The publish-to-pypi job (lines 57-59) already declares job-level id-token: write permissions. The workflow-level declaration at line 35 may be unnecessary and contributes to the static analysis warning about overly broad permissions.

Consider removing the workflow-level id-token: write and relying on the job-level permissions for clarity and least-privilege.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/publish-python-pypi.yml around lines 33 - 36, The
workflow-level permissions block currently sets "id-token: write" broadly;
remove the workflow-level "id-token: write" entry and keep the existing
job-level "id-token: write" declaration in the publish-to-pypi job (referencing
the publish-to-pypi job name) so permissions follow least-privilege and
eliminate the redundant workflow-level id-token setting.
scripts/baml-wrapper-version (1)

49-57: 💤 Low value

Consider validating that the version field belongs to the [package] section.

The regex r'^version = "([^"]+)"$' with MULTILINE will match any line with that pattern, not necessarily the [package] section's version. If the Cargo.toml has other version fields (e.g., in dependencies), this could match the wrong line.

Given that check() validates absence of version.workspace, the risk is reduced but not eliminated. Consider either:

  • Parsing the TOML properly (via tomllib which is already available in Python 3.11+), or
  • Using a more specific regex that ensures the match is within the [package] section.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/baml-wrapper-version` around lines 49 - 57, The read_version()
function currently uses a multiline regex that can match any "version = ..."
line; update it to ensure the version is read from the [package] table (instead
of arbitrary sections). Replace the regex approach in read_version() to parse
WRAPPER_CARGO_TOML using tomllib (available in Python 3.11+), extract
data["package"]["version"], then call Version.parse(...) and fail(...) on
missing keys or parse errors; alternatively, if you prefer a regex solution keep
WRAPPER_CARGO_TOML.read_text() but scope the regex to the [package] section
before matching the version line to avoid picking up dependency/version fields.
scripts/baml-language-version (1)

346-353: ⚡ Quick win

Fragile insertion marker for __version__ in PY_INIT.

The logic inserts __version__ after "atexit.register(flush_events)\n" if the version line is missing. If that marker line changes format or is removed, the insertion will silently fail (no error, version line not added).

Consider making the fallback more robust by appending to the end of the file or using a more stable insertion point, and adding validation that the insertion succeeded.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/baml-language-version` around lines 346 - 353, The current insertion
for __version__ in PY_INIT relies on the fragile marker
"atexit.register(flush_events)\n" and may silently fail if that line changes;
update the fallback to append version_line to the end of PY_INIT (or insert at
another stable anchor) instead of using text.replace with the marker, then
validate the result by checking that '__version__ = "' appears in the final text
and raise/exit with a clear error if it does not; reference PY_INIT,
version_line, marker, and the atexit.register(flush_events) anchor when making
the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@baml_language/crates/baml_release/src/lib.rs`:
- Around line 152-162: In install_to_toolchain_root, avoid downloading the
archive when the version is already installed by moving the VERSION file
idempotency check to before the call to fetch_archive(); keep the existing
fs::create_dir_all and InstallLock::acquire(root.join(format!(".{}.lock",
self.spec.version))) calls, compute install_dir = root.join(&self.spec.version)
and read install_dir.join("VERSION") to compare with self.spec.version, and
return Ok(install_dir) if it matches; only call self.fetch_archive() (and
subsequent install steps) when the VERSION check indicates the toolchain is not
already installed.
- Around line 380-405: The retry loop can panic because a 3xx response leaves
last_error None; update the Ok(response) branch that checks
response.status().is_redirection() (and the surrounding retry loop that sets
last_error and ultimately returns Err(FetchError::Network { url, source:
last_error.expect(...) })) to handle 3xx explicitly: either immediately return a
concrete FetchError for redirects (e.g., construct and return a FetchError
describing the 3xx status using response.status() and url) or ensure last_error
is set to a valid reqwest::Error before continuing (for example by converting
the 3xx response into an Err and storing that in last_error) so that the final
Err(FetchError::Network { ... source: last_error.expect(...) }) cannot panic;
touch the branches around response.status().is_redirection(),
response.error_for_status(), last_error, and the final Err(FetchError::Network)
return.

In `@baml_language/crates/baml/src/main.rs`:
- Around line 291-303: The code currently swallows
toml::from_str::<ProjectConfig>(&text) parse errors when reading a candidate
baml.toml (variables: candidate, ProjectConfig, toolchain), causing silent
fallback; change the logic to surface parse failures instead of ignoring
them—match on toml::from_str and on Err return or propagate a descriptive error
(including candidate path and the toml error) so the caller sees a malformed
local baml.toml rather than falling back to parent/default toolchain selection.
- Around line 97-99: The current global check using args.iter().any(|arg| arg ==
"--version" || arg == "-V") in main.rs accidentally intercepts flags meant for
subcommands; restrict the wrapper-owned version handling to the top-level
invocation only by checking the first user argument (e.g. use args.get(1) or
args.iter().skip(1).next()) and compare that single argument to "--version" or
"-V" (or ensure no subcommand is present) before printing and returning from
main; update the version-check code that references args so it only triggers for
that top-level position (preserving downstream pass-through to baml-cli).
- Around line 617-624: self_update currently writes to current.tmp and calls
fs::rename(tmp, current) which fails on Windows when the running EXE is locked;
on Windows, change the flow so after writing tmp you do not rename but instead
spawn a short-lived updater process (via std::process::Command) that takes
arguments like --replace <tmp> <current>, then exit the running process;
implement a new branch in main (or a new function handler) that recognizes the
--replace args, waits a moment for the parent to exit, atomically moves/renames
tmp to current (retrying on sharing errors) and then optionally relaunches the
replaced executable—use the existing symbols tmp, current, self_update, and
fs::rename to locate where to add the platform-gated spawn and the
replacement-handler logic.
- Around line 433-440: The blocking fetch uses reqwest::blocking::get(&url) with
no timeout causing possible indefinite hangs; replace it by constructing a
reqwest::blocking::Client via
reqwest::blocking::Client::builder().timeout(std::time::Duration::from_secs(N)).build()?
(choose a sensible N, e.g. 10–30s), then call client.get(&url).send() and
proceed with .error_for_status()?.text()?; update both occurrences (the block
that sets fetched_remote = true and the other fetch at the second occurrence) to
use this client (preferably create the client once and reuse) so requests have
an explicit timeout. Ensure you import std::time::Duration and handle the
Client::build() error via existing ? handling.

In `@scripts/baml-package-manager-artifacts`:
- Around line 88-109: The aur_srcinfo function hardcodes pkgdesc causing
.SRCINFO to diverge from PKGBUILD; change aur_srcinfo to accept a pkgdesc
parameter (remove the unused pkgbuild parameter) and use that value instead of
the hardcoded "BAML wrapper - toolchain manager and launcher", then update the
call sites that generate baml and baml-bin to pass the exact pkgdesc strings
from their PKGBUILD files ("...launcher (prebuilt binary)" and "...launcher
(built from source)"). Ensure the returned string uses the provided pkgdesc and
keep the rest of the fields unchanged.

In `@scripts/baml-release-manifests`:
- Line 78: The line using vsix = next(args.vsix_dir.glob("*.vsix")) can raise
StopIteration with no message; change this to explicitly handle the empty-case
(e.g., use next(args.vsix_dir.glob("*.vsix"), None) or
list(args.vsix_dir.glob("*.vsix")) and check length) and when no .vsix is found
raise a clear, user-facing error (consistent with other missing-artifact
handling) referencing args.vsix_dir and the vsix variable so the log/exit
message states that no .vsix files were found in the provided directory.

In `@scripts/install.sh`:
- Around line 45-46: The tmp directory creation is insecure: replace the
predictable tmp="${TMPDIR:-/tmp}/baml-install.$$" and mkdir -p "$tmp" usage with
a secure temporary directory created via mktemp -d; update any code that
references the tmp variable (tmp) to use the mktemp-produced path and ensure you
handle mktemp failure (check for non-empty/exit) and clean up the directory on
exit so tmp is exclusively owned and unpredictable.
- Around line 78-91: The check using grep -qx 'bin/baml' against the entries
file fails for tar members prefixed with ./; update the installer to accept both
forms by normalizing or adjusting the pattern: either strip leading ./ from the
variable that stores entries (entries="$tmp/entries.txt") after creating it, or
change the existence test to use a regex accepting (^|\\./)bin/baml$ (the
current grep call grep -qx 'bin/baml' "$entries" and the tar listing step using
tar -tzf "$archive" are the relevant symbols to modify). Ensure the same
normalization or pattern is applied to any other safety checks that inspect
$entries so both 'bin/baml' and './bin/baml' are accepted.

In `@TASK/PRIOR-ART.md`:
- Line 233: The word "foresseable" in the document should be corrected to
"foreseeable"; locate the occurrence of "foresseable" in TASK/PRIOR-ART.md (the
sentence "This baml wrapper is too old to read manifest schema v2." context) and
replace that misspelling with "foreseeable" to fix the typo.

In `@TASK/USER-PATHS.md`:
- Line 233: Replace the misspelled word "foresseable" with the correct spelling
"foreseeable" in the sentence that currently reads 'All other foresseable SDKs
don't have any issues with this system.'; search for the exact token
"foresseable" in the document and update it to "foreseeable" so the sentence
reads correctly.

In `@typescript2/README.md`:
- Around line 82-86: The README step 4 currently documents running "pnpm
--filter app-vscode-ext build" but the package.json script
"vscode:package:build" actually runs "pnpm --filter baml-language build"; update
the README to match the real command (replace "app-vscode-ext" with
"baml-language") or, if the intended turbo target is different, change the
"vscode:package:build" script to use "app-vscode-ext" so the docs and
package.json are consistent; reference the README step and the
"vscode:package:build" script and ensure the documented command matches the
turbo target that emits the extension host bundle.

---

Outside diff comments:
In `@typescript2/app-vscode-ext/src/extension.ts`:
- Around line 194-226: The global knownProjects array is being overwritten
per-client and cleared on any client's Stopped state; change knownProjects to a
Map keyed by the client/project root (e.g. Map<string, string[]>) so each client
stores its own project list, modify the 'baml/listProjects' handler to set
knownProjects.set(clientIdOrProjectRoot, params.projects ?? []), change the
onDidChangeState Stopped branch to remove only that client's entry
(knownProjects.delete(clientIdOrProjectRoot)) instead of clearing everything,
and update refreshTooltip() to aggregate across all Map values when rendering
the status-bar tooltip; use the client instance or its projectRoot as the unique
key to locate per-client entries.
- Around line 312-317: The command handler registered as 'baml.openPlayground'
is using the raw server-provided projectPath to look up clients in the clients
Map, but server paths from baml/listProjects may point at baml_src/ and
therefore won't match keys created by findBamlProjectRoot(); fix by normalizing
the incoming projectPath with the same resolution logic used for client keys
(call findBamlProjectRoot(projectPath) or otherwise strip/resolve baml_src to
the project root) before doing clients.get(projectPath), so the lookup and the
activeClient() fallback use the same canonical project root; update the handler
around clients.get(...) (or update findBamlProjectRoot to accept server paths)
to perform this normalization.

---

Nitpick comments:
In @.github/workflows/publish-python-pypi.yml:
- Around line 33-36: The workflow-level permissions block currently sets
"id-token: write" broadly; remove the workflow-level "id-token: write" entry and
keep the existing job-level "id-token: write" declaration in the publish-to-pypi
job (referencing the publish-to-pypi job name) so permissions follow
least-privilege and eliminate the redundant workflow-level id-token setting.

In @.github/workflows/release-baml-language.yml:
- Around line 66-69: Update every actions/checkout@v4 step to include
persist-credentials: false unless that job intentionally needs GitHub token;
specifically locate the checkout steps (the uses: actions/checkout@v4
occurrences around the shown diff and also at the other occurrences noted) and
add the persist-credentials: false key alongside ref and fetch-depth so the
checkout does not leave the default token in the checked-out repo; leave
checkout entries in jobs that explicitly require pushing/committing unchanged if
they truly need credentials.

In `@baml_language/crates/baml_cli/src/ide_command.rs`:
- Around line 26-32: Add a clap-level conflict so the parser rejects using both
flags: annotate the IdeInstallArgs fields to declare mutual exclusivity (use the
clap attribute like conflicts_with on the cursor and/or code fields) and then
remove the runtime check in IdeInstallArgs::resolve_editor that returns an
anyhow error for self.cursor && self.code; keep resolve_editor focused on
resolving the Editor and rely on clap to enforce the conflict at parse time.

In `@baml_language/crates/bex_project/src/bex_lsp/multi_project/request.rs`:
- Around line 80-89: Add a unit test that pins the initialize metadata by
asserting the exact experimental.baml JSON payload and the server version
returned by server_capabilities() / on_request_initialize(); locate the
experimental payload construction in the multi-project initialize logic (the
block that sets experimental: Some(serde_json::json!({...}))) and the functions
server_capabilities() and on_request_initialize() and create a test that calls
those functions (or constructs the same payload path) and compares the resulting
JSON object and server_info.version against a hard-coded expected value to
detect accidental key/name or version-source drift; ensure the test lives
alongside the module as a standard Rust #[cfg(test)] unit test and fails on any
change to keys, values, or version constants.

In `@baml_language/crates/bex_project/src/bex_lsp/protocol.rs`:
- Around line 1-10: The protocol constants (BAML_LSP_PROTOCOL_VERSION,
BAML_PLAYGROUND_PROTOCOL_VERSION, MIN_SUPPORTED_VSCODE_LSP_PROTOCOL,
MIN_SUPPORTED_PLAYGROUND_PROTOCOL) and the CAPABILITIES array are duplicated in
TypeScript (compat.ts and extension.ts) and must be kept in sync; update this
Rust file by adding a clear comment above these declarations pointing to the
exact TypeScript counterparts (compat.ts for BAML_* values and extension.ts for
the capabilities list) and include a short TODO/instruction that any change here
must be mirrored in those TS files (or consider centralizing generation later)
so future maintainers will update both places atomically.

In `@scripts/baml-language-version`:
- Around line 346-353: The current insertion for __version__ in PY_INIT relies
on the fragile marker "atexit.register(flush_events)\n" and may silently fail if
that line changes; update the fallback to append version_line to the end of
PY_INIT (or insert at another stable anchor) instead of using text.replace with
the marker, then validate the result by checking that '__version__ = "' appears
in the final text and raise/exit with a clear error if it does not; reference
PY_INIT, version_line, marker, and the atexit.register(flush_events) anchor when
making the change.

In `@scripts/baml-wrapper-version`:
- Around line 49-57: The read_version() function currently uses a multiline
regex that can match any "version = ..." line; update it to ensure the version
is read from the [package] table (instead of arbitrary sections). Replace the
regex approach in read_version() to parse WRAPPER_CARGO_TOML using tomllib
(available in Python 3.11+), extract data["package"]["version"], then call
Version.parse(...) and fail(...) on missing keys or parse errors; alternatively,
if you prefer a regex solution keep WRAPPER_CARGO_TOML.read_text() but scope the
regex to the [package] section before matching the version line to avoid picking
up dependency/version fields.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 1fa8baed-9841-415a-b6dd-290bfc93770b

📥 Commits

Reviewing files that changed from the base of the PR and between 5e03373 and f3bc96f.

⛔ Files ignored due to path filters (2)
  • baml_language/Cargo.lock is excluded by !**/*.lock
  • baml_language/sdks/python/uv.lock is excluded by !**/*.lock
📒 Files selected for processing (69)
  • .github/workflows/build-python-sdk.reusable.yaml
  • .github/workflows/ci.yaml
  • .github/workflows/publish-python-pypi.yml
  • .github/workflows/release-baml-language-alpha.yml
  • .github/workflows/release-baml-language.yml
  • .github/workflows/release-cli.yaml
  • .github/workflows/release-pkg-boundaryml-com.yml
  • TASK/AMENDMENTS.md
  • TASK/COMMANDS.md
  • TASK/FAILURE-MODES.md
  • TASK/OPEN-QUESTIONS.md
  • TASK/PRIOR-ART.md
  • TASK/TASK.md
  • TASK/USER-PATHS.md
  • TASK/docs/install.md
  • TASK/docs/release-maintainer.md
  • TASK/docs/toolchain-system.md
  • baml_language/Cargo.toml
  • baml_language/crates/baml/Cargo.toml
  • baml_language/crates/baml/src/main.rs
  • baml_language/crates/baml_cli/Cargo.toml
  • baml_language/crates/baml_cli/src/commands.rs
  • baml_language/crates/baml_cli/src/ide_command.rs
  • baml_language/crates/baml_cli/src/lib.rs
  • baml_language/crates/baml_cli/src/main.rs
  • baml_language/crates/baml_cli/src/pack_command.rs
  • baml_language/crates/baml_lsp_server/Cargo.toml
  • baml_language/crates/baml_lsp_server/src/lib.rs
  • baml_language/crates/baml_lsp_server/src/playground_server.rs
  • baml_language/crates/baml_lsp_server/src/playground_ws.rs
  • baml_language/crates/baml_release/Cargo.toml
  • baml_language/crates/baml_release/src/lib.rs
  • baml_language/crates/baml_release/src/manifest.rs
  • baml_language/crates/baml_version/Cargo.toml
  • baml_language/crates/baml_version/src/lib.rs
  • baml_language/crates/bex_project/Cargo.toml
  • baml_language/crates/bex_project/src/bex_lsp/mod.rs
  • baml_language/crates/bex_project/src/bex_lsp/multi_project/request.rs
  • baml_language/crates/bex_project/src/bex_lsp/protocol.rs
  • baml_language/crates/bridge_cffi/Cargo.toml
  • baml_language/crates/bridge_cffi/src/ffi/runtime.rs
  • baml_language/crates/bridge_wasm/Cargo.toml
  • baml_language/crates/bridge_wasm/src/lib.rs
  • baml_language/release.toml
  • baml_language/sdks/nodejs/bridge_nodejs/Cargo.toml
  • baml_language/sdks/nodejs/bridge_nodejs/package.json
  • baml_language/sdks/nodejs/bridge_nodejs/src/lib.rs
  • baml_language/sdks/python/pyproject.toml
  • baml_language/sdks/python/rust/bridge_python/Cargo.toml
  • baml_language/sdks/python/rust/bridge_python/src/lib.rs
  • baml_language/sdks/python/src/baml_core/__init__.py
  • baml_language/stow.toml
  • packaging/aur/baml-bin/PKGBUILD
  • packaging/aur/baml/PKGBUILD
  • scripts/baml-language-version
  • scripts/baml-package-manager-artifacts
  • scripts/baml-release-manifests
  • scripts/baml-wrapper-version
  • scripts/install.ps1
  • scripts/install.sh
  • tools/pkg_boundaryml_com/data/index.html
  • tools/pkg_boundaryml_com/lib/pkg-boundaryml-com-stack.ts
  • typescript2/README.md
  • typescript2/app-vscode-ext/package.json
  • typescript2/app-vscode-ext/src/compat.ts
  • typescript2/app-vscode-ext/src/extension.ts
  • typescript2/package.json
  • typescript2/pkg-playground/src/ports/WebSocketRuntimePort.ts
  • typescript2/pkg-playground/src/protocol.ts
💤 Files with no reviewable changes (3)
  • .github/workflows/release-pkg-boundaryml-com.yml
  • .github/workflows/release-cli.yaml
  • .github/workflows/release-baml-language-alpha.yml

Comment thread baml_language/crates/baml/src/main.rs Resolved
Comment thread baml_language/crates/baml/src/main.rs Resolved
Comment thread baml_language/crates/baml/src/main.rs Resolved
Comment thread scripts/install.sh Resolved
Comment thread scripts/install.sh Resolved
Comment thread TASK/PRIOR-ART.md Resolved
Comment thread TASK/USER-PATHS.md Resolved
Comment thread typescript2/README.md Resolved
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 June 2, 2026 16:53 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle June 2, 2026 16:53 Inactive
@rossirpaulo
rossirpaulo marked this pull request as ready for review June 3, 2026 05:14
@vercel
vercel Bot temporarily deployed to Preview – beps June 3, 2026 05:15 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle June 3, 2026 05:32 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 June 3, 2026 05:32 Inactive
…-release-pipeline

# Conflicts:
#	.github/workflows/release-baml-language-alpha.yml
#	baml_language/sdks/nodejs/bridge_nodejs/package.json
@github-actions

github-actions Bot commented Jun 3, 2026 •

Copy link
Copy Markdown

⏭️ Performance benchmarks were skipped

Perf benchmarks (CodSpeed) are opt-in on pull requests — they no longer run on every push. They always run automatically after merge to canary/main.

To run them on this PR, do any of the following, then push a commit (or re-run CI):

  • Add RUN_CODSPEED=1 to the PR description, or
  • Include run-perf or /perf in the PR title or any commit message.

@vercel
vercel Bot temporarily deployed to Preview – beps June 3, 2026 06:16 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 June 3, 2026 06:21 Inactive

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
TASK/MERGE-TO-CANARY.md (1)

7-14: ⚡ Quick win

Move this merge playbook out of the long-lived repo before merging.

The branch SHAs, divergence counts, and one-off conflict decisions here become stale immediately once paulo/baml-language-release-pipeline moves or the merge lands. Keeping this in-tree will leave misleading operator guidance next to the real release docs.

Also applies to: 15-21, 411-420

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@TASK/MERGE-TO-CANARY.md` around lines 7 - 14, The MERGE-TO-CANARY playbook
currently embeds ephemeral branch SHAs and divergence info for
paulo/baml-language-release-pipeline and origin/canary; remove those stale,
in-repo details before merging by extracting the full playbook content to an
external, versioned runbook/wiki (or private ops storage) and replace the
in-repo MERGE-TO-CANARY playbook with a short pointer and a note that
SHA/divergence lines are ephemeral; update the same change in the other
occurrences referenced (the blocks around the earlier 15-21 and 411-420
sections) so no hard-coded SHAs (e.g., merge base 1742580..., branch head
12463db..., origin/canary 9cff3559...) remain in-tree.
.github/workflows/build-nodejs-sdk.reusable.yaml (1)

20-24: ⚡ Quick win

Ensure the push rehearsal exercises the stamped release path.
sam/publish-nodejs runs from on: push, and for push-triggered workflow runs the inputs context is not populated (even if the workflow also has workflow_call inputs). Since the “Stamp release plan” step is guarded by if: ${{ inputs.release_plan_json != '' }}, it will be skipped on that rehearsal branch, so the stamped release path isn’t exercised. Add a push-compatible way to provide a fixture release_plan_json (or use a workflow_dispatch rehearsal path) so the stamp step runs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-nodejs-sdk.reusable.yaml around lines 20 - 24, The
"Stamp release plan" step is skipped on push because inputs.release_plan_json is
empty for push-triggered runs; to fix, add a push-compatible fixture and broaden
the guard: create a small preparatory step (run-on-push) that sets an env/output
like RELEASE_PLAN_JSON with a fixture JSON when github.event_name == 'push',
then change the "Stamp release plan" condition from if: ${{
inputs.release_plan_json != '' }} to check either source (e.g. if: ${{
inputs.release_plan_json != '' || env.RELEASE_PLAN_JSON != '' }} or use
steps.prepare.outputs.release_plan_json), and update the step to read the
release plan from inputs.release_plan_json || env.RELEASE_PLAN_JSON (or the
prepare step output) so the stamped release path runs during the
sam/publish-nodejs push rehearsal.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build-nodejs-sdk.reusable.yaml:
- Around line 45-50: The comment claiming “Target glibc 2.17” for the aarch64
target in build-nodejs-sdk.reusable.yaml is incorrect because the container used
(ghcr.io/rust-cross/manylinux_2_28-cross:aarch64) targets glibc >= 2.28; either
replace that container with a manylinux_2_17-compatible cross image or sysroot
for target aarch64-unknown-linux-gnu, or update the inline comment and any
release/docs to state the true minimum glibc (2.28) for the aarch64 build;
locate the aarch64-unknown-linux-gnu block and change the container string or
the comment to reflect the chosen, consistent glibc floor.
- Around line 106-110: Update the local composite action's input schema so
actionlint can parse the node-action-version input: open the action definition
that declares the input named node-action-version (in the action.yml for the
setup-node composite action) and remove or replace unsupported keys like type:
choice and the options array with an actionlint-compatible declaration (e.g.,
use a simple string type or omit type/options entirely and provide a
description/default), ensuring the input name node-action-version remains and
the setup usage (uses: ./.github/actions/setup-node with: node-action-version:
v6) still works.

---

Nitpick comments:
In @.github/workflows/build-nodejs-sdk.reusable.yaml:
- Around line 20-24: The "Stamp release plan" step is skipped on push because
inputs.release_plan_json is empty for push-triggered runs; to fix, add a
push-compatible fixture and broaden the guard: create a small preparatory step
(run-on-push) that sets an env/output like RELEASE_PLAN_JSON with a fixture JSON
when github.event_name == 'push', then change the "Stamp release plan" condition
from if: ${{ inputs.release_plan_json != '' }} to check either source (e.g. if:
${{ inputs.release_plan_json != '' || env.RELEASE_PLAN_JSON != '' }} or use
steps.prepare.outputs.release_plan_json), and update the step to read the
release plan from inputs.release_plan_json || env.RELEASE_PLAN_JSON (or the
prepare step output) so the stamped release path runs during the
sam/publish-nodejs push rehearsal.

In `@TASK/MERGE-TO-CANARY.md`:
- Around line 7-14: The MERGE-TO-CANARY playbook currently embeds ephemeral
branch SHAs and divergence info for paulo/baml-language-release-pipeline and
origin/canary; remove those stale, in-repo details before merging by extracting
the full playbook content to an external, versioned runbook/wiki (or private ops
storage) and replace the in-repo MERGE-TO-CANARY playbook with a short pointer
and a note that SHA/divergence lines are ephemeral; update the same change in
the other occurrences referenced (the blocks around the earlier 15-21 and
411-420 sections) so no hard-coded SHAs (e.g., merge base 1742580..., branch
head 12463db..., origin/canary 9cff3559...) remain in-tree.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: d4af2bbe-adc6-4a3c-af76-bd1836c371a0

📥 Commits

Reviewing files that changed from the base of the PR and between 12463db and e6e005b.

⛔ Files ignored due to path filters (1)
  • baml_language/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • .github/workflows/build-nodejs-sdk.reusable.yaml
  • .github/workflows/ci.yaml
  • .github/workflows/publish-python-pypi.yml
  • TASK/MERGE-TO-CANARY.md
  • baml_language/Cargo.toml
  • baml_language/crates/baml_cli/Cargo.toml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/syntax/invalid_assignment/compound_ops.baml
  • baml_language/sdk_tests/crates/python_pydantic2/type_shapes/customizable/test_complex_models.py
  • baml_language/sdk_tests/crates/typescript_node/type_shapes/customizable/roundtrip_complex_models.test.ts
💤 Files with no reviewable changes (2)
  • baml_language/sdk_tests/crates/typescript_node/type_shapes/customizable/roundtrip_complex_models.test.ts
  • baml_language/sdk_tests/crates/python_pydantic2/type_shapes/customizable/test_complex_models.py
✅ Files skipped from review due to trivial changes (1)
  • baml_language/crates/baml_cli/Cargo.toml
🚧 Files skipped from review as they are similar to previous changes (2)
  • baml_language/Cargo.toml
  • .github/workflows/publish-python-pypi.yml

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 2

🧹 Nitpick comments (2)
TASK/MERGE-TO-CANARY.md (1)

7-14: ⚡ Quick win

Move this merge playbook out of the long-lived repo before merging.

The branch SHAs, divergence counts, and one-off conflict decisions here become stale immediately once paulo/baml-language-release-pipeline moves or the merge lands. Keeping this in-tree will leave misleading operator guidance next to the real release docs.

Also applies to: 15-21, 411-420

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@TASK/MERGE-TO-CANARY.md` around lines 7 - 14, The MERGE-TO-CANARY playbook
currently embeds ephemeral branch SHAs and divergence info for
paulo/baml-language-release-pipeline and origin/canary; remove those stale,
in-repo details before merging by extracting the full playbook content to an
external, versioned runbook/wiki (or private ops storage) and replace the
in-repo MERGE-TO-CANARY playbook with a short pointer and a note that
SHA/divergence lines are ephemeral; update the same change in the other
occurrences referenced (the blocks around the earlier 15-21 and 411-420
sections) so no hard-coded SHAs (e.g., merge base 1742580..., branch head
12463db..., origin/canary 9cff3559...) remain in-tree.
.github/workflows/build-nodejs-sdk.reusable.yaml (1)

20-24: ⚡ Quick win

Ensure the push rehearsal exercises the stamped release path.
sam/publish-nodejs runs from on: push, and for push-triggered workflow runs the inputs context is not populated (even if the workflow also has workflow_call inputs). Since the “Stamp release plan” step is guarded by if: ${{ inputs.release_plan_json != '' }}, it will be skipped on that rehearsal branch, so the stamped release path isn’t exercised. Add a push-compatible way to provide a fixture release_plan_json (or use a workflow_dispatch rehearsal path) so the stamp step runs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-nodejs-sdk.reusable.yaml around lines 20 - 24, The
"Stamp release plan" step is skipped on push because inputs.release_plan_json is
empty for push-triggered runs; to fix, add a push-compatible fixture and broaden
the guard: create a small preparatory step (run-on-push) that sets an env/output
like RELEASE_PLAN_JSON with a fixture JSON when github.event_name == 'push',
then change the "Stamp release plan" condition from if: ${{
inputs.release_plan_json != '' }} to check either source (e.g. if: ${{
inputs.release_plan_json != '' || env.RELEASE_PLAN_JSON != '' }} or use
steps.prepare.outputs.release_plan_json), and update the step to read the
release plan from inputs.release_plan_json || env.RELEASE_PLAN_JSON (or the
prepare step output) so the stamped release path runs during the
sam/publish-nodejs push rehearsal.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build-nodejs-sdk.reusable.yaml:
- Around line 45-50: The comment claiming “Target glibc 2.17” for the aarch64
target in build-nodejs-sdk.reusable.yaml is incorrect because the container used
(ghcr.io/rust-cross/manylinux_2_28-cross:aarch64) targets glibc >= 2.28; either
replace that container with a manylinux_2_17-compatible cross image or sysroot
for target aarch64-unknown-linux-gnu, or update the inline comment and any
release/docs to state the true minimum glibc (2.28) for the aarch64 build;
locate the aarch64-unknown-linux-gnu block and change the container string or
the comment to reflect the chosen, consistent glibc floor.
- Around line 106-110: Update the local composite action's input schema so
actionlint can parse the node-action-version input: open the action definition
that declares the input named node-action-version (in the action.yml for the
setup-node composite action) and remove or replace unsupported keys like type:
choice and the options array with an actionlint-compatible declaration (e.g.,
use a simple string type or omit type/options entirely and provide a
description/default), ensuring the input name node-action-version remains and
the setup usage (uses: ./.github/actions/setup-node with: node-action-version:
v6) still works.

---

Nitpick comments:
In @.github/workflows/build-nodejs-sdk.reusable.yaml:
- Around line 20-24: The "Stamp release plan" step is skipped on push because
inputs.release_plan_json is empty for push-triggered runs; to fix, add a
push-compatible fixture and broaden the guard: create a small preparatory step
(run-on-push) that sets an env/output like RELEASE_PLAN_JSON with a fixture JSON
when github.event_name == 'push', then change the "Stamp release plan" condition
from if: ${{ inputs.release_plan_json != '' }} to check either source (e.g. if:
${{ inputs.release_plan_json != '' || env.RELEASE_PLAN_JSON != '' }} or use
steps.prepare.outputs.release_plan_json), and update the step to read the
release plan from inputs.release_plan_json || env.RELEASE_PLAN_JSON (or the
prepare step output) so the stamped release path runs during the
sam/publish-nodejs push rehearsal.

In `@TASK/MERGE-TO-CANARY.md`:
- Around line 7-14: The MERGE-TO-CANARY playbook currently embeds ephemeral
branch SHAs and divergence info for paulo/baml-language-release-pipeline and
origin/canary; remove those stale, in-repo details before merging by extracting
the full playbook content to an external, versioned runbook/wiki (or private ops
storage) and replace the in-repo MERGE-TO-CANARY playbook with a short pointer
and a note that SHA/divergence lines are ephemeral; update the same change in
the other occurrences referenced (the blocks around the earlier 15-21 and
411-420 sections) so no hard-coded SHAs (e.g., merge base 1742580..., branch
head 12463db..., origin/canary 9cff3559...) remain in-tree.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: d4af2bbe-adc6-4a3c-af76-bd1836c371a0

📥 Commits

Reviewing files that changed from the base of the PR and between 12463db and e6e005b.

⛔ Files ignored due to path filters (1)
  • baml_language/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • .github/workflows/build-nodejs-sdk.reusable.yaml
  • .github/workflows/ci.yaml
  • .github/workflows/publish-python-pypi.yml
  • TASK/MERGE-TO-CANARY.md
  • baml_language/Cargo.toml
  • baml_language/crates/baml_cli/Cargo.toml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/syntax/invalid_assignment/compound_ops.baml
  • baml_language/sdk_tests/crates/python_pydantic2/type_shapes/customizable/test_complex_models.py
  • baml_language/sdk_tests/crates/typescript_node/type_shapes/customizable/roundtrip_complex_models.test.ts
💤 Files with no reviewable changes (2)
  • baml_language/sdk_tests/crates/typescript_node/type_shapes/customizable/roundtrip_complex_models.test.ts
  • baml_language/sdk_tests/crates/python_pydantic2/type_shapes/customizable/test_complex_models.py
✅ Files skipped from review due to trivial changes (1)
  • baml_language/crates/baml_cli/Cargo.toml
🚧 Files skipped from review as they are similar to previous changes (2)
  • baml_language/Cargo.toml
  • .github/workflows/publish-python-pypi.yml
🛑 Comments failed to post (2)
.github/workflows/build-nodejs-sdk.reusable.yaml (2)

45-50: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🌐 Web query:

What minimum glibc version does the manylinux_2_28 policy target for Linux aarch64 wheels/containers?

💡 Result:

The manylinux_2_28 policy targets a minimum glibc version of 2.28 for all supported architectures, including aarch64 [1][2][3]. This policy is based on the glibc version provided by the underlying distribution used for the manylinux_2_28 images (AlmaLinux 8) [1][4][5]. Wheels built under this policy are expected to be compatible with any Linux distribution that uses glibc 2.28 or later [1][5].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file=".github/workflows/build-nodejs-sdk.reusable.yaml"

# Print the relevant section around the snippet
sed -n '35,70p' "$file" | cat -n

# Search for all mentions of glibc floor / manylinux policy / 2.17 / 2.28
rg -n "glibc|manylinux|2\.17|2\.28" "$file" || true

# Show any release metadata stamping / inputs around those lines if present
rg -n "release|Stamp|release_plan_json|abi|target" "$file" || true

Repository: BoundaryML/baml

Length of output: 3741


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n "glibc\s*2\.17|2\.17-compatible|manylinux_2_28|glibc\s*2\.28|2\.28-compatible" .github/workflows/build-nodejs-sdk.reusable.yaml

# If you want broader confirmation of release metadata claims, also scan the repo for 2.17 mentions (cap output kept small).
rg -n "glibc\s*2\.17|2\.17-compatible" . | head -n 50

Repository: BoundaryML/baml

Length of output: 640


Fix glibc compatibility claim for aarch64-unknown-linux-gnu in build-nodejs-sdk.reusable.yaml

build-nodejs-sdk.reusable.yaml states “Target glibc 2.17” for aarch64-unknown-linux-gnu, but the container used is ghcr.io/rust-cross/manylinux_2_28-cross:aarch64 (manylinux_2_28 targets a minimum glibc of 2.28). This makes the artifact misrepresented as 2.17-compatible on distros with glibc 2.17–2.27. Either switch to a true manylinux/2.17-cross (or equivalent 2.17 sysroot) for that target, or update the documented support floor/release notes accordingly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-nodejs-sdk.reusable.yaml around lines 45 - 50, The
comment claiming “Target glibc 2.17” for the aarch64 target in
build-nodejs-sdk.reusable.yaml is incorrect because the container used
(ghcr.io/rust-cross/manylinux_2_28-cross:aarch64) targets glibc >= 2.28; either
replace that container with a manylinux_2_17-compatible cross image or sysroot
for target aarch64-unknown-linux-gnu, or update the inline comment and any
release/docs to state the true minimum glibc (2.28) for the aarch64 build;
locate the aarch64-unknown-linux-gnu block and change the container string or
the comment to reflect the chosen, consistent glibc floor.

106-110: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect the local action definition that actionlint could not parse.
fd -p 'action.y*ml' .github/actions/setup-node -x sed -n '1,160p' {}
rg -n 'node-action-version|options:' .github/actions/setup-node

Repository: BoundaryML/baml

Length of output: 2695


🏁 Script executed:

#!/bin/bash
set -euo pipefail

command -v actionlint >/dev/null 2>&1 && echo "actionlint: $(actionlint -version || true)" || echo "actionlint: not installed"

# Lint the specific workflow that calls the local action.
if command -v actionlint >/dev/null 2>&1; then
  actionlint .github/workflows/build-nodejs-sdk.reusable.yaml || true
fi

# If the action.yml exists, attempt to lint it as well (best-effort; actionlint behavior may vary).
if command -v actionlint >/dev/null 2>&1; then
  actionlint .github/actions/setup-node/action.yml || true
fi

Repository: BoundaryML/baml

Length of output: 1538


Fix .github/actions/setup-node/action.yml so actionlint can parse the node-action-version input.

actionlint fails parsing the local action used by .github/workflows/build-nodejs-sdk.reusable.yaml (line 107), specifically rejecting the options key for the node-action-version input—so static validation for that with: contract is lost at the call site. Adjust the node-action-version input schema to what actionlint accepts (e.g., change/remove type: choice + options) so linting remains safe.

🧰 Tools
🪛 actionlint (1.7.12)

[error] 107-107: could not parse action metadata in "/home/jailuser/git/.github/actions/setup-node": line 5: unexpected key "options" for definition of input "node-action-version"

(action)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-nodejs-sdk.reusable.yaml around lines 106 - 110,
Update the local composite action's input schema so actionlint can parse the
node-action-version input: open the action definition that declares the input
named node-action-version (in the action.yml for the setup-node composite
action) and remove or replace unsupported keys like type: choice and the options
array with an actionlint-compatible declaration (e.g., use a simple string type
or omit type/options entirely and provide a description/default), ensuring the
input name node-action-version remains and the setup usage (uses:
./.github/actions/setup-node with: node-action-version: v6) still works.

@vercel
vercel Bot temporarily deployed to Preview – promptfiddle June 3, 2026 06:32 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps June 3, 2026 06:43 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 June 3, 2026 06:48 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle June 3, 2026 07:00 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps June 3, 2026 07:22 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps June 3, 2026 07:23 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 June 3, 2026 07:28 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle June 3, 2026 07:41 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps June 3, 2026 14:51 Inactive
@rossirpaulo
rossirpaulo enabled auto-merge June 3, 2026 14:54
@vercel
vercel Bot temporarily deployed to Preview – beps June 3, 2026 14:55 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 June 3, 2026 15:00 Inactive

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/build-python-sdk.reusable.yaml (1)

85-93: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Direct rehearsal paths skip stamping entirely.

When release_plan_json is empty, this step is skipped. That happens on this workflow's push trigger and on manual publish-python-pypi.yml runs, so those builds read whatever version is already in checkout instead of the canary-stamped surfaces the release graph will publish. The Node reusable workflow in this PR already handles the empty-input case correctly; this one should generate a canary plan and stamp unconditionally too.

Suggested change
       - name: Stamp release plan
-        if: ${{ inputs.release_plan_json != '' }}
         env:
           RELEASE_PLAN_JSON: ${{ inputs.release_plan_json }}
         run: |
           set -euo pipefail
-          printf '%s\n' "$RELEASE_PLAN_JSON" > release-plan.json
+          if [[ -n "${RELEASE_PLAN_JSON:-}" ]]; then
+            printf '%s\n' "$RELEASE_PLAN_JSON" > release-plan.json
+          else
+            scripts/baml-language-version plan --channel canary --out release-plan.json
+          fi
           scripts/baml-language-version stamp --plan release-plan.json
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-python-sdk.reusable.yaml around lines 85 - 93, The
"Stamp release plan" step currently skips when inputs.release_plan_json is
empty, causing builds to use unchecked versions; update this step so it always
produces and stamps a release plan: if RELEASE_PLAN_JSON is empty, have the step
generate a canary release-plan.json (e.g., create a minimal canary plan JSON)
before calling scripts/baml-language-version stamp --plan release-plan.json, and
ensure the environment variable RELEASE_PLAN_JSON is used when present; keep the
step name "Stamp release plan" and the stamp command intact so
scripts/baml-language-version runs unconditionally with either the provided plan
or the generated canary plan.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build-python-sdk.reusable.yaml:
- Around line 81-84: The checkout step using actions/checkout@v6 with ref: ${{
inputs.source_sha || github.sha }} is leaving persistable credentials; add
persist-credentials: false under the same with block to prevent checkout
credentials from being available to later steps. Update the step that references
actions/checkout@v6 and the with: ref entry to include persist-credentials:
false so the runner does not retain repository credentials.

In @.github/workflows/publish-python-pypi.yml:
- Around line 96-135: When RELEASE_PLAN_JSON is present (plan_json) and you set
version = json.loads(plan_json)["pypi_version"], validate that the wheels in
dist/ actually match that version before querying PyPI: after computing
local_files (or wheels) check that every local wheel filename contains the exact
version string (e.g. using a regex similar to r"^baml_core-(.+?)-" or by
asserting version in path.name); if any local wheel does not match, print an
error (to stderr) and exit non‑zero to fail fast rather than publishing
mismatched artifacts; otherwise continue with the existing PyPI URL/query logic.

---

Outside diff comments:
In @.github/workflows/build-python-sdk.reusable.yaml:
- Around line 85-93: The "Stamp release plan" step currently skips when
inputs.release_plan_json is empty, causing builds to use unchecked versions;
update this step so it always produces and stamps a release plan: if
RELEASE_PLAN_JSON is empty, have the step generate a canary release-plan.json
(e.g., create a minimal canary plan JSON) before calling
scripts/baml-language-version stamp --plan release-plan.json, and ensure the
environment variable RELEASE_PLAN_JSON is used when present; keep the step name
"Stamp release plan" and the stamp command intact so
scripts/baml-language-version runs unconditionally with either the provided plan
or the generated canary plan.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: bc353522-68dd-41e0-848e-3912bc715f33

📥 Commits

Reviewing files that changed from the base of the PR and between 150661d and 4a5f660.

⛔ Files ignored due to path filters (1)
  • baml_language/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (12)
  • .github/workflows/build-nodejs-sdk.reusable.yaml
  • .github/workflows/build-python-sdk.reusable.yaml
  • .github/workflows/publish-python-pypi.yml
  • .github/workflows/release-baml-language.yml
  • TASK/OPEN-QUESTIONS.md
  • TASK/docs/toolchain-system.md
  • baml_language/Cargo.toml
  • baml_language/crates/baml/Cargo.toml
  • baml_language/crates/baml/src/main.rs
  • baml_language/crates/baml_cli/Cargo.toml
  • baml_language/stow.toml
  • tools/pkg_boundaryml_com/lib/pkg-boundaryml-com-stack.ts
✅ Files skipped from review due to trivial changes (2)
  • baml_language/crates/baml_cli/Cargo.toml
  • TASK/docs/toolchain-system.md
🚧 Files skipped from review as they are similar to previous changes (7)
  • baml_language/Cargo.toml
  • tools/pkg_boundaryml_com/lib/pkg-boundaryml-com-stack.ts
  • baml_language/crates/baml/Cargo.toml
  • baml_language/stow.toml
  • .github/workflows/release-baml-language.yml
  • baml_language/crates/baml/src/main.rs
  • TASK/OPEN-QUESTIONS.md

@vercel
vercel Bot temporarily deployed to Preview – beps June 3, 2026 15:16 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 June 3, 2026 15:21 Inactive
@rossirpaulo
rossirpaulo added this pull request to the merge queue Jun 3, 2026
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle June 3, 2026 15:34 Inactive
Merged via the queue into canary with commit 6883b0d Jun 3, 2026
58 checks passed
@rossirpaulo
rossirpaulo deleted the paulo/baml-language-release-pipeline branch June 3, 2026 15:40
@coderabbitai coderabbitai Bot mentioned this pull request Jun 4, 2026

This branch was previously deployed

3 inactive deployments
Preview – promptfiddle — 4b0d3ae8 Deployed Jun 3, 2026 by vercel[bot]
Preview – promptfiddle2 — 4b0d3ae8 Deployed Jun 3, 2026 by vercel[bot]
Preview – beps — 4b0d3ae8 Deployed Jun 3, 2026 by vercel[bot]
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