This file is for AI coding agents working on the template repository itself (not a generated project).
For agents working on a generated project, see the agents.md rendered inside that project.
springrs-template is a baker code-generation template that
scaffolds production-ready Rust backend services (using the summer / spring-rs framework,
SeaORM, axum, optional gRPC, Helm, and frontend kits) from a single JSON answers file.
springrs-template/
├── baker.yaml # Baker configuration: questions, import root, globs
├── Cargo.toml.baker.j2 # Workspace Cargo.toml template
├── Dockerfile.baker.j2 # Multi-stage Docker image template
├── docker-compose.yml.baker.j2 # Docker Compose template
├── mise.toml # Task runner for testing the template (see below)
├── mise.toml.baker.j2 # mise.toml template rendered into generated projects
├── deny.toml.baker.j2 # cargo-deny policy template
├── recipe.json.baker.j2 # cargo-chef recipe template
├── rustfmt.toml.baker.j2 # rustfmt config template
├── build.rs.baker.j2 # build.rs template (gRPC only)
│
├── src/ # Source templates rendered into the generated project
│ ├── main.rs.baker.j2
│ ├── controllers/ # Conditional: only rendered when 'rest' in protocols
│ ├── models/ # Conditional: only rendered when database=='postgres'
│ └── services/
│ └── seaorm_migration_plugin.rs.baker.j2
│
├── migration/ # SeaORM migration crate template (conditional)
├── proto/ # .proto template (conditional: 'grpc' in protocols)
├── helm/ # Helm chart template (conditional: 'helm' in features)
├── frontend/ # Frontend template (conditional: frontend != 'none')
├── e2e/ # End-to-end test crate template
│
├── templates/ # Shared Jinja2 macros and sub-templates imported by baker
│ ├── macros.jinja # Core macros: type mapping, relation helpers, M2M logic
│ ├── types.jinja → rust/types.jinja
│ ├── proto3.jinja # Proto3 code-generation macros
│ ├── react-admin.jinja # React Admin frontend macros
│ ├── solidjs-admin.jinja # SolidJS Admin frontend macros
│ ├── strapi.schema.json # JSON Schema for validating the `entities` answer
│ ├── entities.schema.json # Extended entity schema
│ ├── rust/ # Rust-specific sub-templates (controllers, models, …)
│ ├── docker/ # Docker sub-templates
│ ├── kubernetes/helm/ # Helm chart sub-templates
│ ├── mise/ci/ # CI mise task sub-templates
│ ├── ci/github/ # GitHub Actions workflow
│ ├── schema/grpc|openapi/ # gRPC / OpenAPI schema templates
│ ├── sql/ # SQL macros
│ └── frontend/ # shadcn-admin-kit / solidjs-frontend sub-templates
│
├── samples/ # Pre-filled answers files used in CI testing
│ ├── answers-rest.json
│ ├── answers-rest-jwt.json
│ ├── answers-rest-shadcn.json
│ └── answers-grpc.json
│
└── generated/ # Output directory written by the test tasks (git-ignored)
├── rest/
├── rest-jwt/
├── rest-shadcn/
└── grpc/
Baker reads baker.yaml and processes every file in the repo that is not excluded.
Any file whose name ends in .baker.j2 is treated as a Jinja2 template. Baker strips the
.baker.j2 suffix from the output filename and renders the file contents with the answers as
context variables.
Example: Cargo.toml.baker.j2 → Cargo.toml in the generated project.
Baker evaluates Jinja2 expressions inside path segments (directory and file names). This is how entire sub-trees are included or excluded based on answers:
| Path in template repo | Condition | Effect |
|---|---|---|
{% if 'grpc' in protocols %}proto{% endif %}/ |
protocols contains grpc | proto/ dir is included |
{% if 'helm' in features %}helm{% endif %}/ |
features contains helm | helm/ dir is included |
{% if use_seaorm_migrations %}migration{% endif %}/ |
use_seaorm_migrations is true | migration/ dir is included |
{% if 'shadcn-admin-kit'==frontend %}frontend{% endif %}/ |
frontend is shadcn-admin-kit | frontend/ dir is included |
{%if 'rest' in protocols%}controllers{% endif %}/ |
protocols contains rest | controllers/ dir is included |
{%if database=='postgres'%}models{% endif %}/ |
database is postgres | models/ dir is included |
If an expression evaluates to an empty string the path segment (and its whole sub-tree) is omitted from the output.
Files under templates/ are not copied to the output; they are imported by other templates
via Jinja2 {% import %}. Baker is configured with import_root: "templates" and
template_globs: ["**/*.jinja", "*.jinja"].
The root mise.toml drives end-to-end generation and build tests for all sample variants.
Use this to verify that template changes produce a project that actually compiles and passes tests.
# Install baker and other tools declared in mise.toml
mise install
# Run all four sample variants (rest, rest-jwt, rest-shadcn, grpc)
mise run all
# Or run a single variant
mise run rest
mise run rest-jwt
mise run rest-shadcn
mise run grpcEach task does two things:
- generate — runs
baker . ./generated/<variant> --answers-file samples/answers-<variant>.json --force - e2e — enters
generated/<variant>/, runsmise trustthenmise run build-and-test
A variant passes only when the generated project both compiles cleanly and passes its tests.
- Edit template files (
.baker.j2or.jinja) for content changes. - Use conditional path names (Jinja2 in directory/file names) to add new optional sub-trees.
- Update
baker.yamlif a new answer variable is needed (add a question entry). - Update
samples/answers-*.jsonfiles to cover the new variable so CI tests remain valid. - Run
mise run allto confirm all variants still generate, compile, and pass tests.
- Answers as context — every key in
baker.yamlquestions is available as a Jinja2 variable in all.baker.j2files and path names. templates/macros.jinjais the central macro library; prefer extending it over duplicating logic across templates.generated/is ephemeral — it is regenerated on every test run and should not be edited manually or committed.- One template per concern — follow the existing pattern of one
.baker.j2file per entity type / output file type rather than merging unrelated concerns.