Skip to content

Examples

llms.txt lists every page for an agent
Optional: hand this page to your coding agentThe steps work by hand too.
Show the whole prompt
Read https://intentius.io/chant/lexicons/docker/examples/.
Write the Compose services and Dockerfiles I describe in src/, starting from the closest example on the page, with each Dockerfile as an ordered `steps` list.
Run `npx chant build src --lexicon docker -o docker-compose.yml`, `npx chant lint src` and `docker compose config --quiet` until all pass, and open a pull request. Do not push an image.
Never deploy to a real cloud account or shared environment (with `chant run`, `chant components` or a platform's own CLI), approve (a pull request review, `chant approve` or `chant run approve`), override a policy denial (`chant approve policy-override`), or merge; never cut or publish a release (`chant release cut --yes` or `chant release publish`), push or delete a `ci/*` tag (`chant ci tick` pushes them), or change the value of an existing flag; never touch `.chant/allowed_signers` or `chant/lifecycle`.

API service + PostgreSQL + named volume.

import { Service, Volume, env } from "@intentius/chant-lexicon-docker";
export const db = new Service({
image: "postgres:16-alpine",
environment: {
POSTGRES_DB: "myapp",
POSTGRES_USER: "myapp",
POSTGRES_PASSWORD: env("DB_PASSWORD", { required: true }),
},
volumes: ["pgdata:/var/lib/postgresql/data"],
restart: "unless-stopped",
healthcheck: {
test: ["CMD-SHELL", "pg_isready -U myapp"],
interval: "10s",
timeout: "5s",
retries: 5,
},
});
export const pgdata = new Volume({});
export const api = new Service({
image: env("API_IMAGE", { default: "myapp:latest" }),
ports: ["8080:8080"],
environment: {
DATABASE_URL: "postgresql://myapp:${DB_PASSWORD}@db:5432/myapp",
},
depends_on: ["db"],
restart: "unless-stopped",
});
export const redis = new Service({
image: "redis:7-alpine",
volumes: ["redisdata:/data"],
command: "redis-server --appendonly yes",
restart: "unless-stopped",
});
export const redisdata = new Volume({});
import { Service, DockerConfig } from "@intentius/chant-lexicon-docker";
export const nginxConf = new DockerConfig({ file: "./nginx.conf" });
export const proxy = new Service({
image: "nginx:1.25-alpine",
ports: ["80:80", "443:443"],
configs: [{ source: "nginxConf", target: "/etc/nginx/nginx.conf" }],
depends_on: ["api"],
restart: "unless-stopped",
});

The build stage copies the manifests and installs before copying the source, so the install layer is reused until the manifests change. The runtime stage copies only the built app and its production dependencies, and runs as node.

import { Dockerfile, Service } from "@intentius/chant-lexicon-docker";
export const app = new Dockerfile({
stages: [
{
from: "node:20-alpine",
as: "build",
steps: [
{ workdir: "/app" },
{ copy: "package.json package-lock.json ./" },
{ run: "npm ci" },
{ copy: "src/ ./src/" },
{ run: "npm run build" },
{ run: "npm prune --omit=dev" },
],
},
{
from: "node:20-alpine",
steps: [
{ workdir: "/app" },
{ copy: "--from=build /app/node_modules ./node_modules" },
{ copy: "--from=build /app/dist ./dist" },
{ user: "node" },
{ expose: 3000 },
{ cmd: ["node", "dist/index.js"] },
],
},
],
});
export const api = new Service({
build: { context: ".", dockerfile: "Dockerfile.app" },
ports: ["3000:3000"],
restart: "unless-stopped",
});

Dockerfile.app:

FROM node:20-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY src/ ./src/
RUN npm run build
RUN npm prune --omit=dev
FROM node:20-alpine
WORKDIR /app
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
USER node
EXPOSE 3000
CMD ["node","dist/index.js"]

To share stages or steps between Dockerfiles, see Sharing stages and steps between Dockerfiles.

import { defaultLabels, Service, Volume } from "@intentius/chant-lexicon-docker";
export const labels = defaultLabels({
"com.example.team": "platform",
"com.example.managed-by": "chant",
});
export const api = new Service({ image: "myapp:1.0" });
export const db = new Service({ image: "postgres:16-alpine" });
// Both api and db inherit the labels above

chant