mirror of
https://github.com/bestnite/quadlet-migrator-skill.git
synced 2026-04-03 21:53:27 +00:00
init
This commit is contained in:
24
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
24
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Report a problem, ambiguity, or incorrect migration rule
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
Describe the issue.
|
||||
|
||||
## Input
|
||||
|
||||
Provide the relevant `docker run`, Compose snippet, or repository context.
|
||||
|
||||
## Expected behavior
|
||||
|
||||
Describe what the skill should have done.
|
||||
|
||||
## Actual behavior
|
||||
|
||||
Describe what happened instead.
|
||||
|
||||
## Additional context
|
||||
|
||||
Add any references, screenshots, or Podman / Quadlet version details.
|
||||
24
.github/ISSUE_TEMPLATE/rule_improvement.md
vendored
Normal file
24
.github/ISSUE_TEMPLATE/rule_improvement.md
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
name: Rule improvement
|
||||
about: Propose an improvement to mapping rules, env strategy, or workflow
|
||||
---
|
||||
|
||||
## Area
|
||||
|
||||
- [ ] workflow
|
||||
- [ ] compose mapping
|
||||
- [ ] env strategy
|
||||
- [ ] repo intake
|
||||
- [ ] deployment / validation
|
||||
|
||||
## Proposal
|
||||
|
||||
Describe the rule change.
|
||||
|
||||
## Why
|
||||
|
||||
Explain the concrete problem this would solve.
|
||||
|
||||
## Example
|
||||
|
||||
Add a minimal input and the expected outcome if possible.
|
||||
14
.github/pull_request_template.md
vendored
Normal file
14
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
## Summary
|
||||
|
||||
- describe the change
|
||||
- explain any skill behavior or rule updates
|
||||
|
||||
## Test / validation
|
||||
|
||||
- [ ] reviewed `SKILL.md`
|
||||
- [ ] reviewed affected files under `references/`
|
||||
- [ ] considered impact on topology, env handling, and finalize flow
|
||||
|
||||
## Notes
|
||||
|
||||
Add any migration edge cases or trade-offs here.
|
||||
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# OS / editor
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# Claude / local tooling
|
||||
.claude/
|
||||
|
||||
# Build or temp outputs
|
||||
*.log
|
||||
*.tmp
|
||||
*.bak
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 nite
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
44
README.md
Normal file
44
README.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# Quadlet Migrator
|
||||
|
||||
[English](./README.md) | [简体中文](./README.zh-CN.md)
|
||||
|
||||
A skill for migrating `docker run` commands and Docker Compose-style deployments into maintainable Podman Quadlet units.
|
||||
|
||||
## What it does
|
||||
|
||||
- translates `docker run` and Compose-style inputs into Quadlet-oriented designs
|
||||
- helps decide between `.container`, `.pod`, `.network`, `.volume`, and `.build`
|
||||
- preserves `.env` / `env_file` workflows when appropriate
|
||||
- reduces large env templates into a small set of high-impact deployment questions
|
||||
- explains rootless vs rootful placement, deployment notes, and validation steps
|
||||
|
||||
## Design principles
|
||||
|
||||
- prefer the lightest operating mode that matches the request
|
||||
- separate planning, review, and generation into explicit phases
|
||||
- do not invent deployment-specific values
|
||||
- make lossy mappings explicit
|
||||
- prefer maintainable output over mechanical one-to-one translation
|
||||
|
||||
## Operating modes
|
||||
|
||||
- `advice`: explain mappings or review source inputs without writing final artifacts
|
||||
- `design`: perform planning and finalize review, then stop before runnable artifact generation
|
||||
- `generate`: produce approved runnable artifacts after planning and finalize review
|
||||
|
||||
## References
|
||||
|
||||
- `SKILL.md` contains the operating modes, workflow, and high-level rules
|
||||
- `references/compose-mapping.md` covers field mapping and topology decisions
|
||||
- `references/env-strategy.md` covers env handling and secret defaults
|
||||
- `references/github-repo-intake.md` covers repository discovery and canonical input selection
|
||||
- `references/deployment-notes.md` covers deployment guidance
|
||||
- `references/validation.md` covers validation and troubleshooting
|
||||
|
||||
## Limitations
|
||||
|
||||
This skill does not claim perfect equivalence between Docker Compose semantics and Podman Quadlet semantics.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
44
README.zh-CN.md
Normal file
44
README.zh-CN.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# Quadlet Migrator
|
||||
|
||||
[English](./README.md) | [简体中文](./README.zh-CN.md)
|
||||
|
||||
一个 skill,用来将 `docker run` 命令和 Docker Compose 风格部署迁移为可维护的 Podman Quadlet 单元。
|
||||
|
||||
## 功能概览
|
||||
|
||||
- 将 `docker run` 和 Compose 风格输入转换为面向 Quadlet 的设计
|
||||
- 帮助在 `.container`、`.pod`、`.network`、`.volume`、`.build` 之间做选择
|
||||
- 在合适时保留 `.env` / `env_file` 工作流
|
||||
- 将大型 env 模板归纳为少量高影响部署问题
|
||||
- 说明 rootless / rootful 放置路径、部署说明与验证步骤
|
||||
|
||||
## 设计原则
|
||||
|
||||
- 优先选择满足需求的最轻运行模式
|
||||
- 将规划、审阅、生成拆成明确阶段
|
||||
- 不虚构部署相关取值
|
||||
- 对有损映射保持显式说明
|
||||
- 优先输出可维护的结果,而不是机械一比一转换
|
||||
|
||||
## 运行模式
|
||||
|
||||
- `advice`:解释映射方式或审查输入,不写最终产物
|
||||
- `design`:执行 planning 和 finalize 审阅,但在生成可运行产物前停止
|
||||
- `generate`:在 planning 和 finalize 审阅通过后,生成已批准的可运行产物
|
||||
|
||||
## 文档说明
|
||||
|
||||
- `SKILL.md`:运行模式、工作流和高层规则
|
||||
- `references/compose-mapping.md`:Compose 字段映射与拓扑决策
|
||||
- `references/env-strategy.md`:env 处理与 secret 默认策略
|
||||
- `references/github-repo-intake.md`:仓库发现与 canonical 输入选择
|
||||
- `references/deployment-notes.md`:部署说明
|
||||
- `references/validation.md`:验证与排障
|
||||
|
||||
## 限制
|
||||
|
||||
本 skill 不保证 Docker Compose 语义与 Podman Quadlet 语义完全等价。
|
||||
|
||||
## 许可证
|
||||
|
||||
MIT
|
||||
284
SKILL.md
Normal file
284
SKILL.md
Normal file
@@ -0,0 +1,284 @@
|
||||
---
|
||||
name: quadlet-migrator
|
||||
description: Convert docker run commands or Docker Compose configurations into maintainable Podman Quadlet files, help users map env/env_file/.env usage into Environment or EnvironmentFile, and explain rootless or rootful deployment details and migration risks.
|
||||
---
|
||||
|
||||
# Quadlet Migrator
|
||||
|
||||
Use this skill when the user wants to migrate `docker run`, `docker compose`, or Compose-like service definitions into Podman Quadlet units, especially when environment variables, `env_file`, `.env`, rootless deployment, or systemd layout need to be planned or generated.
|
||||
|
||||
Do not rely on `podlet` as an execution dependency. You may use it only as prior-art knowledge, not as part of the runtime workflow.
|
||||
|
||||
## What this skill does
|
||||
|
||||
This skill helps you:
|
||||
|
||||
- discover Docker deployment entry points from a GitHub repository URL
|
||||
- translate `docker run` flags and Compose service fields into Quadlet units
|
||||
- choose between `.container`, `.pod`, `.network`, `.volume`, and `.build`
|
||||
- decide whether values belong in `Environment=` or `EnvironmentFile=`
|
||||
- work closely with the user to confirm deployment-specific environment values and operational choices
|
||||
- identify missing variables, unsafe inline secrets, and unsupported Compose semantics
|
||||
- produce deployment notes for rootless or rootful systemd setups
|
||||
|
||||
## Operating modes
|
||||
|
||||
Choose the lightest mode that satisfies the user's request.
|
||||
|
||||
- `advice`: explain mappings, review source inputs, answer targeted migration questions, or sketch a recommended structure without writing final artifacts
|
||||
- `design`: perform `Planning` and `Finalize`, produce `QUADLET-FINALIZE.md`, but stop before writing runnable artifacts
|
||||
- `generate`: perform `Planning`, `Finalize`, and `Execution`, then write the approved runnable artifacts
|
||||
|
||||
Do not force `generate` mode when the user only wants explanation, review, or a partial conversion.
|
||||
|
||||
## Workflow
|
||||
|
||||
The full workflow has three explicit phases: `Planning`, `Finalize`, and `Execution`.
|
||||
|
||||
- `advice` usually stays in `Planning` or gives a targeted answer without entering all phases
|
||||
- `design` uses `Planning` and `Finalize`
|
||||
- `generate` uses all three phases
|
||||
|
||||
Do not skip phase boundaries when you are using them. The skill should not jump directly from discovery into writing files.
|
||||
|
||||
### Planning phase
|
||||
|
||||
Goal: gather inputs, understand the project, and work with the user to make the key decisions.
|
||||
|
||||
Tasks in this phase:
|
||||
|
||||
1. Classify the input.
|
||||
- `docker run` or `podman run` style command
|
||||
- single-file Compose configuration
|
||||
- Compose plus `.env` and optional `env_file`
|
||||
- GitHub repository URL that likely contains self-hosting assets
|
||||
- already partially converted Quadlet files that need cleanup
|
||||
|
||||
2. If the input is a GitHub repository, discover the deployment entry points first.
|
||||
- start from the repository README and deployment subdirectory READMEs
|
||||
- follow explicit links or references from documentation before making assumptions about file locations
|
||||
- search the repository tree for `docker-compose.yaml`, `docker-compose.yml`, `compose.yaml`, `compose.yml`
|
||||
- inspect common deployment-oriented subdirectories such as `docker/`, `deploy/`, `ops/`, `infra/`, `.devcontainer/`, and `examples/`, but do not assume the right entry point must live there
|
||||
- look for `.env.example`, `.env.sample`, `env.example`, `middleware.env.example`, or similar templates
|
||||
- inspect whether the project uses Compose profiles, multiple compose files, generated compose files, or helper scripts
|
||||
- identify the canonical self-hosting entry point rather than assuming the repo root file is authoritative
|
||||
|
||||
3. Build a semantic model before writing Quadlet.
|
||||
- services
|
||||
- images or builds
|
||||
- ports
|
||||
- volumes and bind mounts
|
||||
- networks
|
||||
- environment variables and env files
|
||||
- restart policy
|
||||
- health checks
|
||||
- startup dependencies
|
||||
|
||||
4. Identify which values and decisions must be confirmed with the user.
|
||||
- external URLs, domains, and ports
|
||||
- database hostnames, passwords, and database names
|
||||
- storage backend selection and credentials
|
||||
- profile selection or optional service selection
|
||||
- pod grouping when the project has many services or optional containers
|
||||
- volume mode selection: named volume, bind mount, or anonymous volume
|
||||
- rootless vs rootful deployment mode
|
||||
- whether secrets should stay in env files or be moved elsewhere
|
||||
|
||||
Do not silently invent deployment-specific values. If the repository or compose file provides placeholders, defaults, or examples, read the surrounding documentation and comments yourself, infer the intended meaning, and only ask the user to confirm the values that materially affect deployment.
|
||||
|
||||
When many variables exist, do not hand the raw `.env.example` back to the user for manual review. Your job is to digest it, reduce it, and produce a concise checklist of high-impact decisions. Prioritize the variables that are required to produce a safe and runnable output.
|
||||
|
||||
At the end of planning, summarize what you learned and what you intend to generate, then explicitly ask the user whether anything should be changed or added before you move to the next phase.
|
||||
|
||||
Planning is also the phase where you must actively ask the user for the unresolved high-impact decisions you identified.
|
||||
|
||||
Do not defer first-time decision gathering into `QUADLET-FINALIZE.md`.
|
||||
|
||||
If decisions are still unresolved, stop in planning and ask the user directly. Do not write `QUADLET-FINALIZE.md` yet.
|
||||
|
||||
### Finalize phase
|
||||
|
||||
Goal: consolidate the decisions already made in planning into one internally consistent design snapshot and ask the user to review it.
|
||||
|
||||
The output of this phase must be written to a Markdown file named `QUADLET-FINALIZE.md`.
|
||||
|
||||
This filename is fixed. Do not rename it per project.
|
||||
|
||||
This phase starts only after planning-phase questions have been asked and the user has had a chance to answer or explicitly say there is nothing more to add.
|
||||
|
||||
Finalize is not a second discovery pass. Do not use it to introduce new major design choices, gather first-time requirements, or expand the scope of analysis. If execution reveals a new material decision or conflict, return to planning rather than stretching finalize into another analysis phase.
|
||||
|
||||
Tasks in this phase:
|
||||
|
||||
1. Freeze the chosen service set and runtime grouping.
|
||||
- prefer putting the whole project in a single pod when practical
|
||||
- if the project is a simple single-container deployment, a standalone `.container` is acceptable
|
||||
- if shared networking, shared published ports, or tighter lifecycle coupling make pod semantics useful, prefer one or more `.pod` units
|
||||
- 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`; if you split the topology across multiple pods, use container networking and service addressing, or publish ports across the host boundary when that better matches the deployment
|
||||
- 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
|
||||
|
||||
2. Freeze the storage strategy.
|
||||
- named volume, bind mount, or anonymous volume per storage use case
|
||||
- bind mounts must end up as absolute host paths
|
||||
|
||||
3. Freeze the image strategy.
|
||||
- prefer upstream prebuilt registry images when they already exist and local build is not required for correctness
|
||||
- create `.build` only when local build is actually required, or when the user explicitly wants a declarative local-build workflow
|
||||
- prefer fully qualified image names in generated output
|
||||
- if the source image omits a registry and is intended for Docker Hub, expand it explicitly instead of relying on short-name resolution
|
||||
- for images of the form `name[:tag]` with no namespace, normalize to `docker.io/library/name[:tag]`
|
||||
- for images of the form `namespace/name[:tag]` with no registry, normalize to `docker.io/namespace/name[:tag]`
|
||||
- if the source clearly points to another registry such as `ghcr.io`, `quay.io`, or a private registry, preserve that registry explicitly
|
||||
|
||||
4. Freeze the environment strategy.
|
||||
- use `Environment=` for a small number of stable non-sensitive values
|
||||
- use `EnvironmentFile=` for bulk variables, secrets, or values already sourced from `.env` / `env_file`
|
||||
- if Compose interpolation references variables that are missing, report them explicitly and prepare a candidate env file with placeholders or suggested defaults instead of delegating the entire review back to the user
|
||||
- treat variable names containing `PASSWORD`, `TOKEN`, `SECRET`, `KEY`, `PRIVATE`, or `PASS` as sensitive by default and avoid inlining unless the user explicitly wants that
|
||||
|
||||
5. Summarize already-known conflicts and their chosen resolution.
|
||||
- port collisions
|
||||
- incompatible grouping decisions
|
||||
- storage mode inconsistencies
|
||||
- unresolved required variables
|
||||
- mismatch between requested deployment mode and selected file locations
|
||||
|
||||
At the end of finalize, write `QUADLET-FINALIZE.md` and ask the user to review it before you start writing the final artifacts.
|
||||
|
||||
`QUADLET-FINALIZE.md` is a review artifact, not a questionnaire. It should summarize decisions that were already discussed in planning.
|
||||
|
||||
If `QUADLET-FINALIZE.md` already exists, read it first and update it intentionally. Do not blindly overwrite it without checking whether it reflects a prior review round that should be preserved or revised.
|
||||
|
||||
When the design has materially changed, replace outdated sections so the file remains a single current review snapshot rather than an append-only log.
|
||||
|
||||
`QUADLET-FINALIZE.md` should include:
|
||||
|
||||
- source inputs you chose and why
|
||||
- selected services and omitted optional services
|
||||
- pod layout
|
||||
- naming prefix
|
||||
- image strategy
|
||||
- volume strategy
|
||||
- env strategy
|
||||
- only the minimal placeholders that still cannot be resolved without user secrets or environment-specific values
|
||||
- detected conflicts and how they were resolved
|
||||
- the list of files that will be created in execution phase
|
||||
|
||||
Do not start execution until the user has reviewed and confirmed `QUADLET-FINALIZE.md` or provided requested edits.
|
||||
|
||||
Do not use `QUADLET-FINALIZE.md` as the first place where the user sees important choices. Those choices should already have been raised in planning.
|
||||
|
||||
### Execution phase
|
||||
|
||||
Goal: write the approved runnable artifacts.
|
||||
|
||||
Tasks in this phase:
|
||||
|
||||
1. Generate the Quadlet files.
|
||||
2. Generate the env file or env delta only when needed for runnable output.
|
||||
3. Generate deployment notes or validation guidance only when they materially help the user operate the result.
|
||||
4. Generate a README only when the user explicitly wants a self-contained handoff artifact or a packaged deliverable.
|
||||
|
||||
Execution should follow the approved contents of `QUADLET-FINALIZE.md`. If the implementation reveals a material conflict with the finalized design, stop and return to planning rather than silently diverging.
|
||||
|
||||
If you generate a README or operational notes, use the same language as the user unless the user explicitly asks for another language.
|
||||
|
||||
## Decision priority
|
||||
|
||||
When rules or signals conflict, use this priority order:
|
||||
|
||||
1. the user's explicit request
|
||||
2. the source project's documented canonical deployment path
|
||||
3. runnable and safe output
|
||||
4. maintainable output
|
||||
5. default style rules in this skill and its references
|
||||
|
||||
If a lower-priority default conflicts with a higher-priority source of truth, follow the higher-priority source and say so briefly.
|
||||
|
||||
## Hard stops
|
||||
|
||||
Stop and ask the user before finalizing or generating runnable output when any of these remain unresolved:
|
||||
|
||||
- required secrets, external URLs, host paths, or other deployment-specific values are missing
|
||||
- multiple plausible source inputs exist and the canonical deployment entry point cannot be determined confidently
|
||||
- image strategy versus local build strategy is materially ambiguous
|
||||
- a lossy mapping would change runtime behavior in a way that matters
|
||||
- the requested deployment mode conflicts with the intended output location or operator model
|
||||
|
||||
Do not keep moving forward by guessing through these gaps.
|
||||
|
||||
## Rootless vs rootful
|
||||
|
||||
Decide early whether the deployment is rootless or rootful, because this changes the output path and some operational guidance.
|
||||
|
||||
- For rootless deployments, use `~/.config/containers/systemd/` unless the user has a reason to use another supported path.
|
||||
- For rootful deployments, use `/etc/containers/systemd/` unless the user asks for a different placement.
|
||||
- For rootless long-running services, remind the user about lingering if relevant. See `references/deployment-notes.md`.
|
||||
|
||||
When you need authoritative details about supported search paths, unit semantics, option names, or debugging, read `references/podman-systemd.unit.5.md`.
|
||||
|
||||
## Reference routing
|
||||
|
||||
Use the reference files for detailed rules instead of restating them here:
|
||||
|
||||
- `references/compose-mapping.md` for Compose field mapping, topology choices, and naming conventions
|
||||
- `references/env-strategy.md` for `.env`, `env_file`, interpolation, and secret-handling defaults
|
||||
- `references/github-repo-intake.md` for GitHub repository discovery and canonical input selection
|
||||
- `references/deployment-notes.md` for deployment guidance and rootless or rootful operational notes
|
||||
- `references/validation.md` for post-generation validation and troubleshooting steps
|
||||
|
||||
## User collaboration
|
||||
|
||||
This skill is not a blind converter. For runnable output, collaborate tightly with the user.
|
||||
|
||||
- Confirm any environment value that controls external connectivity, credentials, storage, or deployment topology.
|
||||
- If the source contains a large env template, summarize the required variables into a small decision list and ask the user to confirm only those values.
|
||||
- Do not ask the user to read upstream docs or manually audit a large `.env.example` unless they explicitly want to do that themselves.
|
||||
- Read the docs, comments, and example values yourself, then present the user with a reduced set of concrete decisions and a candidate env result.
|
||||
- Ask the user to choose optional services and pod grouping early when the source project offers many containers or feature profiles.
|
||||
- Ask the user which volume mode they want before finalizing storage mappings.
|
||||
- Ask these questions before writing `QUADLET-FINALIZE.md`, not inside it.
|
||||
- Preserve placeholders when the user has not provided final values yet.
|
||||
- Distinguish between upstream example values and user-confirmed production values.
|
||||
|
||||
You should still make reasonable structural decisions yourself, but do not pretend unknown deployment inputs are settled facts.
|
||||
|
||||
## Deployment and validation
|
||||
|
||||
When the user wants runnable output, provide the relevant deployment notes from `references/deployment-notes.md` and the validation steps from `references/validation.md` as needed.
|
||||
|
||||
At minimum, mention the need to:
|
||||
|
||||
- place files in a valid Quadlet directory
|
||||
- run `systemctl daemon-reload` or `systemctl --user daemon-reload`
|
||||
- create required bind-mount directories before first start
|
||||
- verify generator output or systemd unit validity when startup fails
|
||||
|
||||
## Examples
|
||||
|
||||
- `docker run` for a single web service -> often `advice` or `generate` with one `.container`
|
||||
- small Compose app with api and db -> usually `design` or `generate`, often one `.pod` plus child containers
|
||||
- GitHub repo with `.env.example` and multiple profiles -> start in `Planning`, reduce the env questions, then move to `Finalize`
|
||||
|
||||
## Anti-examples
|
||||
|
||||
- do not dump a large `.env.example` back to the user as the primary review artifact
|
||||
- do not introduce first-time critical decisions inside `QUADLET-FINALIZE.md`
|
||||
- do not force pod topology when a standalone `.container` is the simpler correct result
|
||||
- do not keep generating through unresolved deployment-critical unknowns
|
||||
|
||||
## Boundaries
|
||||
|
||||
Do not claim perfect equivalence where Podman or Quadlet semantics differ from Docker Compose.
|
||||
|
||||
Be especially careful with:
|
||||
|
||||
- Compose interpolation and default syntax
|
||||
- `depends_on` readiness assumptions
|
||||
- complex `deploy` blocks
|
||||
- multi-file Compose merges
|
||||
- secrets and credentials
|
||||
- permission behavior on rootless bind mounts
|
||||
|
||||
If a mapping is lossy, say so directly and explain the concrete risk.
|
||||
177
references/compose-mapping.md
Normal file
177
references/compose-mapping.md
Normal file
@@ -0,0 +1,177 @@
|
||||
# Compose Mapping
|
||||
|
||||
Use this file when converting `docker-compose.yml` or `compose.yaml` into Quadlet units.
|
||||
|
||||
## General approach
|
||||
|
||||
- Model each service first, then decide how to group all resulting containers into one or more `.pod` units.
|
||||
- Prefer maintainable Quadlet output over mechanical one-to-one translation.
|
||||
- Keep names stable and predictable. Generated filenames should use a shared project prefix.
|
||||
|
||||
## Field strategy
|
||||
|
||||
### `name`
|
||||
|
||||
- Use as an application prefix when it improves unit naming clarity.
|
||||
- Do not force a top-level project name into every filename if the user prefers shorter units.
|
||||
|
||||
### `services.<name>.image`
|
||||
|
||||
- Map to `Image=` in `[Container]`.
|
||||
- Prefer fully qualified image names when normalizing output.
|
||||
- If the source omits a registry and is using Docker Hub semantics, normalize it explicitly for Podman.
|
||||
- Use these rules when filling in Docker Hub references:
|
||||
- `redis:7` -> `docker.io/library/redis:7`
|
||||
- `nginx` -> `docker.io/library/nginx`
|
||||
- `langgenius/dify-api:latest` -> `docker.io/langgenius/dify-api:latest`
|
||||
- Do not guess `docker.io/library/...` for images that already include a namespace.
|
||||
|
||||
### `services.<name>.build`
|
||||
|
||||
- Prefer upstream published images over local builds when the project already documents supported registry images.
|
||||
- If the user wants declarative builds, create a `.build` unit and reference it from `Image=`.
|
||||
- If the build semantics are too custom, or if an equivalent upstream image is clearly available, keep this as a manual follow-up item instead of guessing.
|
||||
|
||||
### `container_name`
|
||||
|
||||
- Drop it.
|
||||
- Do not generate `ContainerName=`. Let Podman and systemd derive the runtime name.
|
||||
|
||||
### `ports`
|
||||
|
||||
- For a standalone service, map to `PublishPort=` on the `.container`.
|
||||
- For a pod-based topology, prefer `PublishPort=` on the `.pod` when the published ports belong to the pod boundary rather than one child container.
|
||||
|
||||
### `volumes`
|
||||
|
||||
- Bind mounts become `Volume=HOST:CONTAINER[:OPTIONS]`.
|
||||
- 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.
|
||||
|
||||
### `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.
|
||||
- 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.
|
||||
|
||||
### `environment`
|
||||
|
||||
- Small stable values can become one or more `Environment=` lines.
|
||||
- Sensitive values should be moved to `EnvironmentFile=` unless the user explicitly wants them inline.
|
||||
|
||||
### `env_file`
|
||||
|
||||
- Prefer `EnvironmentFile=`.
|
||||
- If there are multiple env files, preserve order and explain precedence if the user asks.
|
||||
|
||||
### `.env` interpolation
|
||||
|
||||
- Resolve only when you have the actual source values.
|
||||
- If variables are missing, surface a missing-variable list.
|
||||
- Never silently replace unknown values with blanks.
|
||||
|
||||
### `profiles`
|
||||
|
||||
- Decide first which profiles are actually part of the desired deployment.
|
||||
- Do not try to preserve Compose profiles as a direct Quadlet concept.
|
||||
- Treat profiles as source selection inputs that decide which services become units.
|
||||
|
||||
### `depends_on`
|
||||
|
||||
- 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.
|
||||
- If the Compose healthcheck is only partially representable, preserve the command intent and call out missing knobs.
|
||||
|
||||
### `command` and `entrypoint`
|
||||
|
||||
- `entrypoint` typically maps to `Entrypoint=`.
|
||||
- `command` typically maps to `Exec=`.
|
||||
|
||||
### `user`
|
||||
|
||||
- Map to `User=` and `Group=` in `[Container]` only when it is a container runtime user mapping, not a systemd service user.
|
||||
- Do not use systemd `User=` to try to make a rootless Quadlet run as another login user.
|
||||
|
||||
### unsupported or risky fields
|
||||
|
||||
Handle these conservatively and usually as migration notes:
|
||||
|
||||
- `deploy`
|
||||
- `profiles`
|
||||
- `extends`
|
||||
- advanced Compose merge behavior
|
||||
- readiness semantics hidden behind `depends_on`
|
||||
|
||||
## Minimal examples
|
||||
|
||||
### Single service to standalone container
|
||||
|
||||
Source intent:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
ports:
|
||||
- "8080:80"
|
||||
```
|
||||
|
||||
Reasonable result shape:
|
||||
|
||||
```ini
|
||||
[Container]
|
||||
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.
|
||||
|
||||
### Small multi-service app to one pod
|
||||
|
||||
Source intent:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
api:
|
||||
image: ghcr.io/example/api:1.0
|
||||
depends_on:
|
||||
- db
|
||||
db:
|
||||
image: postgres:16
|
||||
```
|
||||
|
||||
Reasonable result shape:
|
||||
|
||||
- one `.pod` for the application boundary
|
||||
- one container unit for `api`
|
||||
- one container unit for `db`
|
||||
- `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.
|
||||
|
||||
## Pod decision rule
|
||||
|
||||
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 shared networking, shared published ports, or tightly coupled service lifecycle make pod semantics useful, prefer one or more `.pod` units.
|
||||
|
||||
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.
|
||||
|
||||
For large application stacks with optional services, ask the user to choose the desired service set before generating a minimized result.
|
||||
55
references/deployment-notes.md
Normal file
55
references/deployment-notes.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Deployment Notes
|
||||
|
||||
Use this file when the user wants deployment-ready instructions alongside generated Quadlet units.
|
||||
|
||||
## Directory choice
|
||||
|
||||
### Rootless
|
||||
|
||||
- primary default: `~/.config/containers/systemd/`
|
||||
- user-scoped management commands use `systemctl --user`
|
||||
|
||||
### Rootful
|
||||
|
||||
- primary default: `/etc/containers/systemd/`
|
||||
- system-scoped management commands use `systemctl`
|
||||
|
||||
See `podman-systemd.unit.5.md` for the full search-path matrix.
|
||||
|
||||
## Rootless operational notes
|
||||
|
||||
- Bind mounts may hit UID/GID mismatches.
|
||||
- For pod-based deployments that should preserve host ownership semantics, consider `UserNS=keep-id` on `[Pod]` when appropriate.
|
||||
- If the service must survive logout, mention lingering:
|
||||
|
||||
```bash
|
||||
sudo loginctl enable-linger <username>
|
||||
```
|
||||
|
||||
## Paths and bind mounts
|
||||
|
||||
- Ensure bind-mount source directories exist before first start.
|
||||
- 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 `./...`.
|
||||
|
||||
## Recommended service defaults
|
||||
|
||||
Depending on the workload, consider adding:
|
||||
|
||||
```ini
|
||||
[Service]
|
||||
Restart=always
|
||||
TimeoutStartSec=900
|
||||
```
|
||||
|
||||
Use the timeout especially when first start may need to pull large images or build locally.
|
||||
|
||||
## Useful optional enhancements
|
||||
|
||||
- `AutoUpdate=registry` for opt-in automatic image refresh workflows
|
||||
- explicit `.volume` or `.network` units when the user wants declarative infrastructure instead of implicit Podman objects
|
||||
|
||||
## Output language
|
||||
|
||||
If you generate a README, deployment note, or operator-facing document as part of the migration, write it in the user's language unless the user explicitly asks for another language.
|
||||
165
references/env-strategy.md
Normal file
165
references/env-strategy.md
Normal file
@@ -0,0 +1,165 @@
|
||||
# Environment Strategy
|
||||
|
||||
Use this file whenever the migration includes `.env`, `env_file`, Compose interpolation, or inline `-e` flags.
|
||||
|
||||
## Goals
|
||||
|
||||
- preserve source-of-truth for variables
|
||||
- avoid leaking secrets into generated Quadlet files by default
|
||||
- keep resulting units readable
|
||||
- report missing variables explicitly
|
||||
- reduce large upstream env templates into a small set of user decisions
|
||||
|
||||
## Default rules
|
||||
|
||||
The agent should actively interpret the env template and its comments. Do not offload the entire env review back to the user.
|
||||
|
||||
### Prefer `Environment=` when
|
||||
|
||||
- there are only a few variables
|
||||
- values are stable and not sensitive
|
||||
- keeping everything in one file materially improves readability
|
||||
|
||||
### Prefer `EnvironmentFile=` when
|
||||
|
||||
- the source already uses `.env` or `env_file`
|
||||
- variables are numerous
|
||||
- variables contain secrets or deployment-specific values
|
||||
- the same env file is shared by multiple services
|
||||
|
||||
## Sensitive-value heuristic
|
||||
|
||||
Treat names containing these substrings as sensitive unless the user tells you otherwise:
|
||||
|
||||
- `PASSWORD`
|
||||
- `TOKEN`
|
||||
- `SECRET`
|
||||
- `KEY`
|
||||
- `PRIVATE`
|
||||
- `PASS`
|
||||
|
||||
Default behavior:
|
||||
|
||||
- do not inline them in `Environment=`
|
||||
- keep them in `EnvironmentFile=` or generate a placeholder sample file instead
|
||||
|
||||
## Compose interpolation
|
||||
|
||||
Common forms:
|
||||
|
||||
- `${VAR}`
|
||||
- `${VAR:-default}`
|
||||
- `${VAR-default}`
|
||||
|
||||
Strategy:
|
||||
|
||||
- if the actual value source is present, resolve it and document where it came from
|
||||
- if only a default is available, note that the value is default-derived
|
||||
- if the variable is missing, list it as unresolved
|
||||
|
||||
Do not fabricate values.
|
||||
|
||||
## Agent responsibility
|
||||
|
||||
When the source project ships a large `.env.example` or multiple env templates:
|
||||
|
||||
- read the comments and deployment docs yourself
|
||||
- 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
|
||||
|
||||
The user should only need to answer the small number of high-impact questions that cannot be discovered locally.
|
||||
|
||||
## Minimal examples
|
||||
|
||||
### Inline stable values
|
||||
|
||||
Source intent:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
APP_ENV: production
|
||||
APP_PORT: "8080"
|
||||
```
|
||||
|
||||
Reasonable result shape:
|
||||
|
||||
```ini
|
||||
[Container]
|
||||
Environment=APP_ENV=production
|
||||
Environment=APP_PORT=8080
|
||||
```
|
||||
|
||||
Use this when there are only a few non-sensitive structural values.
|
||||
|
||||
### Preserve env-file workflow
|
||||
|
||||
Source intent:
|
||||
|
||||
```yaml
|
||||
env_file:
|
||||
- .env
|
||||
```
|
||||
|
||||
Reasonable result shape:
|
||||
|
||||
```ini
|
||||
[Container]
|
||||
EnvironmentFile=/opt/myapp/.env
|
||||
```
|
||||
|
||||
Use this when the source already relies on an env file, especially for secrets or many variables.
|
||||
|
||||
### Large template reduced to a candidate env
|
||||
|
||||
Source intent:
|
||||
|
||||
- upstream ships `.env.example`
|
||||
- only a few values are true deployment decisions
|
||||
|
||||
Recommended behavior:
|
||||
|
||||
- keep documented defaults that are safe to preserve
|
||||
- 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
|
||||
|
||||
## Output patterns
|
||||
|
||||
### Small inline set
|
||||
|
||||
```ini
|
||||
[Container]
|
||||
Environment=APP_ENV=production
|
||||
Environment=APP_PORT=8080
|
||||
```
|
||||
|
||||
### External env file
|
||||
|
||||
```ini
|
||||
[Container]
|
||||
EnvironmentFile=/opt/myapp/myapp.env
|
||||
```
|
||||
|
||||
### Mixed pattern
|
||||
|
||||
Use this when a few values are structural and the rest are secret or deployment-specific.
|
||||
|
||||
```ini
|
||||
[Container]
|
||||
Environment=APP_ENV=production
|
||||
EnvironmentFile=/opt/myapp/myapp.env
|
||||
```
|
||||
|
||||
## Missing-variable reporting
|
||||
|
||||
When variables cannot be resolved, report them as a concrete checklist.
|
||||
|
||||
Example:
|
||||
|
||||
- missing `DB_PASSWORD`
|
||||
- missing `IMMICH_VERSION`
|
||||
- missing `UPLOAD_LOCATION`
|
||||
|
||||
If the user asks for scaffolding, generate a sample env file with obvious placeholders.
|
||||
|
||||
Even when the user does not explicitly ask for scaffolding, produce a candidate env result when that materially advances the migration.
|
||||
57
references/github-repo-intake.md
Normal file
57
references/github-repo-intake.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# GitHub Repository Intake
|
||||
|
||||
Use this file when the user provides a GitHub repository URL and expects you to find the deployment inputs yourself.
|
||||
|
||||
## Goal
|
||||
|
||||
Discover the canonical self-hosting assets before attempting any Quadlet conversion.
|
||||
|
||||
## Discovery order
|
||||
|
||||
1. Read the repository `README.md`.
|
||||
2. Look for self-hosting instructions and explicit references to Compose files.
|
||||
3. If documentation names a path, follow that path first.
|
||||
4. Search the repository tree for likely deployment files:
|
||||
- `docker-compose.yaml`
|
||||
- `docker-compose.yml`
|
||||
- `compose.yaml`
|
||||
- `compose.yml`
|
||||
- `.env.example`
|
||||
- `.env.sample`
|
||||
- `env.example`
|
||||
- `middleware.env.example`
|
||||
5. Inspect likely deployment directories when needed:
|
||||
- `docker/`
|
||||
- `deploy/`
|
||||
- `ops/`
|
||||
- `infra/`
|
||||
- `examples/`
|
||||
- `.devcontainer/`
|
||||
6. Read deployment-specific README files in those directories.
|
||||
7. Identify helper scripts that generate or sync compose files.
|
||||
|
||||
## What to extract
|
||||
|
||||
- canonical compose file path
|
||||
- companion env template path
|
||||
- additional compose files used for middleware or optional services
|
||||
- whether the compose file is generated
|
||||
- whether the source relies on profiles
|
||||
- whether startup requires preparatory steps such as copying `.env.example` to `.env`
|
||||
|
||||
## Heuristics
|
||||
|
||||
- Prefer the path explicitly linked from the main README over a randomly discovered file.
|
||||
- Do not hardcode assumptions like "the deployment entry point is always under `docker/`".
|
||||
- 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 several candidate compose files exist, explain which one you selected and why.
|
||||
|
||||
## Migration posture for GitHub-sourced projects
|
||||
|
||||
When converting a GitHub-hosted project, report:
|
||||
|
||||
- which files you chose as source of truth
|
||||
- which optional files or profiles you ignored
|
||||
- which variables still require user decisions
|
||||
2556
references/podman-systemd.unit.5.md
Normal file
2556
references/podman-systemd.unit.5.md
Normal file
File diff suppressed because it is too large
Load Diff
70
references/validation.md
Normal file
70
references/validation.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# Validation
|
||||
|
||||
Use this file when the user asks how to verify or troubleshoot generated Quadlet units.
|
||||
|
||||
## Basic deployment flow
|
||||
|
||||
### Rootless
|
||||
|
||||
```bash
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user start <unit>
|
||||
systemctl --user status <unit>
|
||||
```
|
||||
|
||||
### Rootful
|
||||
|
||||
```bash
|
||||
systemctl daemon-reload
|
||||
systemctl start <unit>
|
||||
systemctl status <unit>
|
||||
```
|
||||
|
||||
## Generator debugging
|
||||
|
||||
Use the Podman systemd generator dry run when units fail to appear or options look unsupported.
|
||||
|
||||
```bash
|
||||
/usr/lib/systemd/system-generators/podman-system-generator --dryrun
|
||||
```
|
||||
|
||||
For rootless debugging:
|
||||
|
||||
```bash
|
||||
/usr/lib/systemd/system-generators/podman-system-generator --user --dryrun
|
||||
```
|
||||
|
||||
## Systemd verification
|
||||
|
||||
```bash
|
||||
systemd-analyze verify <unit>.service
|
||||
```
|
||||
|
||||
For user units:
|
||||
|
||||
```bash
|
||||
systemd-analyze --user verify <unit>.service
|
||||
```
|
||||
|
||||
## Common failure causes
|
||||
|
||||
- unsupported Quadlet option for the installed Podman version
|
||||
- bind-mount source directory missing
|
||||
- wrong rootless or rootful unit directory
|
||||
- unresolved env file path
|
||||
- permissions on rootless bind mounts
|
||||
- readiness assumptions hidden behind `depends_on`
|
||||
|
||||
## Troubleshooting posture
|
||||
|
||||
When validation fails, report:
|
||||
|
||||
- what generated successfully
|
||||
- what failed to generate or start
|
||||
- whether the issue is syntax, unsupported feature, path resolution, or permissions
|
||||
|
||||
## Relationship to execution phase
|
||||
|
||||
Validation belongs after the files are written in the execution phase.
|
||||
|
||||
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