Agent deployment platform on Kubernetes. Deploy, manage, and monitor AI agents at scale.
Live demo: ranch.cleanslice.org
Built with CleanSlice architecture.
Install the CLI globally — it auto-clones the project on first run:
bun add -g @cleanslice/ranch # or: npm install -g @cleanslice/ranch ranch dev # offers to clone if no checkout, then starts api + app + admin + local k3d
See cli/README.md for all ranch commands.
git clone https://github.com/CleanSlice/ranch.git
cd ranch
make initThe setup wizard will guide you through:
- Installing dependencies (Bun, Docker)
- Setting up local PostgreSQL and running migrations
- Optionally: configuring and deploying to Hetzner Cloud
After setup, start developing:
make dev # Starts api:3000 + app:3001 + admin:3002┌─────────────────────────────────────────────────────────┐
│ Hetzner Cloud │
│ │
│ ┌────────────┐ ┌────────────────┐ ┌───────────────┐ │
│ │ ArgoCD │ │ Argo Workflows │ │ CloudNativePG│ │
│ │ (GitOps) │ │ (Agent runs) │ │ (PostgreSQL) │ │
│ └─────┬──────┘ └──────▲さんかく─────────┘ └───────────────┘ │
│ │ sync │ submit │
│ ▼ │ │
│ ┌──────────────────────┴──────────────────────────┐ │
│ │ Agent Manager (api) │ │
│ │ NestJS + Prisma + CleanSlice │ │
│ └─────────────────────────────────────────────────┘ │
│ ┌─────────────────┐ ┌─────────────────────────────┐ │
│ │ Dashboard (app)│ │ Admin Panel (admin) │ │
│ │ Nuxt + Vue 3 │ │ Nuxt + Vue 3 │ │
│ └─────────────────┘ └─────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Agent Pods (dynamic, via Argo Workflows) │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
| Layer | Technology |
|---|---|
| Backend | NestJS, Prisma, PostgreSQL |
| Frontend | Nuxt 3, Vue 3, Pinia, Tailwind, shadcn-vue |
| Infrastructure | Terraform, Hetzner Cloud, k3s |
| Deployment | ArgoCD (GitOps), Argo Workflows |
| Runtime | Bun |
| Monorepo | Turborepo |
ranch/
├── api/ # NestJS backend
│ └── src/slices/
│ ├── setup/ # prisma, init, health
│ ├── user/ # auth + user
│ ├── agent/ # agent, file, pod, secret, template, templateFile
│ ├── workflow/ # Argo Workflows integration
│ ├── bridle/ # chat (sessions, messages, streaming)
│ ├── mcp/ # MCP runtime hosted at /mcp/*
│ ├── mcpServer/ # MCP server registry
│ ├── llm/ # LLM provider config
│ ├── skill/ # Reusable agent skills
│ ├── rancher/ # Per-tenant ranch (workspace) management
│ ├── reins/ # Access control / API keys
│ ├── setting/ # System settings
│ ├── usage/ # Usage metering
│ ├── log/ # Agent logs
│ └── aws/ # AWS-backed integrations (S3, etc.)
├── app/ # Nuxt user dashboard
│ └── slices/ # setup, agent, bridle, template, user, common
├── admin/ # Nuxt admin panel
│ └── slices/ # setup, agent, bridle, llm, mcpServer, rancher,
│ # reins, setting, skill, usage, user, common
├── cli/ # @cleanslice/ranch — published to npm
├── rancher/ # Default agent template ("rancher" agent)
├── terraform/ # Hetzner infrastructure
│ ├── modules/ # cluster, network, bootstrap, dns, database, storage, apps
│ └── environments/ # dev, prod, dreamvention (+ your custom env)
├── k8s/ # Kubernetes manifests
│ ├── argocd/ # App-of-apps
│ ├── infrastructure/ # Argo Workflows, CNPG, database
│ ├── platform/ # api, app, admin deployments
│ ├── templates/ # Argo WorkflowTemplate + RBAC for agents
│ ├── local/ # Local k3d-only manifests (CoreDNS host alias, etc.)
│ └── deploy/ # Deploy hooks
└── .github/workflows/ # CI/CD
- Bun —
curl -fsSL https://bun.sh/install | bash - Docker — for local PostgreSQL
- Terraform — for infrastructure
- kubectl — for cluster management
- Helm — for chart management
The ranch CLI wraps the most-used make targets and works from any
directory once installed globally. See cli/README.md
for the full reference.
bun add -g @cleanslice/ranch # one-time install ranch dev # start api + app + admin ranch dev api # or just one service: api | app | admin ranch down # stop dev servers, postgres, k3d ranch db start | stop | reset | studio ranch generate # regenerate Prisma schema from slices ranch status # show what's running locally ranch where # show which Ranch checkout the CLI is using
Equivalent targets, run from the project root:
make help # Show all commands # Development make setup # Full local setup (first time) make dev # Start all services (api:3000, app:3001, admin:3002) make dev-api # Start API only make dev-app # Start app only make dev-admin # Start admin only # Database make db # Start PostgreSQL via Docker make db-stop # Stop PostgreSQL make db-reset # Reset database (destroy data) make migrate # Generate schema + run migrations make generate # Regenerate schema.prisma from slices make studio # Open Prisma Studio # Build & Test make build # Build all services make lint # Lint all services make test # Run tests make clean # Remove node_modules and build artifacts
After ranch dev (or make dev):
| URL | Description |
|---|---|
http://localhost:3000 |
API (NestJS) |
http://localhost:3000/api |
Swagger UI — full endpoint reference |
http://localhost:3000/mcp/* |
MCP runtime (tools exposed via @Tool decorators) |
http://localhost:3000/health |
Health check |
http://localhost:3001 |
App (user dashboard) |
http://localhost:3002 |
Admin panel |
ranch dev also brings up a local k3d cluster (ranch) with the
platform and agents namespaces and Argo workflow templates pre-applied,
so the API can submit real agent workflows against a local Kubernetes.
Kubeconfig is written to ~/.kube/ranch-local.yaml.
For RAG-backed agents, a LightRAG + Ollama + Postgres stack ships behind a Docker Compose profile:
make lightrag-up # First run pulls ~3GB of models — LightRAG at :9621 make lightrag-down # Stop (keeps data) make lightrag-reset # Wipe data + models make lightrag-logs # Tail container logs
Each slice defines its own .prisma file at the slice root. They are merged into prisma/schema.prisma by prisma-import at build time.
api/src/slices/
├── setup/prisma/prisma.prisma # datasource + generator
├── agent/agent/agent.prisma # Agent model
├── agent/template/template.prisma # Template model
└── user/user/user.prisma # User model
Edit the slice .prisma files, then:
make generate # Merge into prisma/schema.prisma make migrate # Create migration + generate client
📘 Full Terraform guide (remote state backend, environments, imports, DNS, gotchas):
terraform/README.md
# Copy the dev template cp -r terraform/environments/dev terraform/environments/myenv # Edit variables vi terraform/environments/myenv/terraform.tfvars.example # Copy and fill in your values: cp terraform/environments/myenv/terraform.tfvars.example terraform/environments/myenv/terraform.tfvars
Required variables in terraform.tfvars:
hcloud_token = "your-hetzner-api-token" domain = "ranch.yourdomain.com" admin_ip = "YOUR_IP/32" # curl ifconfig.me ssh_public_key_path = "~/.ssh/id_ed25519.pub"
The k3s cluster requires MicroOS snapshots on Hetzner:
brew install packer # if not installed # Download and build snapshots cd /tmp curl -sLO https://raw.githubusercontent.com/kube-hetzner/terraform-hcloud-kube-hetzner/master/packer-template/hcloud-microos-snapshots.pkr.hcl packer init hcloud-microos-snapshots.pkr.hcl HCLOUD_TOKEN="your-token" packer build hcloud-microos-snapshots.pkr.hcl
make infra-init ENV=myenv # Download providers make infra-plan ENV=myenv # Preview changes make infra-apply ENV=myenv # Create cluster (~5-10 min)
This creates:
- k3s cluster with Traefik ingress and cert-manager
- VPC + Firewall
- Load Balancer
make kubeconfig ENV=myenv export KUBECONFIG=~/.kube/ranch-myenv kubectl get nodes
# Add Helm repos helm repo add argo https://argoproj.github.io/argo-helm helm repo add cnpg https://cloudnative-pg.github.io/charts helm repo update # Install ArgoCD helm install argocd argo/argo-cd \ --namespace argocd --create-namespace \ --set server.ingress.enabled=true \ --set server.ingress.ingressClassName=traefik \ --set "server.ingress.hosts[0]=argocd.ranch.yourdomain.com" # Install Argo Workflows helm install argo-workflows argo/argo-workflows \ --namespace argo --create-namespace # Install CloudNativePG helm install cnpg cnpg/cloudnative-pg \ --namespace cnpg-system --create-namespace # Create namespaces kubectl create namespace platform kubectl create namespace agents
Ranch ships five public services behind one shared Hetzner Load Balancer. You need an A record per subdomain at your DNS provider — the records themselves are not managed by Terraform (intentional: keeps the DNS zone your single source of truth and lets you change provider without touching the platform module).
Required A records — point each at the same Load Balancer IP:
| Subdomain | Serves | Required? |
|---|---|---|
ranch.yourdomain.com |
App (root, end-user UI) | yes |
api.ranch.yourdomain.com |
NestJS API | yes |
admin.ranch.yourdomain.com |
Admin panel (Nuxt) | yes |
argocd.ranch.yourdomain.com |
ArgoCD UI | yes |
browser.ranch.yourdomain.com |
Browser-pool live VNC view | yes — agents send users this URL for manual logins (Instagram, Meta Ads, etc.). Without it, every site that needs an interactive login is unreachable. |
Get the Load Balancer IP after terraform apply:
kubectl get svc -n traefik traefik -o jsonpath='{.status.loadBalancer.ingress[0].ip}' # or, equivalently, ask Terraform: terraform -chdir=terraform/environments/<env> output dns_records_needed
The dns_records_needed output lists every subdomain that needs a record
and the IP to point it at — keep this in sync if you ever add a new
public-facing ingress (otherwise cert-manager will spin forever on a
challenge that can't resolve).
Propagation: 1–5 min typical (set TTL=300). cert-manager then
issues a Let's Encrypt cert automatically via the HTTP-01 challenge —
the first hit to https://<subdomain>/ after propagation triggers it.
Smoke test once propagated:
for sub in "" api. admin. argocd. browser.; do host="${sub}ranch.yourdomain.com" printf "%-45s " "$host" curl -sS -o /dev/null -w "%{http_code}\n" "https://$host/" --max-time 5 || echo "(timeout)" done
All five should return a non-zero HTTP code (200/301/302/401 are all fine — means the cert handshake succeeded and Traefik routed the request).
# Get ArgoCD password make argocd-password # Login to ArgoCD UI at https://argocd.ranch.yourdomain.com # Username: admin # Password: <output from above> # Deploy app-of-apps make deploy
make k8s-secrets # Interactive — will ask for DATABASE_URLRanch is designed to be forked per-organization:
# 1. Fork CleanSlice/ranch → YourOrg/ranch # 2. Clone your fork git clone git@github.com:YourOrg/ranch.git cd ranch # 3. Add upstream git remote add upstream git@github.com:CleanSlice/ranch.git # 4. Create your environment cp -r terraform/environments/dev terraform/environments/yourenv # 5. Customize k8s manifests # - k8s/argocd/app-of-apps.yaml → change repoURL to YourOrg/ranch # - k8s/platform/*/ingress.yaml → change hostnames # - k8s/platform/*/deployment.yaml → change image registry # - Makefile → change ENV default # 6. Sync upstream changes git fetch upstream git merge upstream/main git push origin main
make k8s-status # Show nodes, pods, ArgoCD apps make k8s-logs-api # Tail API logs make argocd-password # Get ArgoCD admin password make infra-destroy ENV=myenv # Tear down infrastructure
git push → GitHub Actions:
├── CI (lint + test)
├── Build Docker images → ghcr.io
└── ArgoCD detects new image
└── Syncs to cluster (zero-downtime rolling update)
ArgoCD manages:
- Infrastructure — Argo Workflows, CloudNativePG, PostgreSQL cluster
- Platform — API, App, Admin deployments
- Templates — Argo WorkflowTemplates for agent pods
Private — CleanSlice