README Structure
All template READMEs should follow this standard structure. This ensures a consistent experience for users across all templates.
Required Sections
These sections must be present (checked by validate-docs.sh):
| Section | Purpose |
|---|---|
| Quick Start | Numbered copy-paste steps to install, configure, and run the template |
| Prerequisites | What needs to exist before the template works (DCT, UIS provision-host running, services deployed in cluster) |
| Project Structure | Directory tree showing the layout the user sees after dev-template <id> |
Optional Sections
These are recommended but not enforced:
| Section | Purpose |
|---|---|
| Development | How to edit, test, and debug the app |
| CI/CD | How the GitHub Actions workflow works |
| Try this with | Cross-references to related/companion templates |
| VS Code tip | One-line workspace setting the user can paste into their existing .vscode/settings.json (see "VS Code settings pattern" below) |
The Environment card
Every non-overlay template detail page on the website renders an Environment card below the TemplateHeader. The card is auto-generated by <TemplateEnvironment> from the template's template-info.yaml, vendored DCT/UIS data, and the template's manifests/deployment.yaml. Contributors don't write any of this by hand — it reads existing files.
The card has up to four numbered sub-sections:
| Sub-section | When it shows | Source |
|---|---|---|
| ① What gets set up | Always when there's anything to show | tools field (DCT) + requires/provides (UIS services) + init SQL files |
| ② Configure | When the template requires: services | Read from requires: and params: |
| ③ Setup | When quickstart.setup has commands | From quickstart.setup |
| ④ Run | When quickstart exists | From quickstart.run and quickstart.title |
For deeper details on what each sub-section renders and the full prop interface, see project-dev-templates.md → Auto-generated documentation sections.
The auto-generated Architecture section
Below the Environment card, non-overlay template pages render an Architecture section with per-diagram collapsible dropdowns. Today each sub-section has two diagrams:
- Components — a mermaid flowchart showing the named nodes (Developer, DCT, UIS, K8s, app, browser) and how they connect
- Flow — a mermaid sequence diagram showing the ordered steps at runtime (configure call, UIS provisioning, port-forward, .env write, app run)
Both are auto-generated from the template's template-info.yaml, the vendored DCT/UIS registry data, and the template's manifests/deployment.yaml. Contributors don't write any mermaid by hand. Click any diagram on the rendered docs page to enlarge it in an overlay.
The dropdowns are collapsed by default so developers who just want to run the template aren't confronted with a wall of SVGs. Section headings (### Local development / ### Deployment for app templates; ### Overview for stack templates) stay visible as signposts.
Adding a third diagram (e.g. Errors, Data flow, Network) to an existing section is a pure data change in scripts/lib/build-architecture-mermaid.ts's buildArchitectureModel function — push one { name, mermaid } entry onto the section's diagrams array. The emitter and the rendering path are unchanged.
The auto-generated Files dropdown
Inside the Getting Started card, every template page renders a collapsed Files (N) dropdown. When expanded, it shows a tree of every tracked file in the template, with each file linking to its source on GitHub. The list is auto-generated from git ls-files at build time — no curation, no file patterns to maintain.
- New files you
git addappear automatically on the next docs build - To exclude a file from the dropdown, add it to
.gitignore - Overlay templates show only files under their
template/subfolder (the installed content), not the metadatatemplate-info.yamlthat sits one level up
The dropdown is intentionally collapsed by default so it doesn't crowd the Prerequisites and Related-templates sub-sections.
The quickstart: block in template-info.yaml
Templates can declare a quickstart: block in template-info.yaml. It does two things:
- DCT's
dev-template installprints the run command at the end of the install output as a "Run your app" step - The website renders the Setup and Run sub-sections of the Environment card from the same data
The same data drives both surfaces — define it once, get it everywhere.
Schema
quickstart:
title: "Run the Flask app"
setup:
- uv venv
- uv pip install -r requirements.txt
run: "uv run python app/app.py"
note: |
Flask debug server starts on port 3000.
VS Code auto-forwards the port — click the globe icon in the Ports tab.
| Field | Type | Required | Purpose |
|---|---|---|---|
title | string | yes | One-line label, e.g., "Run the Flask app". Becomes the heading on the Run sub-section. |
setup | list of strings | yes (may be empty) | One-time setup commands (e.g., uv venv, npm install). Empty array [] for templates with no setup step. |
run | string | yes | The single command that starts the app (e.g., uv run python app/app.py). |
note | multi-line string | no | Free-form text after the run command (port info, what to expect, browser tips). |
When to add it
Add quickstart: to any template that has runnable code where the user needs to know what to run after dev-template install finishes. Skip it for overlay templates that just add files (like plan-based-workflow) — there's nothing to run.
Examples per language
# Python (uses uv from DCT)
quickstart:
title: "Run the Flask app"
setup:
- uv venv
- uv pip install -r requirements.txt
run: "uv run python app/app.py"
note: |
Flask runs on port 3000.
# Node / TypeScript
quickstart:
title: "Run the Express server"
setup:
- npm install
run: "npm run dev"
note: |
Server runs on port 3000 with hot reload via nodemon.
# Go (no setup commands needed)
quickstart:
title: "Run the Go server"
setup: []
run: "go run main.go"
note: |
Server runs on port 3000.
# Java (Spring Boot — no setup commands needed)
quickstart:
title: "Run the Spring Boot app"
setup: []
run: "mvn spring-boot:run"
note: |
Spring Boot runs on port 3000.
The auto-generated Configure section
Templates with requires: get a Configure sub-section in the Environment card automatically — no schema fields needed. The section reads requires: and params: from template-info.yaml and tells the user:
- Which UIS services the template uses (from
requires[].service) - Which
paramsthey must edit before running configure (fromparams:keys with empty default values) - The configure command to run (from
configure_command) - A collapsible template-info.yaml dropdown with the full raw file so readers can see the editable surface without opening the source
- A collapsible Expected output dropdown auto-generated from registry data — a sample of what DCT prints when the developer actually runs the configure step. Every value (app name, database, K8s secret, port-forward path) is derived from the template's own
template-info.yaml, so the sample matches the template's real defaults and stays in sync when metadata changes. Do not write a hand-authored Expected output mock in the README — it will drift from reality and duplicate this auto-generated content.
Stack templates (those with provides.services:) get a parallel Install sub-section instead of Configure — same shape, just with the stack's uis template install command and stack-flavoured Expected output.
The card auto-adapts based on which yaml blocks are present:
| Template has | Card shows |
|---|---|
No tools, no requires/provides, no quickstart | No card |
Only tools | ① What gets set up |
tools + quickstart | ① What gets set up, ② Setup (if any), ③ Run |
tools + requires + quickstart (app with services) | ① What gets set up, ② Configure, ③ Setup (if any), ④ Run |
tools + provides.services + quickstart (stack) | ① What gets set up, ② Install, ③ Run |
What this means for template authors
If your template has requires: services, you don't need to write any configure documentation in the README — the Configure section is auto-generated. You just need to make sure:
- Your
params:block has the keys the user needs to edit - The default value is
""(empty string) for params the user MUST set, or a sensible default if optional
Example:
params:
app_name: "" # Required — user must set
database_name: "" # Required — user must set
log_level: "INFO" # Optional — has a default
requires:
- service: postgresql
config:
database: "{{ params.database_name }}"
init: "config/init-database.sql"
The auto-generated Configure section will list params.app_name and params.database_name as the params to edit. params.log_level won't appear because it has a default.
VS Code settings pattern (do not ship .vscode/ files)
Templates must not ship .vscode/settings.json or .vscode/extensions.json files. Per 12MSG in INVESTIGATE-improve-template-docs-with-services.md, DCT does not implement JSON merge for template files. A template that ships .vscode/settings.json would risk overwriting the user's existing VS Code config (including the devcontainer extension recommendation in extensions.json that the project needs to start).
If your template benefits from a specific VS Code workspace setting, document it in the README under a "VS Code tip" section. The pattern (used by python-basic-webserver-database):
**VS Code tip (optional):** if you see "Error refreshing packages" from VS Code's Python extension, add this to your workspace `.vscode/settings.json`:
```json
{
"python-envs.alwaysUseUv": true
}
```
The error happens because <one-sentence reason>. The setting tells <which extension> to <what it does instead>. If your project's `.vscode/settings.json` already exists with other keys, just add this one — don't replace the file.
The three rules:
- One sentence explaining the symptom — what error/problem the user might see
- One sentence explaining the fix — what the setting does
- The literal one-line addition — copy-pasteable JSON
- A "don't replace the file" reminder — protects users with existing VS Code config
If a setting becomes universally needed across many templates, the right home is DCT's base devcontainer image (extension recommendations + workspace defaults), not template-level files. That's a DCT investigation, not a template change.
Required Sections for templates with requires
If your template declares requires: in template-info.yaml (i.e., it needs UIS services like PostgreSQL, Redis, Authentik), the README must include these additional sections:
| Section | Purpose |
|---|---|
| What this is | Brief description of the app — what it does, what endpoints it has, what the user will see when it runs |
| Prerequisites (UIS-aware) | Verify the UIS provision-host container is running. Mention that DCT v1.7.34+ provides the uis shim so commands like uis status and uis connect work from inside DCT. |
| Inline file content | Embed template-info.yaml (at minimum the params: and requires: sections) and the init file(s) (e.g., config/init-database.sql) directly in the README so users see the format without opening files |
| Verify it worked | A DB-level (or service-level) verify command that doesn't require running the app — for PostgreSQL, uis connect <service> <db> is the canonical pattern |
Removed sections
These sections used to be optional but should NOT be added to new templates:
Docker Build— manualdocker buildanddocker runbypass the GitHub Actions pipeline. New templates should not document the manual flow.Kubernetes Deployment— manualkubectl applybypasses ArgoCD. New templates should use a single "Deploy" section that walks throughgit push→ GitHub Actions → ArgoCD.
Template — basic app (no requires)
# Template Display Name
Brief one-line description of what this template provides.
## Quick Start
1. Create the project from this template:
```bash
dev-template <template-id>
```
2. Run the app:
```bash
<your run command here>
```
3. Open in browser: http://localhost:<port>
## Prerequisites
Development tools are installed automatically by the devcontainer.
If you need to reinstall, run: `dev-setup`
## Project Structure
After installation, your project contains:
```plaintext
├── app/
│ └── main.ext # Application entry point
├── manifests/
│ ├── deployment.yaml # K8s Deployment + Service
│ └── kustomization.yaml # ArgoCD configuration
├── .github/
│ └── workflows/
│ └── urbalurba-build-and-push.yaml # CI/CD pipeline
├── Dockerfile # Container build
├── template-info.yaml # Template metadata
└── README-<template-name>.md # This file
```
## Development
- Edit `app/main.ext` — the main application file
- Describe hot reload behavior if applicable
- The `/` endpoint returns "Hello World" with template name and time/date
## Deploy to your local cluster
1. `git push` — GitHub Actions builds and pushes the image
2. `./uis argocd register <app-name> <repo-url>` — register with ArgoCD (one-time)
3. Access the app at `http://<app-name>.localhost`
Template — app with requires (database, auth, etc.)
For templates that depend on UIS services, follow the pattern from python-basic-webserver-database:
# Template Display Name
Brief one-line description.
## What this is
A small but complete <framework> application:
| Endpoint | Method | Returns |
|---|---|---|
| `/` | GET | ... |
| `/items` | GET | ... |
The app **requires** `<ENV_VAR>` and exits if it's missing.
## Prerequisites
This template uses UIS to configure <service>. Verify the UIS provision-host container is running:
```bash
docker ps --filter name=uis-provision-host --format '{{.Status}}'
```
Inside DCT v1.7.34+ you also have the `uis` shim. If `<service>` isn't deployed, `dev-template-configure` will tell you what to run.
## Quick Start
### 1. Install the template
```bash
dev-template <template-id>
```
### 2. Edit `template-info.yaml`
Open `template-info.yaml`, find the `params:` section, set your values:
```yaml
params:
app_name: "my-cool-app"
database_name: "my_cool_app_db"
```
The full `template-info.yaml` declares the dependency:
```yaml
requires:
- service: <service>
config:
...
init: "config/init-<service>.<ext>"
```
### 3. (Optional) Customise `config/init-<service>.<ext>`
```<lang>
-- The init file content goes here, embedded in the README
```
All statements should be idempotent so re-running configure is safe.
### 4. Run `dev-template-configure`
```bash
dev-template-configure
```
### 5. Verify the database (or service)
```bash
uis connect <service> <db-or-resource>
```
### 6. Run the app
```bash
uv venv
source .venv/bin/activate
uv pip install -r requirements.txt
python app/app.py
```
### 7. Open in your browser
VS Code's Ports tab auto-forwards the port. Click the globe icon next to it.
## Project Structure
After installation, your project contains:
```plaintext
├── app/
├── config/
│ └── init-<service>.<ext> # Schema/config (applied by dev-template-configure)
├── manifests/
├── .vscode/
│ └── settings.json # IDE settings
├── .gitignore # Excludes .env*, .venv/, etc.
├── template-info.yaml # Template metadata
└── README-<template-name>.md # This file
```
## Development
...
## Deploy to your local cluster
1. `git push` — GitHub Actions builds and pushes the image
2. `./uis argocd register <app-name> <repo-url>` — register with ArgoCD
3. Access the app at `http://<app-name>.localhost`
The Kubernetes Secret containing service credentials is created automatically by `dev-template-configure` (via UIS) and referenced from `manifests/deployment.yaml` via `secretKeyRef`. You don't need to create it manually.
## Try this with
- [Companion or related templates](../<category>/<other-template>) — describe how they compose
Notes
- The Quick Start section is the most important — users see it first after installation
- Project Structure should show the layout the user sees after
dev-template <id>runs, not the template source layout - Keep descriptions concise — the README is a quick reference, not a tutorial
- Don't include tool installation instructions —
dev-template <id>anddev-template-configurehandle this viatools:intemplate-info.yaml - For templates with
requires:, embed the file contents fortemplate-info.yamland init files in the README. Users need to see what they're editing. - Don't document manual
docker buildorkubectl applyworkflows. They bypass GitHub Actions + ArgoCD and aren't the standard platform workflow.