A project to practice AI and distributed systems using Minecraft as an excuse. It should involve the following topics:
- Coding: enough guardrails to quickly code with the assistance of AI
- Infrastructure: usage of remote or local models
- Operations: deployment of games, agents, bots, backups
- Security
- Performance
- Observability: using grafana dashboards, alerts
- Playing: it should be fun
- Prism launcher: https://prismlauncher.org/download/macos/
Apply the monitoring stack with:
kubectl apply -k k8s/overlaysFor local access, run:
kubectl port-forward deployment/grafana 3000:3000The Prometheus datasource is provisioned automatically from
http://prometheus-service.default.svc.cluster.local:9090.
Kubernetes container stdout/stderr logs are collected by Grafana Alloy on every
ready node and retained in Loki for 30 days. Grafana, Prometheus, Loki, and
Alloy run in the observability namespace. Before applying the manifests,
label exactly one ready node for the observability workloads and Loki's local
persistent volume:
kubectl label node NODE_NAME m-ai/observability=trueLoki stores data at /k3s-loki on that node. Query the provisioned Loki
datasource in Grafana Explore, for example:
{namespace="default", pod=~"m-ai-bot-.*"}
Set DATABASE_URL to the PostgreSQL connection URL used for world storage.
For Kubernetes, create k8s/overlays/local.yaml from
k8s/overlays/local.yaml.template and set the PostgreSQL password, connection
URL, player name, and external node addresses.
Set image in k8s/overlays/local.yaml to the pushed commit image tag before
applying the overlay.
The daemon applies pending SQL migrations when it starts.
To update the active world's main player from the applied local Kubernetes configuration, run:
./scripts/m-ai.sh sync-main-playerExport the world data from the running Minecraft pod to a local archive named
minecraft-world-YYYY-MM-DD-HHMMSS.tar:
./scripts/m-ai.sh export-worldImport an archive into the running pod, replacing its current world data:
./scripts/m-ai.sh import-world minecraft-world-YYYY-MM-DD-HHMMSS.tarThe world ID is included in each archive. Importing it switches the daemon to the matching database data. Archives without an ID receive a new one. New worlds receive a new ID automatically.
Clear the world data and restart the Minecraft deployment to generate a new world:
./scripts/m-ai.sh new-worldAccess pgAdmin locally with:
kubectl port-forward deployment/pgadmin 8080:80Sign in at http://localhost:8080 as admin@m-ai.example with the
postgres-password value from k8s/overlays/local.yaml. The m_ai server is
preconfigured.
Set MAIN_PLAYER to initialize the mainPlayer property when a new world is
created. Existing world data is not changed.
The image helper builds both linux/amd64 and linux/arm64 closures and
images. Run:
./scripts/m-ai.sh build-image
./scripts/m-ai.sh deploy-imageOr run both steps with:
./scripts/m-ai.sh build-deploy-imageList tags by their newest platform image creation time:
./scripts/m-ai.sh list-image-tagsUpdate k8s/overlays/local.yaml to use the newest pushed commit image:
./scripts/m-ai.sh use-latest-imageThe architecture-specific images are pushed with -amd64 and -arm64
suffixes, and the full Git commit SHA is published as a multi-platform image
index. Set M_AI_REGISTRY_HOST directly or in .env to configure the registry
host.
For example:
M_AI_REGISTRY_HOST=registry.exampleCopy .env.example to .env for a local configuration. M_AI_IMAGE can still
override the complete image reference. Dependencies are installed separately
for each architecture under build/node_modules-amd64 and
build/node_modules-arm64. Docker must have arm64 emulation enabled when
these commands run on an amd64 host.
For an HTTP registry, configure BuildKit and the M-AI Buildx builder declaratively on the NixOS host that runs image builds:
{
environment.etc."buildkitd.toml".text = ''
[registry."192.168.1.50:5000"]
http = true
insecure = true
'';
services.m-ai.dockerImageBuilder = {
enable = true;
user = "igncp";
home = "/home/igncp";
};
}The builder is configured in the Docker client state of user, so it must be
the same user that runs m-ai.sh. Apply the NixOS configuration before
building. Confirm the service and builder with:
systemctl status m-ai-buildx.service
docker buildx inspect m-ai-multiarchbuildkitdConfig defaults to /etc/buildkitd.toml. Set it in the NixOS
configuration when the configuration is stored elsewhere.
The dashboard in k8s/base/grafana-dashboard.json is generated with the
Grafana Foundation SDK. Regenerate it after changing
scripts/generate_grafana.ts with:
./scripts/m-ai.sh generate-grafanaMIT