feat(templates): adding new templates - #125
Merged
Merged
Conversation
…lates
Grows the built-in catalogue from 22 to 51.
Engines (13): rustfs (S3-compatible), etcd, valkey, mailpit, clickhouse,
meilisearch, opensearch, neo4j, timescaledb, keycloak, jaeger, mosquitto,
consul.
Apps (16): go.app, rust.app, python.app -> {fastapi, django, flask},
elixir.phoenix, ruby.rails, java.spring, dotnet.aspnet, deno.app, smee,
vue.vite, svelte.kit, nuxt, astro.
One template per CONTAINER CONTRACT, not per framework. Go's chi/gin/echo and
Rust's axum/actix are libraries: same image, same air/bacon command, so they get
one template each rather than five. Python, Elixir and Ruby frameworks genuinely
differ in their run command, so those use extends children off a shared parent —
the pattern php.nginx -> php.laravel.nginx already established.
Every fact here was verified against the upstream image or docs rather than
assumed, which caught a number of things that would have shipped broken:
* bitnami/etcd is DEAD — subscription-only since Aug 2025, zero public tags.
Uses quay.io/coreos/etcd, which publishes no :latest and no floating :v3.6,
so the tag must be a full vX.Y.Z.
* etcd's image is distroless: /bin and /usr/bin are EMPTY. A CMD-SHELL or
curl-based healthcheck fails with "exec: sh: not found" forever, so it uses
exec-form etcdctl.
* Setting etcd's listen URLs without advertise URLs is a fatal startup error,
and listen URLs must be IP literals (shared-etcd there crashes on boot).
* ClickHouse with neither CLICKHOUSE_USER nor CLICKHOUSE_PASSWORD set DISABLES
network access entirely — the server starts and is simply unreachable.
* Keycloak ships neither curl nor wget; its healthcheck uses bash /dev/tcp, and
port 9000 stays closed unless KC_HEALTH_ENABLED=true.
* Mailpit's MP_DATABASE is the persistence switch, not the volume: a named
volume without it silently stores nothing.
* Meilisearch's volume must be the /meili_data DIRECTORY, not the .ms file.
* timescaledb-ha is NOT built on docker-library/postgres — PGDATA lives under
/home/postgres/pgdata, so DECISIONS D8's PG18 move does not apply.
* mosquitto 2.1 already ships a working anonymous config, so no conf mount is
needed; its persistence is off by default, so it deliberately has NO volume.
* jaeger and consul likewise get no volume: both store state in memory in dev
mode, and a volume would imply durability neither provides.
* cargo-watch is unmaintained (its own README redirects to bacon). bacon needs
--headless AND -j run-long: plain -j run buffers output until exit, which for
a server is never.
* air moved from cosmtrek to air-verse.
* redpanda was dropped from the plan on discovering the existing kafka template
already IS Redpanda.
Binding is the failure that would bite users hardest — a dev server on 127.0.0.1
inside a container looks healthy, publishes its port, and refuses every
connection. uvicorn, flask, rails, vite, astro and nuxt all default to loopback
and are explicitly overridden here; TestAppTemplatesBindAllInterfaces asserts it.
Phoenix is the exception with no env-var fix: its generated config/dev.exs binds
loopback and the template says so in a comment, because only the user can change
it.
Wiring: each engine gets its mandatory exposeEngines row (without one an engine
is invisible to `ports`, cannot be exposed and cannot be provisioned) plus a
connectionURL case so `devstack ports` prints something usable.
Tests: new engine lint table with a per-engine assertion on the detail that would
silently break it; app-template tests for bind-all-interfaces and for the
dependency dirs a bind mount would shadow (deps/_build, obj/bin, node_modules);
and two drift tests — every built-in must have a row in BOTH doc tables, and
every template dir must be in the go:embed list.
Those drift tests immediately caught pre-existing staleness: templates/README.md
had no rows for kafka/nats/rabbitmq/localstack/ministack, and
docs/guide/templates.md was missing the mysql/mariadb/mongodb/cassandra/arangodb
batch. Both tables are now complete.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The README still described six JS templates and made no mention of the AI-agent surface that landed in #124. * Replaces the framework-templates bullet with the real catalogue: apps across Go, Rust, Python, Node, Bun, Deno, PHP, Ruby, Elixir, Java and .NET plus the Vite family, and a second bullet listing the 25 shared engines. * Adds the `ai` group to the command table and `config schema` alongside `config validate/show`. * Documents that the whole docs corpus is readable from the binary, and links the new AI-agents guide. * Bumps the spec range to 32 and folds spec 32 into the status paragraph. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Grows the built-in catalogue from 22 to 51.
Engines (13): rustfs (S3-compatible), etcd, valkey, mailpit, clickhouse, meilisearch, opensearch, neo4j, timescaledb, keycloak, jaeger, mosquitto, consul.
Apps (16): go.app, rust.app, python.app -> {fastapi, django, flask}, elixir.phoenix, ruby.rails, java.spring, dotnet.aspnet, deno.app, smee, vue.vite, svelte.kit, nuxt, astro.
One template per CONTAINER CONTRACT, not per framework. Go's chi/gin/echo and Rust's axum/actix are libraries: same image, same air/bacon command, so they get one template each rather than five. Python, Elixir and Ruby frameworks genuinely differ in their run command, so those use extends children off a shared parent — the pattern php.nginx -> php.laravel.nginx already established.
Every fact here was verified against the upstream image or docs rather than assumed, which caught a number of things that would have shipped broken:
Binding is the failure that would bite users hardest — a dev server on 127.0.0.1 inside a container looks healthy, publishes its port, and refuses every connection. uvicorn, flask, rails, vite, astro and nuxt all default to loopback and are explicitly overridden here; TestAppTemplatesBindAllInterfaces asserts it. Phoenix is the exception with no env-var fix: its generated config/dev.exs binds loopback and the template says so in a comment, because only the user can change it.
Wiring: each engine gets its mandatory exposeEngines row (without one an engine is invisible to
ports, cannot be exposed and cannot be provisioned) plus a connectionURL case sodevstack portsprints something usable.Tests: new engine lint table with a per-engine assertion on the detail that would silently break it; app-template tests for bind-all-interfaces and for the dependency dirs a bind mount would shadow (deps/_build, obj/bin, node_modules); and two drift tests — every built-in must have a row in BOTH doc tables, and every template dir must be in the go:embed list.
Those drift tests immediately caught pre-existing staleness: templates/README.md had no rows for kafka/nats/rabbitmq/localstack/ministack, and docs/guide/templates.md was missing the mysql/mariadb/mongodb/cassandra/arangodb batch. Both tables are now complete.