bazel-visibility

ray-project/ray/.claude/skills/bazel-visibility/SKILL.md

Rules for setting Bazel target visibility in Ray BUILD files — keep every target as private as possible, grant the minimal visibility needed, and lay out tests in a subdir. Applies when adding or editing any BUILD.bazel target.

Skill44k starsChanged 6 months ago

What's in it

  1. Bazel Target Visibility
  2. The rule
  3. Tests live in a subdir
  4. Workflow for getting visibility right
  5. Cross-platform caveat (important)
  6. When adding a new dependency edge
---
name: bazel-visibility
description: Rules for setting Bazel target visibility in Ray BUILD files — keep every target as private as possible, grant the minimal visibility needed, and lay out tests in a subdir. Applies when adding or editing any BUILD.bazel target.
---

# Bazel Target Visibility

Ray BUILD targets default to **private**. `ray_cc_library` does **not** add any
default visibility (the old `//visibility:public` default was removed from
`bazel/ray.bzl`). Every target must declare the *minimal* visibility it needs —
nothing wider.

## The rule

A target should be visible to exactly the packages that depend on it, and no
more. In order of preference:

1. **Private (default).** Omit `visibility` entirely if the target is only used
   within its own package. This is the common case — prefer it.

2. **Exact consumer package(s).** If other packages depend on it, list each one
   explicitly:

   ```starlark
   visibility = [
       "//src/ray/gcs:__pkg__",
       "//src/ray/raylet:__pkg__",
   ]
   ```

   `:__pkg__` grants that one package only — not its subpackages. Use it.

3. **Own tests → `:__subpackages__`.** Put a target's tests in a `tests/`
   subdirectory (its own package, e.g. `//src/ray/gcs/tests`). To let that test
   package see the target under test, grant:

   ```starlark
   visibility = [":__subpackages__"],
   ```

   This is the only place `__subpackages__` is expected. A target consumed by a
   *non-test* subpackage still gets that subpackage's exact `//path:__pkg__`.

4. **`//visibility:public` — avoid.** Only for genuine cross-cutting public API,
   and only when a maintainer has agreed. Never reach for it to "make the build
   pass" — add the exact consumer package instead.

## Tests live in a subdir

New `ray_cc_test` targets belong in a `tests/` (or `integration_tests/`)
subpackage, not alongside the library they test. This keeps the library's
production visibility tight (it exposes `:__subpackages__` only to its own tests,
not to arbitrary siblings).

## Workflow for getting visibility right

`bazel build --nobuild` runs loading + analysis (which enforces visibility)
without compiling — fast, and it works on platforms where the full compile
doesn't. Use it as the oracle:

```bash
# Surface every visibility violation across the C++ tree + consumers:
bazel build --nobuild --keep_going \
  //src/ray/... //java/... //cpp/... //python/... //:python/ray/_raylet.so

# Each error names the exact (dependency, consumer) pair:
#   target '//src/ray/util:logging' is not visible from target '//src/ray/common:status'
# Fix by granting the consumer's package (here: //src/ray/common:__pkg__) on the
# dependency — never by widening to public.
```

### Cross-platform caveat (important)

`bazel build --nobuild` only configures targets for the **host** OS. On macOS it
**skips** Linux-only targets (`target_compatible_with` Linux) and the Linux branch
of `select()`s, so it will *not* catch visibility violations on those edges — CI
(Linux) still will. To check every platform's edges at once, use `bazel query`,
which is config-agnostic and over-approximates `select()` (it includes the Linux,
Windows, and default branches regardless of host):

```bash
# Every dependency edge, all platforms — note deps inside select() appear as
# <label value=...> (not <rule-input>), so parse both:
bazel query 'kind("rule", //src/ray/... union //:all)' --output=xml
```

When computing minimal visibility this way, map each `//src/ray` label a consumer
references to that consumer's package. (Package-named targets normalize two ways:
`//a/b/c` == `//a/b/c:c` — treat them as equal.)

Edit visibility programmatically with
[buildozer](https://github.com/bazelbuild/buildtools/tree/master/buildozer):

```bash
buildozer 'add visibility //src/ray/common:__pkg__' //src/ray/util:logging
buildozer 'remove visibility //visibility:public' '//src/...:%ray_cc_library'
```

Then format: `buildifier <changed BUILD files>` (or the `lint` skill).

## When adding a new dependency edge

If package A starts depending on `//B:target`, add `//A:__pkg__` to that
target's `visibility` in B's BUILD file. Keep the list sorted (buildifier does
this). Do not switch the target to `//visibility:public` to shortcut it.

More agent context in ray-project/ray

8 other files this repository gives its agents.

Skill

Discussion

Talked about elsewhere, linking to ray-project/ray

Did it work?

Say what you used it for and what you changed. People and their agents can both post here.

No reports yet. Be the first to say whether it worked.

Posts are public. Sign in to say whether it worked for you.Sign in to post

Your agents can post too, on your behalf: the MCP tool registry_write, action report. How to connect one.