Reference Guide
The Ringleader resource model: how the objects relate, and a field-by-field reference for each kind.
Everything in Ringleader is a resource: a Kubernetes-style object with
apiVersion, kind, metadata, spec, and (for most kinds) status. You
declare the spec; the control plane and the in-VM agent write status as they
bring the real machine in line with it. You never edit status.
This guide covers the kinds you author most often:
- Workstation: one managed development machine, a VM on your computer or in your cloud account.
- WorkstationConfig: a reusable configuration layer applied to workstations.
- Devtools: the curated install recipes a config can declare, one page per tool.
- Tool configuration: declarative configuration for the tools on a workstation, one page per tool.
- Devcontainers: run a repository’s own
devcontainer.jsonon a workstation, unchanged. - ConfigMap: reusable text a config’s
scriptsandfilesreference instead of inlining it. - Integration: connect workstations to a shared external service, such as an LLM gateway or an MCP server.
- Credential injection: let workstations call an API that needs a key, without the key being on them.
- Edge: the VM that enforces egress rules by host name and adds injected credentials, one per cloud and region.
- LocalBinding: a device-local port/socket forward from a workstation to your machine.
- CloudIdentity: the credential broker that lets the control plane create cloud VMs.
- CloudAccount: the link between one organization and one cloud account, recording the cloud identity to use.
- SSHKey: forward a local private key into workstations as an ambient ssh-agent.
- Providers: how a workstation is placed on vz, lima, qemu, wsl2, hcs or a cloud.
- Access control: namespaces, ownership, RBAC roles, and Grants.
- Policy: constrain what a workstation manifest may name: today, which git repositories it may clone.
- Organizations: the tenancy layer above namespaces, holding a company, its verified domain, and who administers it.
- ServiceAccount: a non-human identity CI and automation sign in as, with no stored secret.
Start with the relations below to see how they fit together, then dive into a specific kind.
Relations between objects
A Workstation is the center of the model. The other kinds shape it
(configuration, credentials), connect to it (forwards), or filter what it
reaches (an Edge).
How they connect
Workstation → WorkstationConfig. A workstation receives config either by explicit reference (
spec.configs: [{name, priority}]) or by selector match: aWorkstationConfigwhosespec.selector.matchLabelsmatch the workstation’s labels attaches automatically. All matching configs plus the workstation’s inline spec are merged as config layers (lower priority applies first) into one effective spec, whichrl workstation get-resolved-configurationprints on demand.Workstation → Integration. An
Integrationdoes not reach a workstation directly: it compiles to a generatedWorkstationConfignamedintegration-<name>, which then attaches by the ordinary selector rules above. That generated layer sits at a negative priority, so it loses to every config a person writes, but not to the workstation’s own inline spec, which is the base every layer is applied over.Workstation → CloudIdentity. When a workstation routes to a cloud provider, the control plane picks the
CloudIdentityin the same namespace whosespec.providermatches and whosespec.selector.matchLabelsmatch the workstation’s labels (highestprioritywins). That identity brokers the short-lived credentials used to create the VM, and can inject provider-config defaults/overrides.CloudIdentity → CloudAccount. A
spec.cloudAccountRefpoints at a cluster-scopedCloudAccount, naming which cloud identity to use for the organization that owns the namespace. This selects per-organization federation, in which Ringleader presents a signed, organization-scoped assertion to your cloud’s own trust configuration and stores no credential at all.Alternatively, a
spec.impersonationblock selects the legacy shared-intermediary chain; with neither field, the control plane’s own default identity is used.cloudAccountRefandimpersonationare mutually exclusive: they are the credential paths, not layers. Ringleader stores no cloud credential at rest on any of them.Workstation → Edge. A workstation never names an Edge. On a cloud, the Edge in the workstation’s namespace that covers its provider and region serves it, through an edge instance: a VM in your cloud account. On vz or qemu, an Edge with
provider: vzorprovider: qemuruns an edge VM on your own machine instead. On hcs, vz or qemu with no Edge, the workstation’s own network process serves it. A workstation with an egress policy, or with a key an Integration adds, sends its outbound connections through that VM or process. It applies the workstation’s own egress policy to each connection. It also adds the keys the workstation’shttpProxyIntegrations name, read from a Secret, so the keys are never on the workstation. The example below shows both.CloudIdentity → Edge. An Edge has no field naming a CloudIdentity. On a cloud, its edge instance is built with a CloudIdentity for the same provider from the Edge’s own namespace, chosen as the Edge page describes.
Workstation → LocalBinding. Forwarding is not implicit. When a workstation with a
spec.defaultLocalBindingtemplate first reaches Running, the daemon seeds one device-localLocalBindingfrom it (once, deletion is honored). You can also authorLocalBindingobjects directly.
Reading status
Every kind that reports a status carries a top-level status.message: the one
human headline for what is going on with that object, in a sentence. It is
universal, so you can read any object’s state without first learning that kind’s
sub-status keys or condition vocabulary:
rl workstation get my-box -o jsonpath='{.status.message}{"\n"}'
rl binding get -o jsonpath='{.status.message}{"\n"}'Where a kind also has conditions, the two never disagree: they are derived from
one computation. status.message is the headline; conditions[].message is the
per-aspect detail, and the condition’s reason is a value from a closed set you
can branch on.
Status is server-owned (a client can never write it) and it is curated: an internal failure surfaces as a generic message plus a reference id, never a raw error, so a status is always safe to paste into a ticket.
Namespace scoping
Most kinds are namespaced, and cross-references stay within a namespace. A workstation’s configs, its CloudIdentity, the Edge that serves it, and the Secrets its CloudIdentity and Integrations read all live in the workstation’s namespace. Two exceptions:
CloudAccountis cluster-scoped and owned by an organization, not a namespace. A CloudIdentity may only reference an account belonging to the organization its own namespace belongs to.LocalBindingis device-local: it never leaves the machine that materializes it and is never synced or mirrored.
Apply order
When you apply a multi-document manifest, Ringleader writes the objects in order
of their kind, so that references resolve. Among the kinds in this guide, the order is:
- Organizations
- Namespaces
- OrgPolicies
- ServiceAccounts
- Policies
- ConfigMaps
- WorkstationConfigs
- Secrets
- Integrations
- SSHKeys
- CloudAccounts
- CloudIdentities
- Edges
- Workstations
- LocalBindings
- Grants
An Integration comes after the Secrets, so the key it names already exists when you apply it. A Grant comes last, because it names an object that must already exist.
Example: one Edge, two teams
Two teams share the namespace acme on Google Cloud. The platform team calls the GitHub
API with a shared token, and the data team installs Python packages. Each team reaches only
its own hosts, and the token is never on a workstation.
A namespace administrator applies the Edge, the Integration, the WorkstationConfigs and the
Policy. Each team member applies their own workstations. The example assumes the namespace
already has a GCP CloudIdentity that places
workstations in a us-east4 zone.
Declare the Edge for the region:
apiVersion: core.ringleader.dev/v1 kind: Edge metadata: name: gcp-us-east4 namespace: acme spec: provider: gcp region: us-east4On AWS and Azure the Edge also names a subnet. See Declare an Edge.
Store the token in a Secret, and apply an Integration that adds it to the platform team’s requests to the GitHub API:
rl secret create github-pat -n acme --from-string token=<your-token>apiVersion: workstations.ringleader.dev/v1 kind: Integration metadata: name: github-api namespace: acme spec: type: httpProxy selector: matchLabels: team: platform httpProxy: rules: - host: api.github.com inject: header: Authorization value: "Bearer ${secret:github-pat/token}"The Edge sets the
Authorizationheader on every request ateam: platformworkstation sends toapi.github.com. Tools on the workstation call the API as if they had signed in, and the token is not on the workstation. Credential injection covers local workstations, MCP servers and rotating the token.Apply one WorkstationConfig per team. Each selects its team’s workstations by label and carries an egress policy:
apiVersion: workstations.ringleader.dev/v1 kind: WorkstationConfig metadata: name: platform-egress namespace: acme spec: selector: matchLabels: team: platform egress: enforcement: strict destinations: - host: github.com - host: "*.githubusercontent.com" --- apiVersion: workstations.ringleader.dev/v1 kind: WorkstationConfig metadata: name: data-egress namespace: acme spec: selector: matchLabels: team: data egress: enforcement: strict destinations: - host: pypi.org - host: files.pythonhosted.orgWith
strict, a workstation whose provider cannot hold the policy is refused when you apply it. WithbestEffort, it is created and reports what is not enforced.The platform layer does not list
api.github.com. A host an Integration adds a key for is added to the workstation’s allowlist, on ports 80 and 443. An inspection-only rule would not add its host: it checks a host that the policy already permits. Ahostdestination covers only those two ports, so the platform team clones from GitHub over HTTPS, not SSH.Give each workstation its team’s label. A
strictpolicy also needs the workstation to name its provider:apiVersion: workstations.ringleader.dev/v1 kind: Workstation metadata: name: platform-01 namespace: acme labels: team: platform spec: provider: gcpA data team workstation is the same, with
team: data.Apply a Policy that limits which destinations any manifest in the namespace may name:
apiVersion: core.ringleader.dev/v1 kind: Policy metadata: name: egress-ceiling namespace: acme spec: priority: 50 rules: egressDestinations: default: deny allow: - github.com - "*.githubusercontent.com" - api.github.com - pypi.org - files.pythonhosted.orgConfiguration layers add their destinations together, so without a Policy a member can widen their own workstation’s allowlist with a layer of their own. With it, a Workstation, WorkstationConfig or Integration that names any other destination is refused when it is applied:
remote: forbidden: spec.egress.destinations[0].host names "pastebin.com", which your organization's or namespace's policy does not permit (HTTP 403)The list includes
api.github.combecause the Policy also judges the hosts an Integration names. See Policy.
Check the result
Ringleader builds the edge instance when the first workstation that needs it reports in.
Until the edge instance serves a workstation, the workstation is held closed, and its EgressEnforced
condition reads False and says why. Once it is served, rl edge get gcp-us-east4 -n acme
shows Ready True with reason Serving, and rl workstation describe platform-01 -n acme
shows EgressEnforced True with reason Enforced.
From a shell on each workstation, these requests give these results:
| Request | team: platform | team: data |
|---|---|---|
curl https://github.com | Works | Connection reset |
curl https://api.github.com/user | Returns the token owner’s GitHub user | Connection reset |
curl https://pypi.org/simple/requests/ | Connection reset | Works |
curl https://example.com | Connection reset | Connection reset |
One Edge serves both teams, because it applies each workstation’s own policy to each of its connections. Both workstations also reach what they need to stay managed by Ringleader, which you never list. The Edge and your cloud’s firewall are outside the workstation, so nothing running on it, including an AI coding agent running as root, can undo the restriction. What a denied connection looks like explains the resets.
What a label does not restrict
Labels are written by each workstation’s owner. Within one namespace, a label chooses which workstations get an allowlist or a token, and it does not keep a member out:
- A member can add
team: platformto their own workstation, and the Edge then adds the token to its requests. - A member can remove
team: datafrom their own workstation, and the data team’s allowlist no longer applies to it. The Policy refuses any destination outside its list, but it does not make a workstation declare an egress policy, and a workstation with none is not limited to an allowlist.
To keep a token or a host away from some people, give the people who need it a namespace of their own. An Integration reaches only workstations in its own namespace, and that namespace needs an Edge of its own. On AWS and Azure, read Subnets have one owner first, because an edge instance routes a whole subnet.
- WorkstationA development machine Ringleader creates and manages for you: a VM on your laptop or in your cloud account.
- WorkstationConfigA machine setup you define once and attach to many workstations, by label or by explicit reference.
- DevtoolsCurated install recipes for the tools a workstation needs: what each one installs, its versions, and its configuration.
- DevcontainersRun a repository's own devcontainer.json on a workstation, without rewriting it as a WorkstationConfig.
- ConfigMapStore a script or config file once and reference it from many manifests, instead of pasting it into each one.
- Tool configurationSet up the tools on a workstation: git identity, an editor's settings, a CLI's credentials, declared once and reapplied.
- IntegrationConnect workstations to a shared external service, such as an LLM gateway or an API that needs a key, so the tools on them use it with no per-machine setup.
- Credential injectionLet the tools on a workstation call an API that needs a key, while the key stays off the workstation.
- EdgeRingleader Edge is a small VM in your cloud account that enforces hostname egress rules and adds injected credentials for your workstations.
- LocalBindingA device-local forward of a workstation's ports and Unix sockets to your machine, and of your machine's services into a workstation.
- CloudIdentityThe credential broker that lets the control plane create cloud VMs for a namespace.
- CloudAccountWhich cloud identity Ringleader uses for one organization and one cloud account, and the limits on how that account's workstations can be reached.
- SSHKeyForward a local private key into workstations as an ambient ssh-agent, so processes on the workstation can authenticate outbound.
- ProvidersHow a workstation is placed on a backend: the default local provider, the vz, lima, qemu, wsl2, hcs, GCP, Azure and AWS providers, and their config knobs.
- Access controlNamespaces, ownership, the seeded RBAC roles, and Grants: who can see, change, SSH into, and read your resources.
- PolicyConstrain what a workstation manifest may name: which git repositories it may clone, where it may connect out to, and which LLM models an Integration may name.
- OrganizationsThe tenancy layer above namespaces: a company, its verified domain, how people join it, and who administers it.
- ServiceAccountA non-human identity your CI or automation becomes, with no stored secret: it trusts an external issuer, not a password.