{"slug": "how-i-built-a-dsl-for-infrastructure-in-10-days-with-ai", "title": "How I built a DSL for infrastructure in 10 days with AI", "summary": "A developer built Infra Lang, an infrastructure-as-code DSL that compiles a single service definition into Kubernetes manifests, Docker Compose, Helm charts, Terraform HCL, and GitHub Actions workflows, with an LSP and live Kubernetes E2E tests. The project was developed in 10 days with extensive AI assistance using Claude, and the developer reports that mutation testing revealed coverage gaps despite high line coverage, leading to targeted fixes that improved mutation scores to 82-100% in critical modules.", "body_md": "Lessons from building infra-lang — an IaC DSL with 5 compilation targets, an LSP, and live K8s E2E tests. What worked, what surprised me, and what I'd do differently.\n\nEvery team I've worked with maintains the same application in at least three formats: Kubernetes manifests for production, a `docker-compose.yml`\n\nfor local dev, and a GitHub Actions workflow for CI. Every change touches all of them. They drift. And bugs in the K8s YAML only surface when `kubectl apply`\n\nrejects them — not when you write them.\n\nI wanted one file that compiles to all of them. So I built [Infra Lang](https://github.com/TuviDev/infra-lang).\n\n```\nservice api {\n    image: \"myapp/api:v1.0.0\"\n    replicas: 3\n    port 8080\n    health http(\"/health\")\n    resources {\n        requests { cpu: 200m, memory: 256Mi }\n        limits   { cpu: 1000m, memory: 512Mi }\n    }\n}\n```\n\nThat block compiles to a Kubernetes Deployment + Service, a Docker Compose service, a Helm chart, Terraform HCL, or a GitHub Actions workflow. One source of truth, five targets.\n\nWhy a DSL, not YAML templates\n\nHelm, Kustomize, and string interpolation in CI all push the same problem down the road: you still write YAML, just with placeholders. Validation still happens late.\n\nA real DSL gives you three things:\n\nA parser that catches errors immediately. Infra Lang uses a hand-written LALR(1) grammar with {} blocks. A typo is caught at parse time with a location and a helpful message — not after you deploy.\n\nCompile-time linting. 10 security rules catch hardcoded secrets, mutable image tags, and privileged containers. 13 reliability rules catch thundering-herd replica counts, databases without backups, and single-replica Kafka. Error-severity findings block compilation entirely.\n\nOne mental model. You think in services, databases, queues, and pipelines — not in individual YAML documents for each platform.\n\nThe AI-assisted process\n\nI want to be transparent: this project was built with extensive AI assistance — about 40 sessions over 10 days using Claude as a coding partner.\n\nHere's how the process actually worked:\n\nI owned every architecture decision. The DSL syntax, which backends to support, what the LSP should do, how to structure tests. AI doesn't make those calls.\n\nAI wrote implementation and tests. I reviewed, ran, and iterated. Every session had a specific scope: \"add semantic tokens to LSP\", \"fix Compose secret mounting\", not \"build me a DSL\".\n\nI ran everything locally. Docker Desktop, kind for Kubernetes E2E, real helm lint, real docker compose up. AI can't do that.\n\n27 real bugs were found through the process. Secret base64 encoding that passed unit tests but failed kubectl apply. Service port naming that Kubernetes rejected. Windows URI path conversion that crashed the LSP. These are things you only find by actually running the code against real targets.\n\nIs there risk in AI-assisted development? Yes — I don't know 100% of the codebase intimately. But the code runs, tests pass on 3 operating systems and 3 Python versions, and the output is validated against real Kubernetes clusters.\n\nWhat surprised me\n\nCoverage lies\n\n93% line coverage sounded impressive. Then I ran mutation testing — automatically introducing bugs into the code and checking whether tests catch them.\n\nResults: some modules had 34% mutation score despite high line coverage. The tests executed the code but didn't verify the output. A test that says assert result is not None gives you coverage but catches nothing.\n\nAfter two sessions of targeted fixes, critical modules reached 82-100% mutation score. The lesson: line coverage tells you what code ran, not whether your tests actually work.\n\nCross-platform is harder than you think\n\nMy first CI run on Windows failed because .read_text() without encoding=\"utf-8\" uses the system default (cp1252 on Windows). Every file read in the entire codebase needed explicit UTF-8.\n\nDocker daemon detection needed special handling too — Windows CI runners have the Docker CLI installed but no running daemon. docker version succeeds but docker compose up fails. The fix: check docker info exit code, not just whether the binary exists.\n\nThe LSP was the most rewarding part\n\nBuilding a language server taught me more about developer experience than anything else in this project. Each feature had its own challenge:\n\nCross-file rename needed word-boundary-aware regex — renaming db shouldn't touch main-db\n\nSemantic tokens required a line-based tokenizer that doesn't crash on malformed input\n\nSignature help needed brace-balance counting to detect which block the cursor is inside\n\nWorkspace indexing needed to scan files on disk without blocking the main LSP thread\n\nThe result: completion, hover, diagnostics, go-to-definition, find-references, rename, semantic tokens, signature help, document highlight, and folding — all working across every .infra file in the project.\n\nLive E2E tests catch what unit tests miss\n\nThree of the most serious bugs were invisible to unit tests:\n\nKubernetes Secrets with invalid base64 — unit tests checked structure, kubectl apply rejected the values\n\nMulti-port Services without port names — valid YAML, invalid Kubernetes API\n\nCompose secrets declared but never mounted to services — file existed, container couldn't access it\n\nNow there's an opt-in test suite that actually spins up a kind cluster, runs kubectl apply, starts docker compose up, and runs helm lint --strict. These tests found real bugs that 1800+ unit tests missed.\n\nWhat I'd do differently\n\nStart with PyPI from day 1. I spent the first week telling people to pip install git+[https://github.com/](https://github.com/).... The friction was enormous. Once I published to PyPI, installation became pip install infra-lang — 5 seconds instead of a paragraph of instructions.\n\nWrite blog posts before launching. SEO takes weeks to build. Dev.to articles, technical deep dives, comparison posts — all of these should exist before you post on HN, not after.\n\nBuild community before features. I built 5 backends, a full LSP, Helm chart generation, and live E2E tests. Then I posted on Hacker News and got 13 upvotes. Features don't create adoption. Reach does.\n\nThe numbers\n\n1877 tests, 93% line coverage, mutation testing on all critical modules\n\n5 backends: Kubernetes, Helm, Docker Compose, Terraform, GitHub Actions\n\nLSP with 10+ features including completion, hover, rename, semantic tokens, and signature help\n\nCI on Linux, macOS, Windows across Python 3.11, 3.12, 3.13\n\nLive E2E: real kubectl apply on kind, real docker compose up, real helm lint\n\nTry it\n\nBash\n\npip install infra-lang\n\ninfra --help\n\nOr with the VS Code language server:\n\nBash\n\npip install 'infra-lang[lsp]'\n\nLinks:\n\nIf you maintain infrastructure in multiple formats, I'd love your feedback — especially on language design and which compilation targets matter most.", "url": "https://wpnews.pro/news/how-i-built-a-dsl-for-infrastructure-in-10-days-with-ai", "canonical_source": "https://dev.to/tuvidev/how-i-built-a-dsl-for-infrastructure-in-10-days-with-ai-120n", "published_at": "2026-08-19 20:34:36+00:00", "updated_at": "2026-08-19 20:43:43.383016+00:00", "lang": "en", "topics": ["developer-tools", "artificial-intelligence", "ai-tools"], "entities": ["Infra Lang", "Claude", "Kubernetes", "Docker", "Helm", "Terraform", "GitHub Actions"], "alternates": {"html": "https://wpnews.pro/news/how-i-built-a-dsl-for-infrastructure-in-10-days-with-ai", "markdown": "https://wpnews.pro/news/how-i-built-a-dsl-for-infrastructure-in-10-days-with-ai.md", "text": "https://wpnews.pro/news/how-i-built-a-dsl-for-infrastructure-in-10-days-with-ai.txt", "jsonld": "https://wpnews.pro/news/how-i-built-a-dsl-for-infrastructure-in-10-days-with-ai.jsonld"}}