Rootfs Contract Reference
The RootFS contract is the project-specific input that tells the Aleph tooling how to build, describe, and publish a VM image profile.
In practice:
- consumer repos keep one contract file per profile
@le-space/rootfsvalidates and parses the contract- the Node runner exports the contract into shell env for the actual build path
The current uc-go-peer contract lives in:
universal-connectivity/go-peer/aleph/root-profiles/uc-go-peer.json
Contract Shape
The shared tooling currently validates this structure:
{
"schemaVersion": 1,
"id": "uc-go-peer",
"displayName": "Universal Connectivity Go Relay",
"source": {
"repository": "self",
"subdirectory": "go-peer"
},
"rootfs": {
"profile": "uc-go-peer",
"installMode": "prebaked",
"installDir": "/opt/go-peer",
"binaryPath": "/usr/local/bin/universal-chat-go",
"dataDir": "/var/lib/uc-go-peer",
"envFile": "/etc/default/uc-go-peer"
},
"services": {
"bootstrap": "uc-go-peer-bootstrap.service",
"main": "uc-go-peer.service",
"autotlsRefresh": "uc-go-peer-autotls-refresh.service"
},
"ports": [
{
"port": 22,
"tcp": true,
"udp": false,
"purpose": "SSH"
}
],
"manifest": {
"copyTarget": "js-peer/public/rootfs/uc-go-peer/latest.json",
"notes": "Human-readable deployment notes."
}
}
Top-Level Fields
schemaVersionInteger contract schema version.idStable internal identifier for the profile.displayNameOptional human-readable label.sourceOptional source repository hints used by the shared tooling.
source
repositoryOptional source repository marker.selfmeans the caller repo.subdirectoryOptional subdirectory that contains the source project.
For uc-go-peer, this is used to indicate that the build input comes from the
consumer repository’s go-peer directory.
rootfs
The rootfs object describes how the guest image should be structured.
profileReference profile name. This selects the reusable reference assets packaged in@le-space/rootfs.installModeConsumer-specific install mode.uc-go-peercurrently usesprebaked.installDirGuest install directory used by helper scripts.binaryPathAbsolute path to the relay binary inside the image.dataDirPersistent runtime data directory inside the guest.envFileGuest environment file used by the relay and helper services.
services
The services object names the important systemd units in the guest:
bootstrapOne-shot setup/bootstrap unit.mainMain runtime service.autotlsRefreshAutoTLS refresh and announce adaptation service.
The shared tooling exports these into the shell environment so build and guest scripts can stay profile-aware without hardcoding service names.
ports
ports is a list of host-forward expectations that are copied into the rootfs
manifest published for consumers.
Each entry supports:
portRequired port number between1and65535.tcpOptional boolean.udpOptional boolean.purposeOptional human-readable description.
For uc-go-peer, this list documents the expected public ports for:
- SSH
- temporary setup on
80 - proxy/Caddy HTTPS and WSS on
443 - direct secure websocket listener on
9097 - raw libp2p TCP/UDP transports on
9095
manifest
The manifest object controls how the generated RootFS manifest is copied back
into the consumer repo.
copyTargetRelative path where the latest generated manifest should be copied.notesOptional human-readable explanation included in the manifest.
For uc-go-peer, the manifest is copied into the js-peer public assets so
browser-side consumers can discover the latest published RootFS.
Validation Rules
The shared parser currently enforces:
- the contract must be an object
schemaVersionmust be an integeridmust be a non-empty stringrootfs,services, andmanifestmust be objects- required string fields must be non-empty
portsmust be an array of valid port objects
The implementation lives in:
packages/rootfs/src/contract.ts
Shell Environment Export
After validation, the shared tooling exports the contract into shell variables used by the RootFS build scripts. Important examples include:
ROOTFS_CONTRACT_IDROOTFS_CONTRACT_PROFILEROOTFS_CONTRACT_INSTALL_MODEROOTFS_CONTRACT_INSTALL_DIRROOTFS_CONTRACT_BINARY_PATHROOTFS_CONTRACT_DATA_DIRROOTFS_CONTRACT_ENV_FILEROOTFS_CONTRACT_MAIN_SERVICEROOTFS_CONTRACT_BOOTSTRAP_SERVICEROOTFS_CONTRACT_AUTOTLS_SERVICEROOTFS_CONTRACT_MANIFEST_COPY_TARGETROOTFS_CONTRACT_PORT_FORWARDS_JSON
This is how the contract becomes the bridge between:
- consumer repo profile data
- shared RootFS reference assets
- guest build/runtime behavior
Runtime HTTP Surface
The contract file describes what gets built. This section describes what a deployed guest must answer, which is a separate contract and the one consumers actually call.
Everything here has to be reachable through the deployment's HTTPS proxy
hostname, not only on the mapped port. The mapped ports are plain HTTP, and a
browser on an HTTPS page refuses to fetch them as mixed content — an app that
can only reach a guest over http://<host>:<mapped-port> cannot reach it at
all. Route named paths before any catch-all in the profile's Caddyfile;
behind a bare handle they never match.
Paths
| Path | Profiles | Answers |
|---|---|---|
/health | all | Readiness. Shape is profile-specific. |
/multiaddrs | libp2p profiles | The relay's dialable addresses. |
/multiaddresses | orbitdb-relay | Spelled-out alias of /multiaddrs. |
/describe | uc-go-peer | Same document as /multiaddrs, shared name. |
/metrics, /pinning/*, /ipfs/* | orbitdb-relay | Its own API surface. |
/bootstrap/* | uc-go-peer | Guest configuration handoff. |
/multiaddrs is the one path a consumer can rely on across libp2p profiles.
orbitdb-relay has served it natively since 0.10; uc-go-peer answers it from
its setup server as of 0.8.0, under both names.
Address document
Two shapes exist and a consumer should read whichever it gets rather than branch on the profile name:
orbitdb-relaygroups addresses underbyTransport, alongsideall,peerIdandversion.uc-go-peeruses<transport>_multiaddrskeys —direct_tcp,autotls_wss,proxy_wss,webtransport,webrtc_direct,browser_bootstrap,probe— alongsidepeer_idandprofile.
A profile that publishes no libp2p addresses answers 404, which consumers
must present as "this profile publishes no address document" rather than as an
empty address list.
Do not treat any single field as the address to use. orbitdb-relay reports
a best object whose websocket entry has pointed at the Caddy port rather
than the relay (see the relay dialability timeline); the deployment card
deliberately ignores it and shows what the relay reported instead.
Where this is implemented
packages/rootfs/reference/uc-go-peer/rootfs/uc-go-peer-configure.sh—render_proxy_caddyfile, named handles ahead of the WebSocket catch-allpackages/rootfs/reference/uc-go-peer/rootfs/uc-go-peer-setup-server.py—_handle_describe, unwrapping the readiness envelopepackages/rootfs/reference/orbitdb-relay/rootfs/orbitdb-relay-configure.sh— the full API surface proxied to the metrics port
Recommended Consumer Pattern
For consumer repos:
- keep one small contract file per deployable profile
- keep project-specific values in the contract
- keep reusable RootFS logic and guest baselines in
relay-button
That keeps consumer repos thin while preserving explicit profile-level control.