ext.rbs under
a namespace you choose, and load its modules as
@<namespace>//<path>.rbs.
The ext.rbs manifest
ext.rbs lives at the workspace root. It is evaluated like any other .rbs
file, but ext() is the only available function — load() is deliberately
disallowed. A dependency list that could compute itself could not be read
without running it, and resolution must be answerable before any rule code
executes. (This is also what makes nested packages cheap: reading a fetched
package’s manifest is parsing, not evaluation.)
ext()
Each entry must name exactly one source:
git, http, or rule.
The
rule = "org/name" coordinate form is resolved through a control
plane. On a ReasonOS node this is zero-config — nodes launch with
RBS_CONTROL_PLANE_URL set — and the control plane answers with a clone
URL and the commit its version tag points at. Off a node, set the same
variable or use git =.Loading package modules
Once declared, a package’s.rbs files load by namespace:
@<namespace>// is a file path inside the package
repository; the .rbs extension is appended if missing. Resolution happens
before any build-language code runs: the whole external graph is settled first,
then evaluation reads it — a failed fetch fails the build up front rather
than surfacing later as “unknown rule”.
The rbs ext CLI
The manifest is the source of truth;rbs ext edits it and resolves, the
way go get edits go.mod.
rbs ext add flags:
Pinning and updating
A ref resolves to a commit, and the commit is recorded inrbs.lock
(under the ext ecosystem). After that, the pin answers:
- Builds are reproducible — a moved tag cannot change your rules silently.
- A warm workspace resolves offline; no remote lookups per build.
rbs ext updateis the only operation that re-reads a moving ref.
.rbs/ext/git/<commit>, keyed by commit
rather than namespace — two packages depending on the same rules at the
same commit share one copy and one fetch.
The typical update flow:
ref = in ext.rbs (or re-run
rbs ext add with the new --ref), then build.
Namespaces are private
A rule package carries its ownext.rbs for its own dependencies, and
those are resolved too. Every namespace lookup is answered from the table
of the repository doing the load:
java-rules, @base means jvm-base. In your workspace, @base
means whatever you declared — or nothing at all. Neither can shadow the
other, so a published package’s internal naming never reaches its
consumers. Two packages may even use the same namespace for different
things.
Dependency cycles between packages resolve fine: identity is content, so a
package reached twice is the same package and the walk stops.
Authoring a package
A package repository mirrors the embedded ruleset layout — directories of.rbs modules that define rules with the
rule SDK and export them: