A Kubernetes-native, capability-driven game platform.
⚠️ DISCLAIMER: EXPERIMENTAL HOBBY PROJECTThis project is fully experimental and is not intended for wider consumption or use. The stated goals are intentionally broad and likely unachievable in a real-world product context; however, they serve the purpose of this hobby project.
Note on Authorship: This repository is now public. Please be aware that almost all code and documentation within this repository were generated by AI. It serves as an exploration of AI-assisted development rather than a demonstration of personal coding expertise.
Bindery Core is an open-source platform designed to decouple game logic from infrastructure. It allows game developers to define their game's backend requirements as abstract "Capabilities" (e.g., Physics, Persistence, Messaging), which the platform then resolves and binds to concrete infrastructure implementations at runtime.
- Decouple Logic from Infrastructure: Game modules declare what they need, not how it's provided.
- Game-as-Code: Define entire game worlds, shards, and module dependencies via declarative Kubernetes CRDs.
- Automated Orchestration: Automate the lifecycle of game servers, including sharding, scaling, and storage provisioning.
- Standardized Contracts: Use strict gRPC contracts and semantic versioning to ensure module compatibility.
Status: 🚧 Pre-Alpha / Experimental 🚧
The project is currently in active development.
- Core Controllers (all six registered in
main.go):CapabilityResolver: Resolves abstract requirements to concrete providers.RuntimeOrchestrator: Manages the lifecycle of game server workloads (Deployments, Services).StorageOrchestrator: Provisions and binds persistent storage (PVCs) for stateful modules.WorldShard: Creates and removesWorldShardobjects to matchWorldInstance.spec.shardCount.Realm: Binds realm-scoped global modules shared across worlds.ShardAutoscaler: AdjustsWorldInstance.spec.shardCountwithinminShards/maxShards.
- APIs: v1alpha1 CRDs are defined but subject to breaking changes. Nine
CRDs ship in
k8s/crds/, mirrored byte-for-byte inhelm/bindery-core/crds/. - Deployment: Supports local development via Kind and Helm.
Alongside the Kubernetes operator, this repository contains the external runtime reference service: a control plane for matches whose simulation runs in game clients Bindery does not own. Bindery hosts the match envelope and the transport; it is not an authoritative game server, and game-specific code stays out of core.
It was developed on a separate line of history and merged into main on
2026-08-26. It shares the module but not the operator's runtime: there are no
CRDs or controllers involved, and the two are wired together only by living in
one repository with one CI.
- Service and relay:
internal/externalruntime,internal/relay,pkg/relayv1 - Evidence reconciliation:
pkg/evidencev1(wired intointernal/externalruntime/service.go) - Capture plane:
internal/capture(canonical encoding, content-addressed object store, normalizers) wired intointernal/externalruntime— durable batch ingest, a heavy-object lane, completeness manifests, cursor-paged public reads, and versioned derivations - Calibrated gates:
pkg/gatev1, consumed byinternal/externalruntime/capture_gate.go, which evaluates the consequential gatebindery.capture.completenessover every capture before it may contribute to an evidence set - Binaries:
cmd/bindery-external-runtime,cmd/bindery-udp-relay,cmd/bindery-redaction-scan - Promoted contracts:
contracts/externalruntime/v1 - Chart:
charts/bindery-external-runtime - Image:
ghcr.io/bayleafwalker/bindery-external-runtime, built fromDockerfile.external-runtimeand published frommainand tags
The repository has two chart roots on purpose. helm/bindery-core deploys the
operator and ships the CRDs; charts/bindery-external-runtime deploys a
standalone service that defines no CRDs and runs no controllers. They have
different lifecycles and different install audiences, so they are versioned
separately rather than folded into one chart directory. Only helm/ is covered
by make verify-crds, because only helm/ carries CRDs.
They also deploy different images, which is worth stating plainly because they briefly did not:
| Chart | Dockerfile | Image |
|---|---|---|
helm/bindery-core |
Dockerfile |
ghcr.io/bayleafwalker/bindery-core |
charts/bindery-external-runtime |
Dockerfile.external-runtime |
ghcr.io/bayleafwalker/bindery-external-runtime |
Both are published by the image job in CI, from main and from tags only, with
an SBOM and build provenance attestation each. Each chart's image.tag defaults
to its own chart appVersion, so a chart cannot drift from the image it deploys.
Keeping these apart matters: until 2026-08-26 both charts named
ghcr.io/bayleafwalker/bindery-core, while the only Dockerfile in the repository
built the external-runtime binaries. Restoring the publish job unchanged would
have meant helm install bindery-core deploying the external-runtime service
instead of the operator.
Observation summaries are derived by the broker from persisted events. For
any execution with captured streams, client-supplied counts are refused with
OBSERVATION_ADJUDICATION_FORBIDDEN. That is deliberate: the one demonstrated
RA2 run was scored by an adapter gate that was confidently wrong in both
directions across four iterations, and an evidence set built from figures the
adapters reported about themselves cannot support a claim of independence.
Repeating the run through this control plane is roadmap item ERH-006 and is
still pending — the enabler landed, the run has not happened.
The control plane persists identity, session, placement, execution, enrollment, capture, idempotency, and reconciled evidence through a crash-safe single-writer state store. Capture event bodies and heavy artifacts are content-addressed files beside the snapshot rather than inside it, so a snapshot write stays proportional to the number of batches rather than the number of events. That file-backed mode is deliberately not a multi-replica database: the chart refuses to render with more than one replica, and running wider would need a shared relational store.
GET /v1/sessions is intentionally not implemented. Known session IDs are
public; discovery is not. The same known-ID rule applies to placements,
executions, enrollments, captures, and evidence sets.
make verify-external-runtime # race tests, vet, chart lint
BINDERY_RELAY_ENDPOINT=127.0.0.1:50001 \
BINDERY_BUILD_REVISION="$(git rev-parse HEAD)" \
BINDERY_STATE_PATH=/tmp/bindery-control-state.json \
go run ./cmd/bindery-external-runtimeThat /tmp path is disposable development state; deployments mount a volume.
The RA2 path has been demonstrated end to end once, and the dated result and
its limits — including why the pre-hardening run's identifiers must not be
backfilled — are recorded in
docs/assessments/2026-08-25-ra2-vertical-slice.md.
The evidence and gate boundary is described in
docs/architecture/evidence-and-gates.md,
and remaining work is tracked in
docs/roadmap/post-ra2-hardening.yaml.
The research pack under
docs/research/external-runtime-multiplayer
is immutable input, not a committed roadmap.
Start at the documentation index, which explains which of the two subsystems each document covers.
- Standards Index
- Capability Model
- Module Manifest
- Platform Architecture
- Realm Architecture
- Shard Autoscaling
- Booklets & Game Repositories
- Debugging Runtime Coordination
- Evidence, reconciliation, and gates
- RA2 vertical slice assessment
- Post-RA2 hardening roadmap
- Wire contract v1
- Go 1.22+
- Docker
- Kind (Kubernetes in Docker)
- Kubectl
Spin up a local Kind cluster with all CRDs and example resources installed:
make kind-demoTear it down:
make kind-down- Unit Tests:
make test - Integration Tests:
make test-integration(Requires envtest) - E2E Smoke Test:
make test-e2e(Requires Kind and Docker; creates and destroys a cluster, and covers the sharding path end to end — scale out to two shards, per-shard deployments, then scale back) - CRD Gate:
make verify-crds— asserts every scheme-registered kind has a manifest ink8s/crds/, and thatk8s/crds/andhelm/bindery-core/crds/are identical - Pre-push check:
make verify(operator) ormake verify-external-runtime(external runtime)
All of the above run in CI (.github/workflows/ci.yml), which has four jobs:
go-test (fmt, unit, verify-crds, envtest integration, tidy),
sample-game-test, e2e-smoke (Kind), and external-runtime (race tests, vet,
chart lint, secret scan).
Run the controller manager against your current kubecontext:
make run-controllerNote: make run-controller disables the metrics and health probe listeners to avoid occupying localhost:8080 (often used by the sample game web client port-forward). If you want the default controller-runtime ports (:8080/:8081), run:
make run-controller-with-metricsOperator:
api/v1alpha1/: Kubernetes API type definitions.controllers/: Kubernetes controllers (Reconcilers).main.go: Controller manager entrypoint.internal/resolver,internal/semver: Resolution logic used byCapabilityResolver.internal/graph: Unused scaffolding. Its own package comment says "no logic is implemented yet", and nothing outside the package imports it.k8s/crds/: CRD manifests (mirrored intohelm/bindery-core/crds/).k8s/dev/: Kind demo scripts.helm/bindery-core/: Helm chart for the operator.modules/: Module template (physics-engine-template).examples/booklet-bindery-sample/: Runnable sample game (its own Go module).e2e/: Kind-based smoke test.
External runtime:
internal/externalruntime,internal/relay,internal/harness,internal/capture.pkg/evidencev1,pkg/gatev1,pkg/relayv1.charts/bindery-external-runtime/: Helm chart for the standalone service.verification/: Verification context fixtures.adapters/: External-runtime adapter source.bindery-ra2-adapteris the Red Alert 2 adapter;bindery-dedicated-runtimeandbindery-openttd-runtimeare the two ERH-007 runtimes, the second of them driving an unmodified OpenTTD over its own admin protocol (make openttd-acceptance).
Shared:
cmd/: Binary entrypoints for both subsystems.contracts/:proto/(engine gRPC) andexternalruntime/v1(HTTP + relay).docs/: Documentation — seedocs/README.md.config/: RBAC and manager scaffolding.hack/: Verification scripts (verify-crds.sh,fetch-openttd.sh).