In your Bazel repo, tell your agent:
Follow this guide to install rules_agents into this Bazel repo:
https://raw.githubusercontent.com/jastice/rules_agents/refs/heads/main/skills/rules_agents/references/quickstart.md
rules_agents gives every developer on a repo the same coding-agent
environment — same skills, same configuration — launched with one command:
bazel run //agent:devYou declare skills and profiles once in Bazel. The repo owns the setup. Developers just run the target.
Coding agents are useful, but setting them up is manual work:
- Each agent has its own skill format and install location
- Skills need to be copied or wired in by hand, per agent, per repo
- Keeping skills up to date across repos and agents is a chore nobody signs up for
- New team members have to reverse-engineer the setup or ask around
rules_agents solves this the same way Bazel solves build toolchains:
declare what you want, let the tool handle the rest.
- Declare once, run anywhere: one profile works across Codex and Claude Code — no per-agent wiring
- Reproducible: skills and profiles are versioned with the repo in BUILD files
- Always current: remote skills pull from registries; update pins when you're ready
- Zero manual setup: no hand-editing dotfiles, no tribal knowledge, no config drift
- exactly two supported agent clients:
codexandclaude_code - local skills declared from files already in the repo
- remote skills synthesized from git archive downloads
- installation into the agent's native project-local skill directories
doctor,manifest,setup, andrunbehavior for declared profiles and runners
Before using rules_agents, a developer should already have:
- a supported Unix-like host environment; current support is Linux and macOS, not Windows
- one supported agent client installed separately
- any required agent login or auth state handled by that client
- OR: required credential environment variables exported in the shell
rules_agents does not install agent binaries, synthesize user-global config, or manage
secrets beyond validating and forwarding declared env vars.
agent_skill: one portable skill bundle rooted at aSKILL.mdagent_profile: one buildable local profile artifactagent_runner: one runtime realization of a profileskill_deps: one module extension for bringing in remote skill archives
For the supported agents, managed skills will be installed under:
codex:<repo>/.agents/skillsclaude_code:<repo>/.claude/skills
The launcher manages only tool-owned subdirectories inside those native roots.
Multiple agent_profile targets can coexist in Bazel, but installs are active per agent root:
running one Codex profile replaces managed skills previously installed by another Codex profile,
and likewise for Claude Code profiles.
For the smallest local-only setup, a repo only needs a local skill and one profile.
In a BUILD file:
load("@rules_agents//rules_agents:defs.bzl", "agent_profile", "agent_runner", "agent_skill")
agent_skill(
name = "repo_helper",
root = "skills/repo_helper",
srcs = glob(["skills/repo_helper/**"], exclude_directories = 1),
)
agent_profile(
name = "repo_dev_profile",
skills = [
":repo_helper",
],
)
agent_runner(
name = "codex_dev",
runner = "codex",
profile = ":repo_dev_profile",
)That gives the repo one buildable profile artifact plus one runnable Codex runner.
For the fastest batteries-included setup, install the rules_agents skill from this repo and verify with
one command.
In MODULE.bazel, bring in rules_agents:
bazel_dep(name = "rules_agents", version = "0.1.0")In a BUILD file, start with the bundled rules_agents skill target exposed by the module itself:
load("@rules_agents//rules_agents:defs.bzl", "agent_profile", "agent_runner")
agent_profile(
name = "dev_profile",
skills = ["@rules_agents//skills:rules_agents"],
)
agent_runner(
name = "dev",
runner = "codex",
profile = ":dev_profile",
)Verify with one command:
bazel run //:dev_doctorAfter that, add repo-local skills or discovered remote skills to the same agent_profile.
If you need unreleased repository changes instead of the published 0.1.0 module, use
git_override(...) as a development-only path:
git_override(
module_name = "rules_agents",
remote = "https://github.com/jastice/rules_agents/",
branch = "main",
)rules_agents supports discovering skills from skill registries.
The user workflow is:
- enable registry discovery in
MODULE.bazel - list available skills from the configured registries
- copy the printed Bazel snippet for the skill you want
- add the synthesized skill target to an
agent_profile - optionally pin newer registry revisions with an explicit update command
Codex examples omit credential_env by default so normal in-agent login can work unchanged.
Add credential_env = ["OPENAI_API_KEY"] only when a skill or repo-local tool explicitly
needs that variable.
If you only want the registries that ship with rules_agents, add this to MODULE.bazel:
skill_deps = use_extension("@rules_agents//rules_agents:extensions.bzl", "skill_deps")
skill_deps.registries()
use_repo(skill_deps, "rules_agents_registry_index")That enables the built-in official registries and lets Bazel cache registry resolution through its normal module-extension machinery.
The default catalog includes:
rules_agents_skillsfor therules_agentsskill shipped in this repository, discovered underskillsopenai_skillsfor Codex skills fromopenai/skills, discovered underskills/.curatedanthropic_skillsfor Claude Code skills fromanthropics/skills, discovered underskills
skill_deps.registries() is for discovery only. It does not create usable external skill
repos by itself and does not replace skill_deps.remote(...).
To list all skills from the active registries:
bazel run @rules_agents_registry_index//:list_skillsTo filter the output:
bazel run @rules_agents_registry_index//:list_skills -- --agent=codex
bazel run @rules_agents_registry_index//:list_skills -- --registry=openai_skills
bazel run @rules_agents_registry_index//:list_skills -- --skill=python
bazel run @rules_agents_registry_index//:list_skills -- --json--agent filters at registry granularity. A registry is included when it declares support
for that agent.
For each discovered skill, the command prints:
- the short description from
SKILL.mdfrontmatter - a link to the full online skill source
- the Bazel snippet needed to add that registry and the target label to reference
Pick a skill from the listing output and copy the printed MODULE.bazel snippet.
For example, if the listing shows @openai_skills//:python, add the generated remote repo
declaration to MODULE.bazel:
skill_deps = use_extension("@rules_agents//rules_agents:extensions.bzl", "skill_deps")
skill_deps.remote(
name = "openai_skills",
url = "https://github.com/openai/skills/archive/0123456789abcdef.tar.gz",
)
use_repo(skill_deps, "openai_skills")Then reference the discovered skill target from your profile:
agent_profile(
name = "repo_dev_profile",
skills = [
":repo_helper",
"@openai_skills//:python",
],
)skill_deps.registries(...) and skill_deps.remote(...) can coexist in the same
MODULE.bazel. The first lets you browse available skills. The second is what actually makes
one remote skill repo usable from agent_profile.
If your repository needs additional registries or different pinned revisions, create
tools/rules_agents/registries.json and tell skill_deps to use it.
In MODULE.bazel:
skill_deps = use_extension("@rules_agents//rules_agents:extensions.bzl", "skill_deps")
skill_deps.registries(
config = "//tools/rules_agents:registries.json",
mode = "extend", # or "replace"
)
use_repo(skill_deps, "rules_agents_registry_index")Use mode = "extend" to add repo-specific registries on top of the built-ins. Use
mode = "replace" if the repo wants to ignore the built-in curated set completely.
Listing skills never changes registry pins. To check for newer upstream revisions, run:
bazel run @rules_agents//tools:update_registriesTo check one registry only:
bazel run @rules_agents//tools:update_registries -- --registry=openai_skillsTo apply the proposed pin updates to the current workspace catalog:
bazel run @rules_agents//tools:update_registries -- --applyOr for one registry:
bazel run @rules_agents//tools:update_registries -- --registry=openai_skills --applyAfter the pin changes, rerun bazel run @rules_agents_registry_index//:list_skills or your
normal profile targets. Bazel handles cache invalidation and lockfile updates itself.
--apply rewrites a workspace-owned catalog file. By default that means
catalog/registries.json when you run it from this repository. In a consuming repository,
pass --catalog=tools/rules_agents/registries.json or another writable path. It does not
modify the read-only built-in catalog shipped inside an external rules_agents dependency.
The public API stays deliberately small:
agent_skillagent_profileagent_runnerskill_deps
The project is still in PoC phase. The API and target shapes may change without backward
compatibility guarantees.
spec/v1.md is retained as background guidance and historical context.
Current design work may extend or replace parts of it.
The profile/runner split is described in spec/profile_runner.md.
The implemented profile/runner split is:
agent_profile: a buildable profile artifact targetagent_runner: a runtime target that sets up and runs a concrete client or wrapper
One example target flow is:
bazel build //agent:repo_dev_profile
bazel run //agent:codex_dev_setup
bazel run //agent:codex_dev_runMeaning:
- build the portable profile artifact
- deploy or synchronize that artifact into repo-local runner state
- launch the agent frontend using the realized state
Another example with a different runner would be:
bazel build //agent:repo_dev_profile
bazel run //agent:claude_dev_setup
bazel run //agent:claude_dev_runIn that proposed model, for example:
//...:repo_dev_profilebuilds the profile artifact//...:codex_dev_setuprealizes the profile for a concrete runner//...:codex_dev_runlaunches or attaches to the runner frontend//...:codex_devaliases the default interactive entrypoint//...:claude_dev_setupand//...:claude_dev_runfollow the same pattern for another runner
The current implementation provides:
agent_skillpackages local skill bundles and validates bundle shapeagent_profilebuilds:nameand:name_manifestprofile artifactsagent_runnergenerates:name,:name_setup,:name_run,:name_doctor, and:name_manifest- the runtime launcher supports
doctor,setup,run,install, andstart - managed installs land under
.agents/skillsfor Codex and.claude/skillsfor Claude Code skill_deps.remote(...)synthesizes remoteagent_skilltargets from archive contents- examples exist for both supported agents
Repository verification today:
bazel test //tests:alltests/remote_skill_deps_test.shtests/missing_skill_md_test.sh
//agent:dev,//agent:dev_doctoralias the runnable Codex example runner targets//agent:dev_manifestaliases the Codex example profile artifact target (usebazel build, notbazel run)//agent:claude_dev,//agent:claude_dev_doctoralias the runnable Claude Code example runner targets without declared credential env//agent:claude_dev_manifestaliases the Claude Code example profile artifact target (usebazel build, notbazel run)//agent:claude_dev_auth,//agent:claude_dev_auth_doctorshow the opt-in Claude Code example withcredential_env = ["ANTHROPIC_API_KEY"]//examples:codex_dev_setupand//examples:claude_dev_setupare example setup wrappers used by tests
MODULE.bazel: Bazel module rootBUILD.bazel: top-level Bazel packageagent/: example-facing aliases for the runnable profilesexamples/: working local skill and profile targets for both agentstests/: Bazel integration tests for the launcher flowrules_agents/: public Starlark surfacerules_agents/private/: internal implementationrules_agents/runtime/: runtime launcher implementationspec/: product and design specsspec/v1.md: historical v1 product spec and implementation planspec/profile_runner.md: draft proposal for splitting profile declaration from runner realization