sitectl-app-tmpl when adding a new application plugin for a standalone template repository.
The template is intentionally thin. The application repository owns the Compose workload. Core sitectl owns shared lifecycle commands. The plugin contributes app-specific metadata and helpers.
Command Ownership
| Concern | Owner | Examples |
|---|---|---|
| Compose lifecycle | Core sitectl | sitectl compose up, sitectl compose down, sitectl compose logs, sitectl compose ps |
| Create flow metadata | App plugin | CreateSpec, template repo, init artifacts, image specs |
| App-specific commands | App plugin | sitectl <app> exec ..., API wrappers, application maintenance helpers |
| Shared service operations | Core sitectl | sitectl mariadb backup, sitectl solr info, sitectl traefik tls |
| Cross-cutting reports | Core command plus plugin runner | sitectl debug, sitectl validate, sitectl healthcheck |
RegisterComposeTemplateCreateRunner, not RegisterStandardComposeTemplate. The latter still exists for plugins that deliberately want direct namespace lifecycle commands, but first-class app plugins should let core sitectl compose provide the shared lifecycle surface.
Create Definition Contract
The create definition is more than a clone recipe. It is also the desired state metadata used by coresitectl compose up to decide whether a local checkout needs first-run init or image build work. See Compose reconcile contract for the shared core behavior.
DockerComposeInit should be idempotent. It may create .env, run an init service, and write deterministic secret files. It must not destroy existing application data when run again.
DockerComposeRollout should keep rollout commands in plugin metadata, not in a template scripts/rollout.sh or Makefile target. Core rollout/deploy handles git sync from the checkout’s configured upstream branch when one exists, then runs the plugin’s Compose rollout commands.
InitArtifacts should list files that prove init has completed. Prefer explicit files over probing container state. Use ValueFrom: plugin.InitArtifactValueFromHostUID for a UID marker file when generated files need to match the local host user.
InitVolumes should list named Compose volumes that prove first-start runtime state exists, such as database volumes and application file/upload volumes. Core resolves those names through docker compose config, so custom Compose project names and explicit volume names still work.
Images should list local images the template expects to build. Use BuildPolicyIfNotPresent for normal local images, BuildPolicyAlways only when every compose up should rebuild, and BuildPolicyNever for services that should never trigger the build phase.
Image Overrides
Coresitectl image set writes docker-compose.override.yml for local contexts:
- an explicit image override for a service means core does not require the plugin’s default image to exist locally
- a build-arg override triggers the build phase so the new arguments are applied
- the override file fingerprint is part of the reconcile cache key
--image or --build-arg for app-specific services that are not known to the shared --tag map.
Template Checklist
After creating a repository fromsitectl-app-tmpl:
- Rename the Go module, binary, plugin name, display name, and release workflow outputs.
- Set
TemplateRepo,TemplateBranch,DefaultPath,AppService,AppImage,DatabaseService,DatabaseName, and codebase rootfs constants. - Update
CreateSpeclifecycle commands,InitArtifacts,InitVolumes, andImagesto match the real template repository. - Tune project discovery in
SetComposeProjectDiscovery. Use service names and durable codebase markers that identify the real project. - Keep app-specific commands in the plugin namespace. Avoid registering
build,init,up,down,status,logs, orrolloutunless the app has a deliberate compatibility need. - Use core service commands for shared operations. For example, document
sitectl mariadb backup apprather than adding a thin app plugin alias. - Implement debug, validate, and healthcheck runners through the SDK. Results should be structured; progress and diagnostics should go to stderr.
- Keep local workspace wiring in
go.work; do not add sibling-modulereplacedirectives togo.mod. - Update the integration script to create with
--setup-only, start withsitectl compose up, and then runsitectl healthcheck. - Add a plugin page to
sitectl-docsfor app-specific operations.

