mirror of
https://github.com/bestnite/quadlet-migrator-skill.git
synced 2026-04-04 00:13:28 +00:00
Refine review-first Quadlet migration guidance
Clarify that generated artifacts should be reviewed in the current directory first, install.sh only places Quadlet units into the Quadlet target directory, and runtime support files must be copied to their correct host-side paths. Also strengthen the skill's pod-first, support-file discovery, and env completeness validation rules. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -48,14 +48,18 @@ Use this file when converting `docker-compose.yml` or `compose.yaml` into Quadle
|
||||
- Normalize relative host paths against the Compose file directory and emit absolute paths in the final Quadlet output.
|
||||
- Named volumes can remain referenced by name, but when the user wants explicit infrastructure-as-code, create matching `.volume` units.
|
||||
- Ask the user which volume mode they want when the source does not make the intended persistence model obvious.
|
||||
- If a bind mount points to a repo-local file or directory, include that source in the reviewable deliverable set unless the user explicitly wants a host-managed external path instead.
|
||||
- If a bind mount references a whole directory, inspect and preserve the required directory contents rather than only naming the directory root.
|
||||
|
||||
### `networks`
|
||||
|
||||
- If the source uses a default network only, you often do not need a `.network` unit.
|
||||
- If a custom network is intentional and needs to be managed declaratively, create a `.network` unit and reference it explicitly.
|
||||
- Prefer pod-first topology over preserving Compose bridge networks mechanically.
|
||||
- If the source uses a default network only, you often do not need a `.network` unit at all.
|
||||
- If the source uses bridge networking for containers that can reasonably live in one pod, collapse that topology into one `.pod` so the containers share one network namespace.
|
||||
- Create a `.network` unit only when services must be split across pods, or when explicit network isolation or custom network management is materially required.
|
||||
- Containers in the same `.pod` can communicate over `127.0.0.1` / `localhost` because they share a network namespace.
|
||||
- Containers in different pods must not be treated as reachable via `127.0.0.1` / `localhost`.
|
||||
- When splitting services across multiple pods, use container networking and service-level addressing, or publish ports to the host boundary when that is the intended access pattern.
|
||||
- When splitting services across multiple pods, use container names, pod names, or service-level addressing across the shared network, or publish ports to the host boundary when that is the intended access pattern.
|
||||
|
||||
### `environment`
|
||||
|
||||
@@ -84,11 +88,6 @@ Use this file when converting `docker-compose.yml` or `compose.yaml` into Quadle
|
||||
- Translate to `Requires=` and `After=` when that reflects intent.
|
||||
- State clearly that this controls startup ordering, not application readiness.
|
||||
|
||||
### `restart`
|
||||
|
||||
- Map common cases to `[Service] Restart=`.
|
||||
- If the source policy has no direct systemd equivalent, choose the nearest safe mapping and explain it.
|
||||
|
||||
### `healthcheck`
|
||||
|
||||
- Prefer dedicated Quadlet health fields such as `HealthCmd=`, `HealthInterval=`, `HealthTimeout=`, `HealthRetries=` when representable.
|
||||
@@ -98,6 +97,7 @@ Use this file when converting `docker-compose.yml` or `compose.yaml` into Quadle
|
||||
|
||||
- `entrypoint` typically maps to `Entrypoint=`.
|
||||
- `command` typically maps to `Exec=`.
|
||||
- If an entrypoint or helper script is repo-local, treat it as a support file that must be copied or preserved in the generated layout.
|
||||
|
||||
### `user`
|
||||
|
||||
@@ -136,7 +136,7 @@ Image=docker.io/library/nginx:latest
|
||||
PublishPort=8080:80
|
||||
```
|
||||
|
||||
Use this when the deployment is truly a simple single-service case and pod semantics add little value.
|
||||
Use this when the deployment is truly a simple single-service case. A single container should usually stay a standalone `.container` rather than being wrapped in a pod.
|
||||
|
||||
### Small multi-service app to one pod
|
||||
|
||||
@@ -160,7 +160,7 @@ Reasonable result shape:
|
||||
- `api` may reach `db` over `127.0.0.1` / `localhost` because both containers share the pod network namespace
|
||||
- ordering hints for startup, while explicitly noting that `depends_on` does not guarantee readiness
|
||||
|
||||
Use this when shared networking and a grouped lifecycle make the deployment easier to operate.
|
||||
Use this as the default shape for a small multi-container service unless port conflicts or incompatible grouping force a split into multiple pods.
|
||||
|
||||
## Pod decision rule
|
||||
|
||||
@@ -168,10 +168,15 @@ Choose the simplest topology that preserves the source deployment intent.
|
||||
|
||||
Prefer a single `.pod` for multi-container applications when practical.
|
||||
|
||||
If the project is a simple single-container deployment with no real need for pod semantics, a standalone `.container` is acceptable.
|
||||
If one logical service contains multiple containers, default to putting them in the same `.pod` so they share networking and lifecycle.
|
||||
|
||||
If shared networking, shared published ports, or tightly coupled service lifecycle make pod semantics useful, prefer one or more `.pod` units.
|
||||
If the project is a simple single-container deployment with no real need for pod semantics, a standalone `.container` is the preferred result.
|
||||
|
||||
If one pod is not practical because of port conflicts or clearly incompatible groupings, split the result into a small number of pods rather than forcing an awkward topology.
|
||||
|
||||
When services are split across multiple pods, do not rely on `127.0.0.1` / `localhost` for cross-pod communication. Use container names, pod names, or other service-level addressing on the shared network instead.
|
||||
|
||||
Avoid preserving bridge networks by default when pod grouping already expresses the intended communication pattern well.
|
||||
|
||||
For large application stacks with optional services, ask the user to choose the desired service set before generating a minimized result.
|
||||
|
||||
|
||||
@@ -2,20 +2,61 @@
|
||||
|
||||
Use this file when the user wants deployment-ready instructions alongside generated Quadlet units.
|
||||
|
||||
## Directory choice
|
||||
## Delivery flow
|
||||
|
||||
1. Generate the reviewable artifacts in the current working directory.
|
||||
2. Review the generated Quadlet files, env files, helper scripts, and any required repo-local support files or directories.
|
||||
3. Use `install.sh` to copy only the reviewed unit files into the chosen Quadlet directory. Copy env files and any other required runtime support files into the correct host-side paths the deployment expects.
|
||||
4. Use `reload.sh`, `start.sh`, `stop.sh`, and `restart.sh` to manage the deployed services.
|
||||
|
||||
## Apply target directory
|
||||
|
||||
### Rootless
|
||||
|
||||
- primary default: `~/.config/containers/systemd/`
|
||||
- default apply target: `~/.config/containers/systemd/`
|
||||
- user-scoped management commands use `systemctl --user`
|
||||
|
||||
### Rootful
|
||||
|
||||
- primary default: `/etc/containers/systemd/`
|
||||
- default apply target: `/etc/containers/systemd/`
|
||||
- system-scoped management commands use `systemctl`
|
||||
|
||||
See `podman-systemd.unit.5.md` for the full search-path matrix.
|
||||
|
||||
## Helper scripts
|
||||
|
||||
- `install.sh`: canonical apply script; copy only reviewed Quadlet unit files into the selected Quadlet target directory, and copy env files plus any other required runtime support files into the correct host-side paths
|
||||
- do not generate a separate `apply.sh` by default; reserve that alternate name only when the user explicitly asks for it
|
||||
- `reload.sh`: run the appropriate `daemon-reload` command after installation changes
|
||||
- `start.sh`: start the generated units
|
||||
- `stop.sh`: stop the generated units
|
||||
- `restart.sh`: restart the generated units after reload or config changes
|
||||
|
||||
Keep installation separate from service-management scripts so the user can review generated files before applying them.
|
||||
`install.sh` should copy reviewed Quadlet unit files into the chosen Quadlet target directory and place required runtime support files into their correct host-side destinations only, and should not start, stop, restart, or reload services as a side effect.
|
||||
`reload.sh`, `start.sh`, `stop.sh`, and `restart.sh` should not silently install or overwrite reviewed files.
|
||||
|
||||
## Review checklist before install
|
||||
|
||||
Review not only the Quadlet unit files but also:
|
||||
|
||||
- env files referenced by `EnvironmentFile=`
|
||||
- repo-local mounted config files and directory trees
|
||||
- initialization files such as `init.sql`, seed data, or bootstrap assets
|
||||
- repo-local entrypoint and helper scripts referenced by `Entrypoint=`, `Exec=`, docs, or wrapper scripts
|
||||
|
||||
Do not treat the deliverable as complete if these support files are still missing from the reviewable artifact set.
|
||||
|
||||
Execution checklist template before install:
|
||||
|
||||
- [ ] all reviewed artifacts are present in the current-directory deliverable tree
|
||||
- [ ] required support files and directories are included alongside the Quadlet and env artifacts
|
||||
- [ ] unit files map to the intended Quadlet directory
|
||||
- [ ] support files map to the correct host-side runtime paths for mounts and scripts
|
||||
- [ ] startup-critical env keys are present in the final env sources
|
||||
- [ ] any unresolved values are clearly marked as intentionally non-runnable placeholders
|
||||
- [ ] service-management scripts operate on the same reviewed artifact set that will be installed
|
||||
|
||||
## Rootless operational notes
|
||||
|
||||
- Bind mounts may hit UID/GID mismatches.
|
||||
@@ -32,6 +73,7 @@ sudo loginctl enable-linger <username>
|
||||
- Normalize relative source paths against the source Compose file directory or the directory the user specifies.
|
||||
- Emit absolute host paths in generated Quadlet files when using bind mounts.
|
||||
- Explain the resolved absolute path if the source used `./...`.
|
||||
- If the source project bind-mounts repo-local files or directories, make sure the installed artifact set preserves the required contents and places them at the correct host-side paths expected by the mounts.
|
||||
|
||||
## Recommended service defaults
|
||||
|
||||
|
||||
@@ -9,11 +9,23 @@ Use this file whenever the migration includes `.env`, `env_file`, Compose interp
|
||||
- keep resulting units readable
|
||||
- report missing variables explicitly
|
||||
- reduce large upstream env templates into a small set of user decisions
|
||||
- validate env completeness before claiming runnable output
|
||||
|
||||
## Default rules
|
||||
|
||||
The agent should actively interpret the env template and its comments. Do not offload the entire env review back to the user.
|
||||
|
||||
Runnable output requires an env completeness check, not just env summarization.
|
||||
A variable is not considered satisfied unless it is present in one of the actual final output sources:
|
||||
|
||||
- `Environment=` in generated Quadlet
|
||||
- the final `EnvironmentFile=` contents
|
||||
- a documented default that is intentionally preserved in the runnable result
|
||||
- an explicit placeholder, but only when the result is intentionally not yet runnable
|
||||
|
||||
If a variable is still absent from the actual output sources, keep it unresolved.
|
||||
Do not silently downgrade a startup-critical variable into an informational note.
|
||||
|
||||
### Prefer `Environment=` when
|
||||
|
||||
- there are only a few variables
|
||||
@@ -59,6 +71,23 @@ Strategy:
|
||||
|
||||
Do not fabricate values.
|
||||
|
||||
## Env completeness validation
|
||||
|
||||
Before producing runnable artifacts:
|
||||
|
||||
- compare variables referenced by Compose, interpolation, docs, startup scripts, and image-specific setup guidance against the variables present in the final output
|
||||
- verify that every `EnvironmentFile=` referenced in the final result actually contains the required keys the service depends on
|
||||
- treat missing bootstrap credentials for common stateful services as unresolved required variables, not optional omissions
|
||||
- if a high-similarity near-match exists, flag it as a likely typo instead of silently accepting it
|
||||
|
||||
Examples of suspicious mismatches:
|
||||
|
||||
- `POSTGRES_PASSWRD` vs `POSTGRES_PASSWORD`
|
||||
- singular/plural mismatches such as `ALLOWED_HOST` vs `ALLOWED_HOSTS`
|
||||
- prefix mismatches where the docs and final env disagree on the canonical key name
|
||||
|
||||
If a required key is mentioned in the source docs, image guidance, or startup scripts but is absent from the final output sources, stop before claiming runnable output.
|
||||
|
||||
## Agent responsibility
|
||||
|
||||
When the source project ships a large `.env.example` or multiple env templates:
|
||||
@@ -67,6 +96,7 @@ When the source project ships a large `.env.example` or multiple env templates:
|
||||
- determine which values can safely stay at documented defaults
|
||||
- determine which values are true deployment decisions and must be confirmed with the user
|
||||
- prepare a candidate `.env` or env delta instead of asking the user to read the whole template manually
|
||||
- verify that the final env output still contains the variables needed for minimal startup
|
||||
|
||||
The user should only need to answer the small number of high-impact questions that cannot be discovered locally.
|
||||
|
||||
@@ -123,6 +153,21 @@ Recommended behavior:
|
||||
- ask the user only for high-impact values such as domain, storage path, or database password
|
||||
- generate a candidate `.env` or env delta with clear placeholders for the unresolved items
|
||||
|
||||
### Required variable still missing
|
||||
|
||||
Source intent:
|
||||
|
||||
```ini
|
||||
[Container]
|
||||
EnvironmentFile=/home/nite/pod/dify/dify.env
|
||||
Environment=POSTGRES_USER=postgres
|
||||
Environment=POSTGRES_DB=dify
|
||||
Environment=PGDATA=/var/lib/postgresql/data/pgdata
|
||||
```
|
||||
|
||||
If `dify.env` does not contain `POSTGRES_PASSWORD`, do not treat this as runnable output.
|
||||
Report `POSTGRES_PASSWORD` as unresolved and stop before final runnable generation.
|
||||
|
||||
## Output patterns
|
||||
|
||||
### Small inline set
|
||||
@@ -150,6 +195,25 @@ Environment=APP_ENV=production
|
||||
EnvironmentFile=/opt/myapp/myapp.env
|
||||
```
|
||||
|
||||
## Finalize checklist template
|
||||
|
||||
Before freezing the env plan, confirm:
|
||||
|
||||
- which keys are satisfied by `Environment=`
|
||||
- which keys are satisfied by the final `EnvironmentFile=`
|
||||
- which keys are preserved via documented defaults
|
||||
- which keys remain unresolved and therefore block runnable output
|
||||
- which keys look like typo candidates and need human confirmation
|
||||
|
||||
## Execution checklist template
|
||||
|
||||
Before writing runnable artifacts, confirm:
|
||||
|
||||
- the final env file contains every required startup key
|
||||
- every `EnvironmentFile=` path in the generated Quadlet matches an actual generated or preserved file
|
||||
- placeholder values are clearly marked and do not masquerade as confirmed production values
|
||||
- typo-suspect keys are either corrected or explicitly surfaced in the output
|
||||
|
||||
## Missing-variable reporting
|
||||
|
||||
When variables cannot be resolved, report them as a concrete checklist.
|
||||
@@ -159,6 +223,7 @@ Example:
|
||||
- missing `DB_PASSWORD`
|
||||
- missing `IMMICH_VERSION`
|
||||
- missing `UPLOAD_LOCATION`
|
||||
- likely typo: `POSTGRES_PASSWRD` should probably be `POSTGRES_PASSWORD`
|
||||
|
||||
If the user asks for scaffolding, generate a sample env file with obvious placeholders.
|
||||
|
||||
|
||||
@@ -29,15 +29,18 @@ Discover the canonical self-hosting assets before attempting any Quadlet convers
|
||||
- `.devcontainer/`
|
||||
6. Read deployment-specific README files in those directories.
|
||||
7. Identify helper scripts that generate or sync compose files.
|
||||
8. Identify repo-local companion files required at runtime, such as mounted config, templates, initialization files, seed data, bootstrap assets, entrypoint scripts, and bind-mounted directory trees.
|
||||
|
||||
## What to extract
|
||||
|
||||
- canonical compose file path
|
||||
- companion env template path
|
||||
- additional compose files used for middleware or optional services
|
||||
- repo-local companion files required for runtime, such as config, templates, initialization files, bootstrap assets, entrypoint scripts, or mounted directories
|
||||
- whether the compose file is generated
|
||||
- whether the source relies on profiles
|
||||
- whether startup requires preparatory steps such as copying `.env.example` to `.env`
|
||||
- whether those companion files must be copied, rendered, or kept in a specific relative layout for the deployment to work
|
||||
|
||||
## Heuristics
|
||||
|
||||
@@ -46,12 +49,30 @@ Discover the canonical self-hosting assets before attempting any Quadlet convers
|
||||
- If the repo has both a template and a generated compose file, treat the generated file as the runnable source and the template as explanatory context.
|
||||
- If profiles control optional databases or vector stores, decide which profile set the user actually wants before generating Quadlet.
|
||||
- If env management is mandatory, preserve that pattern rather than flattening hundreds of variables into inline `Environment=` values.
|
||||
- If the source mounts or references repo-local config, templates, initialization assets, entrypoint scripts, or directory trees, treat them as first-class deployment inputs rather than incidental files.
|
||||
- If a Compose bind mount points to a repo-relative file or directory, treat that path as a candidate support-file source rather than only recording the mount string.
|
||||
- If docs or startup scripts say to copy, edit, mount, or render a repo-local file before startup, include that asset in the deliverable review set.
|
||||
- If a whole directory is mounted, inspect the directory contents and preserve the required files instead of only naming the directory root.
|
||||
- Do not reduce runnable output to only Quadlet plus env when the source project depends on additional repo-local assets.
|
||||
- If several candidate compose files exist, explain which one you selected and why.
|
||||
|
||||
## Support-file checklist template
|
||||
|
||||
Before choosing the final source of truth, confirm:
|
||||
|
||||
- which repo-local files are mounted directly
|
||||
- which repo-local directories are mounted as whole trees
|
||||
- which startup docs require copying, editing, or rendering companion files
|
||||
- which entrypoint or helper scripts refer to additional local assets
|
||||
- which companion files are mandatory for minimal startup versus optional extras
|
||||
|
||||
Use this checklist to prevent reducing the deliverable to Quadlet plus env when the source project depends on more than that.
|
||||
|
||||
## Migration posture for GitHub-sourced projects
|
||||
|
||||
When converting a GitHub-hosted project, report:
|
||||
|
||||
- which files you chose as source of truth
|
||||
- which required repo-local companion files must ship with the result
|
||||
- which optional files or profiles you ignored
|
||||
- which variables still require user decisions
|
||||
|
||||
@@ -4,6 +4,13 @@ Use this file when the user asks how to verify or troubleshoot generated Quadlet
|
||||
|
||||
## Basic deployment flow
|
||||
|
||||
1. Review the generated files in the current working directory and confirm the expected Quadlet units, env files, helper scripts, and required repo-local support files exist.
|
||||
2. Run `install.sh` to copy only the reviewed unit files into the target Quadlet directory and place required runtime support files into the correct host-side paths.
|
||||
3. Run the appropriate reload command.
|
||||
4. Start the relevant units and inspect their status.
|
||||
|
||||
If the user requested an alternate apply script name explicitly, substitute that name where needed, but treat `install.sh` as the default documentation path.
|
||||
|
||||
### Rootless
|
||||
|
||||
```bash
|
||||
@@ -46,12 +53,37 @@ For user units:
|
||||
systemd-analyze --user verify <unit>.service
|
||||
```
|
||||
|
||||
## Support-file and env checks
|
||||
|
||||
Before calling the result runnable, verify that:
|
||||
|
||||
- every referenced `EnvironmentFile=` exists at the installed path
|
||||
- required env keys are actually present in the final env sources
|
||||
- bind-mounted files and directories exist after installation
|
||||
- repo-local entrypoint or helper scripts referenced by the container exist and are executable when needed
|
||||
- initialization assets such as `init.sql`, seeds, bootstrap files, or config templates are present where the deployment expects them
|
||||
|
||||
Runnable-output gate checklist template:
|
||||
|
||||
- [ ] the support-file set is complete
|
||||
- [ ] env completeness check passed against the actual final env sources
|
||||
- [ ] unit files are installed in the intended Quadlet directory
|
||||
- [ ] support files are installed at the host-side runtime paths expected by mounts and scripts
|
||||
- [ ] service-management scripts operate on the same artifact set that was reviewed
|
||||
- [ ] no required support file, env key, or typo-suspect mismatch remains unresolved
|
||||
|
||||
Do not call the result runnable until every item above is checked.
|
||||
|
||||
## Common failure causes
|
||||
|
||||
- unsupported Quadlet option for the installed Podman version
|
||||
- bind-mount source directory missing
|
||||
- wrong rootless or rootful unit directory
|
||||
- files were generated but `install.sh` has not yet copied the unit files into the target rootless or rootful unit directory and the required runtime support files into their host-side paths
|
||||
- wrong rootless or rootful apply target directory
|
||||
- unresolved env file path
|
||||
- required env key missing from the final env file
|
||||
- likely env-key typo or mismatch between source docs and final env output
|
||||
- required repo-local config, init assets, or helper scripts missing from the installed artifact set
|
||||
- permissions on rootless bind mounts
|
||||
- readiness assumptions hidden behind `depends_on`
|
||||
|
||||
@@ -60,11 +92,12 @@ systemd-analyze --user verify <unit>.service
|
||||
When validation fails, report:
|
||||
|
||||
- what generated successfully
|
||||
- what failed to generate or start
|
||||
- whether the issue is syntax, unsupported feature, path resolution, or permissions
|
||||
- what was applied successfully
|
||||
- what failed to generate, apply, or start
|
||||
- whether the issue is syntax, unsupported feature, path resolution, installation path, missing support files, missing env keys, or permissions
|
||||
|
||||
## Relationship to execution phase
|
||||
|
||||
Validation belongs after the files are written in the execution phase.
|
||||
Validation belongs after the files are written in the execution phase and applied to a valid Quadlet directory and the correct host-side runtime paths.
|
||||
|
||||
Before execution, the skill should already have completed planning and finalize review with the user. Do not treat validation as a substitute for design review.
|
||||
|
||||
Reference in New Issue
Block a user