Templates
Templates
AppKit uses a template system powered by the Databricks CLI's databricks apps init command. Templates define the project structure, and .tmpl files are processed with Go's text/template engine to generate customized output.
How .tmpl files work
Any file ending in .tmpl is processed by the CLI during databricks apps init:
- The
.tmplsuffix is stripped (e.g..env.tmpl→.env) - Go template expressions are evaluated and substituted
- The rendered file is written to the output directory
Files named with a _ prefix are renamed to . prefix (e.g. _gitignore → .gitignore).
Template variables
Conditional content
Use Go template conditionals to include/exclude code based on selected plugins:
{{- if .plugins.analytics}}
import { analytics } from '@databricks/appkit';
{{- end}}
appkit.plugins.json
The plugin manifest drives the CLI's behavior during databricks apps init:
- Plugin selection UI — selectable plugins shown in the interactive prompt
- Resource prompts — required/optional resources prompt the user for values (e.g. SQL Warehouse ID)
.dotEnvpopulation — resource fields with anenvproperty are written to.envapp.yamlgeneration — resource fields produceenv+valueFromentriesdatabricks.ymlgeneration — resource fields produce bundle variables and app resource entries
The synced manifest is generated by appkit plugin sync --write from each plugin's manifest.json (see Plugin manifest for the authoring contract). The on-disk shape carries a version field that the CLI uses to negotiate features:
"1.0"/"1.1"— earlier shapes; still readable."2.0"— current shape. Addsscaffolding(required by the CLI whenversionis"2.0"; enforced at parse time, not via the published JSON Schema) and theoriginfield on every resource field entry. JSON Schema published athttps://databricks.github.io/appkit/schemas/template-plugins.schema.json.
Resource field properties
Each resource field in the synced manifest can have these properties:
origin (v2.0)
origin is computed at sync time from the field's other properties — plugin authors do not write it. It tells scaffolding agents how each value reaches the running app:
Precedence is in the order above (localOnly wins over value, which wins over resolve). The transform overwrites any hand-edited origin on the next sync — drift between the on-disk value and the field's actual shape is not possible by construction.
Resolvers
Fields with a resolve property are auto-populated by the CLI from API calls rather than user prompts. The format is <type>:<field>.
Currently only the postgres resource type has a resolver. Given the user-provided branch and database resource names, it derives:
Example field definition:
{
"host": {
"env": "PGHOST",
"localOnly": true,
"resolve": "postgres:host",
"description": "Postgres host for local development."
}
}
After sync, the field carries "origin": "platform" (because localOnly takes precedence over resolve for local-only fields injected at deploy time).
scaffolding.rules propagation
Each plugin's scaffolding.rules block (see Plugin manifest — Scaffolding rules) is propagated unchanged into its entry in appkit.plugins.json. The CLI hands the merged plugin-level rules — alongside the top-level template scaffolding.rules — to scaffolding agents that drive databricks apps init.
Merge model:
- Gather rules from every selected plugin and from every plugin with
requiredByTemplate: true. - Apply the template-level
scaffolding.ruleson top. - Plugin-level rules override skill-baked or template-level defaults at the same directive site.
- A plugin
mustthat conflicts with a templatenever(or vice versa) stops the init flow — see the validation rules below.
scaffolding descriptor (v2.0)
The scaffolding block at the top level of appkit.plugins.json describes the scaffolding command, its flags, and the cross-cutting rules every scaffolding agent must respect. It is required by the CLI when version is "2.0". The requirement is enforced at parse time — the published JSON Schema marks only version and plugins as top-level required fields because it cannot express conditional requirements.
{
"scaffolding": {
"command": "databricks apps init",
"flags": {
"--name": {
"description": "Project name — sets {{.projectName}} in package.json, databricks.yml, and .env. Required for non-interactive scaffolding.",
"required": true,
"pattern": "^[a-z][a-z0-9-]*$"
},
"--features": {
"description": "Plugins to enable (comma-separated, no spaces; must match keys in this manifest's plugins map)",
"required": false,
"pattern": "^[a-zA-Z0-9_-]+(,[a-zA-Z0-9_-]+)*$"
},
"--profile": {
"description": "Databricks CLI profile to use for authentication (global flag)",
"required": false
}
},
"rules": {
"must": [
"Keep all secrets and credentials only in app.yaml, databricks.yml, and/or .env"
],
"should": [
"ask user when in doubt of resource to use for plugin"
],
"never": [
"guess resources when multiple or no options are available",
"embed secrets in files that will go to the client-bundle"
]
}
}
}
The example above shows three flags. The canonical flag set shipped with every synced template manifest is:
Each rule item is capped at 120 characters by the schema. Long prose fails validation — split into discrete actionable directives.
The descriptor is canonical: AppKit owns the values and ships them with every synced template manifest. Authors of consuming agents (LLM-driven scaffolders, custom CLI runners) should treat the rule lists as enforcement contracts, not suggestions.
Substitutability gate (template rules)
The template-level rules survive the same substitutability gate that governs plugin-level rules: each entry must describe a cross-cutting agent decision the schema cannot already encode. Rules like "modify only files inside the template directory" or "list volumes after prompting for catalog/schema" are absent on purpose — the first is unreachable once you read the manifest as the source of truth, and the second is now encoded structurally as parents: ["catalog", "schema"] on the volume discovery kind (see Plugin manifest — Transient prompts).
See also
- Plugin manifest — the authoring side (
manifest.json). - Plugin management —
appkit plugin sync,appkit plugin create. - Configuration — environment variables.