AI app builder self hosted Kubernetes tutorial
You describe the app in chat on my-app.engineer, AI agents build it into a real repository, and it deploys as a Helm release onto a K3s cluster you own, not a sandbox. You can join your own hardware (including a Mac) as a node so the running cost approaches zero.
Last updated
You describe the app in chat on my-app.engineer, AI agents build it into a real repository, and it deploys as a Helm release onto a K3s cluster you own, not a sandbox. You can join your own hardware (including a Mac) as a node so pods schedule onto it like any other node. This is not a page about Kubernetes in general, and it is not a "self hosted kubernetes reddit" thread of opinions. It is a walkthrough of building and deploying one specific AI application on this platform, from an empty chat window to a running address, with the real commands and the real outputs you see along the way.
One boundary up front: this platform does not teach you to install Kubernetes from scratch on bare metal. It gives you a K3s cluster that is yours, and lets you bring your own nodes into it. If your question is "how do I install k3s myself on a Raspberry Pi," that is a different tutorial on a different site. What this page covers is the path from idea to running AI app on a cluster you own, using the platform's agents and deploy pipeline. For the broader question of whether AI agents can really build you something production-grade, see /learn/can-i-really-build-an-app-with-ai.
How do I start building an AI app on a self-hosted cluster?
Open my-app.engineer and start a new chat. Type a plain-language description of what you want. Not a spec, not a form. The sentences you would use to explain the idea to a colleague. For this walkthrough, the app is a product description generator: it reads a SKU and a product name from a Postgres table, calls an LLM to write an SEO-optimised product description, and stores the result back in the database with a timestamp. A simple web interface lets you enter a SKU and see the generated description.
Before anything is built, the platform returns an editable capability blueprint. This is a list of what it thinks you asked for, written as capabilities you can add, remove, or edit. For the product description generator, the blueprint looks like this:
- Web interface with a single form (SKU input, submit button, result display)
- Postgres database with a
productstable (columns:sku,name,description,generated_at) - LLM integration for generating SEO descriptions from product name and SKU
- API endpoint
POST /generatethat takes a SKU, fetches the product, calls the LLM, stores the result - Deploy as
deliverybuild type (real database, QA up to four iterations)
You can edit this blueprint in the chat before approving it. This is where a wrong assumption is cheap to fix. If the blueprint assumed you wanted user authentication and you did not, you remove it here. After the build, removing a capability means rebuilding. Once you approve the blueprint, the manager agent turns it into a build plan, and the builder agent writes real source into a real Git repository.
The build type matters here and must be chosen before the first line is written. demo means no payments, memory only, one QA pass. Fine for showing something works but nothing persists. delivery means a real Postgres database, payments wired to a client's own account, QA up to four iterations. product means a real database, payments provisioned automatically, QA up to five iterations, and it is treated as a business of its own. A demo that later needs to take money is not upgraded in place. It is rebuilt as the type it should have been, because payments and persistence reach into every part of the app. For this walkthrough, delivery is the right type: the app needs a real database, and the client (you) owns it.
How do I deploy the AI app on Kubernetes, including self-hosted Mac?
When you approve the blueprint, the builder agent writes the source and the deploy pipeline takes over. The app lands on a K3s cluster as a Helm release, in a namespace that belongs to your account. If the app needs a database (this one does), Postgres is deployed alongside it in the same namespace. The deploy runs helm upgrade --atomic, which means a zero-downtime rolling update on K3s, and a release that fails its health checks rolls back rather than half-landing. You do not run the helm command yourself, the pipeline does, but knowing what it runs tells you what to expect when something goes wrong.
The app answers on <app>.<user>.my-app.engineer. For this walkthrough, if your username is jordan and you named the app describethat, the address is describethat.jordan.my-app.engineer. You can point a custom domain at it afterwards. The routing layer handles the TLS certificate. Open that address in a browser and you should see the form: a text input labelled SKU, a submit button, and an empty result area below.
To join your own Mac as a node in the cluster, use the bring-your-own-node path. Your Mac joins the cluster over a private network and becomes a schedulable node. Pods land on it like any other node. The practical effect is that the running cost of the app approaches zero if your own hardware is doing the work. The Mac needs to be awake and networked for pods scheduled onto it to keep running, if it sleeps, those pods are rescheduled elsewhere if capacity exists, or go pending if it does not. This is not magic. It is Kubernetes scheduling, and the same rules apply as any cluster with a flaky node.
How to self host an AI agent?
The AI agents on this platform are the builders, not the product. They design, write, and deploy your app. What you self-host is the app they built, which may itself be an AI application, in this case, a product description generator that calls an LLM. The app runs in your K3s cluster as a container. The LLM call itself goes to whichever provider the app is configured to use (OpenAI, Anthropic, a local model server). The platform does not host an LLM for you. If you want the LLM inference itself to be self-hosted, you would run something like Ollama or vLLM as another service in the cluster, and point your app at it. That is a real and supported pattern, it is just another container in the same K3s cluster, but the platform's agents do not set it up for you automatically. You describe it in the blueprint ("call a local Ollama instance at http://ollama:11434 for text generation") and the builder wires the app to that endpoint. Whether Ollama is already running in your cluster or needs to be deployed is something you handle or ask the agents to handle as part of the build.
For the walkthrough app, let us say you want to use Ollama running on your Mac node. You would add to the blueprint: "The LLM endpoint is a local Ollama instance running at http://ollama-cluster:11434/v1, model llama3. Deploy Ollama as a service in the cluster." The builder agent then writes the app to call that endpoint instead of an external API, and deploys Ollama as a Helm release in the same namespace. The app's POST /generate handler fetches the product row from Postgres, constructs a prompt, POSTs it to the Ollama service, and writes the response back to the description column. You test it by entering a SKU in the web form, pressing submit, and seeing the generated description appear. If Ollama is not running or the model is not pulled, you get a connection error in the response, that is the signal to check the Ollama pod.
What does the QA agent actually check?
After the deploy, a separate QA agent opens the deployed app in Ghost Browser, a real Chromium instance the agents drive, and checks it does what the blueprint said. For the product description generator, QA would open describethat.jordan.my-app.engineer, enter a real SKU into the form, press submit, and verify that a description comes back and is non-empty. A build that does not pass QA does not get called done. For a delivery build, QA runs up to four iterations: if the first pass fails (the description comes back empty, or the form does not submit), the builder agent gets the failure report, fixes the code, redeploys, and QA tries again. You see each iteration in the chat as it happens.
The QA agent is why a wrong assumption caught at the blueprint stage is cheaper than one caught after the build. If the blueprint said the form should accept a SKU and the builder built it to accept a product name instead, QA catches the mismatch, but you have already spent a build cycle. Editing the blueprint before approval costs nothing. For more on what the agents can and cannot reliably do, see /learn/how-to-build-an-app-with-ai-agents.
What goes wrong when you self-host on Kubernetes?
Three real failures have happened on this platform, and they are the ones most likely to hit you if you are running a cluster with your own hardware.
Storage replicas starved etcd. Longhorn was configured with multiple replicas on what was a single node. The replication traffic and disk contention starved etcd until the control plane crash-looped and the cluster stopped responding entirely. The fix is a rule rather than a setting: on a single node, set Longhorn to one replica. Redundancy across replicas of the same disk is not redundancy, it is load. If you are running a single-node cluster (which is what most people running a Mac as a node effectively have), check your Longhorn replica count. It should be 1, not 2 or 3.
A Postgres major version bump crash-looped a database. An image tag moved from Postgres 15 to 16. Postgres does not upgrade its data directory across a major version on start, so the container came up, refused the existing data, and restarted forever. The database is now pinned to its major version, and a major upgrade is a deliberate migration, never a tag change. If you see a Postgres pod in a CrashLoopBackOff after what should have been a routine update, check whether the image tag jumped a major version. The fix is to roll back to the previous tag and plan a proper pg_upgrade migration.
What about self-hosted AI training?
This platform does not do AI training. It builds and deploys applications, some of which call LLMs. If you want to fine-tune a model, run distributed training across Kubernetes nodes, or set up a training pipeline, that is a different problem and a different toolset. You could in principle run a training job as a pod on your K3s cluster, it is just Kubernetes, but the platform's agents are not built to set that up, and pretending they are would waste your time. For self-hosted AI training, look at tools purpose-built for it. What this platform does is put the app that uses the model into a cluster you own, with the source as a real repository you could run anywhere Docker runs.
What my-app.engineer does about this
The platform gives you a K3s cluster that is yours from the first deploy, AI agents that build the app from a chat description, and a deploy pipeline that runs helm upgrade --atomic on push. You bring your own nodes (including a Mac) to drive the running cost toward zero. The source is a real Git repository, not a proprietary export. Nothing about the runtime is invented, Kubernetes, Helm, Postgres, Docker, so somebody who knows those knows this. Where it is the wrong answer: if you want a landing page and never want to think about infrastructure, a hosted builder will feel like less machinery for the job, and this will feel like more.