add-service
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinese<objective>
Add a Docker development service to the current project by writing configuration files to
`.devtools/`. Supported services: Redis, RabbitMQ, PostgreSQL, MySQL/MariaDB, MongoDB.
The skill asks for port, image version, and credentials before writing anything. A
configuration summary is shown for confirmation before any file is created. The skill is
safe to re-run: it detects existing installs and either exits cleanly or installs a
named second instance (alias). All credentials land in which is gitignored.
</objective>
<context>
Service requested: $ARGUMENTS.devtools/.env<objective>
通过将配置文件写入`.devtools/`目录,为当前项目添加Docker开发服务。支持的服务包括:Redis、RabbitMQ、PostgreSQL、MySQL/MariaDB、MongoDB。
在写入任何内容之前,该技能会询问端口、镜像版本和凭据信息。在创建任何文件之前,会显示配置摘要供用户确认。该技能可安全重复运行:它会检测已有的安装,要么干净退出,要么安装一个命名的第二个实例(别名)。所有凭据都会保存在文件中,该文件已被设置为Git忽略。
</objective>
<context>
请求的服务:$ARGUMENTS.devtools/.envService Registry
服务注册表
All template paths below are relative to (defined below) — fetch them
remotely at runtime. The target project's CWD is separate — do NOT mix these paths.
SKILL_RAW_BASE| Service | Compose Template | Taskfile Template | Metadata |
|---|---|---|---|
| redis | compose-templates/redis/redis.compose.yml | taskfile-templates/redis/redis.Taskfile.yml | compose-templates/redis/metadata.json |
| rabbitmq | compose-templates/rabbitmq/rabbitmq.compose.yml | taskfile-templates/rabbitmq/rabbitmq.Taskfile.yml | compose-templates/rabbitmq/metadata.json |
| postgres | compose-templates/postgres/postgres.compose.yml | taskfile-templates/postgres/postgres.Taskfile.yml | compose-templates/postgres/metadata.json |
| mysql | compose-templates/mysql/mysql.compose.yml | taskfile-templates/mysql/mysql.Taskfile.yml | compose-templates/mysql/metadata.json |
| mongodb | compose-templates/mongodb/mongodb.compose.yml | taskfile-templates/mongodb/mongodb.Taskfile.yml | compose-templates/mongodb/metadata.json |
| monitoring | compose-templates/monitoring/monitoring.compose.yml | taskfile-templates/monitoring/monitoring.Taskfile.yml | compose-templates/monitoring/metadata.json |
Root Taskfile template:
taskfile-templates/root/Taskfile.yml以下所有模板路径均相对于(定义如下)——在运行时远程获取。目标项目的CWD是独立的——请勿混淆这些路径。
SKILL_RAW_BASE| 服务 | Compose模板 | Taskfile模板 | 元数据 |
|---|---|---|---|
| redis | compose-templates/redis/redis.compose.yml | taskfile-templates/redis/redis.Taskfile.yml | compose-templates/redis/metadata.json |
| rabbitmq | compose-templates/rabbitmq/rabbitmq.compose.yml | taskfile-templates/rabbitmq/rabbitmq.Taskfile.yml | compose-templates/rabbitmq/metadata.json |
| postgres | compose-templates/postgres/postgres.compose.yml | taskfile-templates/postgres/postgres.Taskfile.yml | compose-templates/postgres/metadata.json |
| mysql | compose-templates/mysql/mysql.compose.yml | taskfile-templates/mysql/mysql.Taskfile.yml | compose-templates/mysql/metadata.json |
| mongodb | compose-templates/mongodb/mongodb.compose.yml | taskfile-templates/mongodb/mongodb.Taskfile.yml | compose-templates/mongodb/metadata.json |
| monitoring | compose-templates/monitoring/monitoring.compose.yml | taskfile-templates/monitoring/monitoring.Taskfile.yml | compose-templates/monitoring/metadata.json |
根Taskfile模板:
taskfile-templates/root/Taskfile.ymlRemote Template Base URL
远程模板基础URL
Templates are fetched at runtime from the skill's source repository. All template reads
below use this base URL (so the skill works when installed via — only
SKILL.md is installed locally):
npx skills addSKILL_RAW_BASE=https://raw.githubusercontent.com/Cyboooooorg/dev-tools/mainFetch any template with:
bash
curl -fsSL "${SKILL_RAW_BASE}/<template-path>"If is unavailable, use .
curlwget -qO- "${SKILL_RAW_BASE}/<template-path>"模板在运行时从技能的源仓库获取。以下所有模板读取操作均使用此基础URL(因此当通过安装技能时,该技能仍可正常工作——仅SKILL.md会被安装到本地):
npx skills addSKILL_RAW_BASE=https://raw.githubusercontent.com/Cyboooooorg/dev-tools/main使用以下命令获取任意模板:
bash
curl -fsSL "${SKILL_RAW_BASE}/<template-path>"如果不可用,请使用。
curlwget -qO- "${SKILL_RAW_BASE}/<template-path>"Template Format Note
模板格式说明
Compose templates already use references (e.g. ) — they do NOT
contain placeholders. For standard installs, copy templates verbatim. String
substitution (renaming env vars, container names, volume names) is only required for
alias/multi-instance installs.
</context>
<process>${ENV_VAR}${REDIS_PORT}{{TOKEN}}Compose模板已使用引用(例如)——它们不包含占位符。对于标准安装,直接复制模板内容即可。仅在别名/多实例安装时才需要进行字符串替换(重命名环境变量、容器名称、卷名称)。
</context>
<process>${ENV_VAR}${REDIS_PORT}{{TOKEN}}Step 1: Detect Installation State
步骤1:检测安装状态
Determine the service name:
- If is not empty,
$ARGUMENTS(normalize to lowercase).SERVICE=$ARGUMENTS - If is empty, skip to Step 3 to ask the user to select a service.
$ARGUMENTS
Check whether the service is already installed:
bash
test -f .devtools/${SERVICE}.compose.yml- If the file does not exist → continue to Step 2.
- If the file exists → go to Step 1a.
确定服务名称:
- 如果不为空,则
$ARGUMENTS(转换为小写)。SERVICE=$ARGUMENTS - 如果为空,则跳至步骤3,让用户选择服务。
$ARGUMENTS
检查该服务是否已安装:
bash
test -f .devtools/${SERVICE}.compose.yml- 如果文件不存在 → 继续执行步骤2。
- 如果文件存在 → 进入步骤1a。
Step 1a: Merge Detection
步骤1a:合并检测
The service is already installed. Inform the user:
"is already installed in${SERVICE}.".devtools/
Ask:
"Add another instance with an alias, or cancel? [alias/cancel]"- If user answers cancel → output and stop.
"Nothing written. Exiting." - If user provides an alias (e.g. ,
cache):session- Set (lowercase, letters/numbers/hyphens only).
ALIAS=<alias> - Set (e.g.
SERVICE_SLUG=${SERVICE}-${ALIAS}).redis-cache - Set (e.g.
SERVICE_SNAKE=${SERVICE}_${ALIAS}) — used for YAML service keys, volume keys, network keys.redis_cache - Set (e.g.
ENV_PREFIX=<SERVICE_UPPER>_<ALIAS_UPPER>) — used for env var names.REDIS_CACHE - Check if alias already installed:
bash
test -f .devtools/${SERVICE_SLUG}.compose.yml - If file exists → output and stop. (MERGE-04)
"${SERVICE_SLUG} is already installed — nothing to do." - If file does not exist → set and continue to Step 3.
MODE=alias
- Set
- No alias set and no existing file → set and continue to Step 2.
MODE=standard
该服务已安装。告知用户:
"已安装在${SERVICE}目录中。".devtools/
询问:
"是否使用别名添加另一个实例,还是取消?[alias/cancel]"- 如果用户回答cancel → 输出并停止操作。
"未写入任何内容。正在退出。" - 如果用户提供别名(例如、
cache):session- 设置(仅允许小写字母/数字/连字符)。
ALIAS=<alias> - 设置(例如
SERVICE_SLUG=${SERVICE}-${ALIAS})。redis-cache - 设置(例如
SERVICE_SNAKE=${SERVICE}_${ALIAS})——用于YAML服务键、卷键、网络键。redis_cache - 设置(例如
ENV_PREFIX=<SERVICE_UPPER>_<ALIAS_UPPER>)——用于环境变量名称。REDIS_CACHE - 检查别名是否已安装:
bash
undefined
- 设置
test -f .devtools/${SERVICE_SLUG}.compose.yml
- 如果文件**存在** → 输出`"${SERVICE_SLUG}已安装——无需执行任何操作。"`并停止操作。(MERGE-04)
- 如果文件**不存在** → 设置`MODE=alias`并继续执行**步骤3**。
- 未设置别名且无现有文件 → 设置`MODE=standard`并继续执行**步骤2**。Step 2: First-Run Setup
步骤2:首次运行设置
Only run this step if does not yet exist.
.devtools/Check:
bash
test -d .devtools-
Ifexists → skip to Step 3.
.devtools/ -
Ifdoes not exist → proceed:
.devtools/- Announce: .
"Creating .devtools/ directory..." - Create the directory:
bash
mkdir -p .devtools - Write with exactly this content (do not add any other entries):
.devtools/.gitignore.env - Ask:
"Project name for Docker namespacing? [default: <derive from git remote or pwd>]"- Derive the default: run
basename $(git remote get-url origin 2>/dev/null || echo $(pwd)) | sed 's/\.git$//' - Set .
COMPOSE_PROJECT_NAME=<user answer or default>
- Derive the default: run
- Continue to Step 3.
Ifalready exists and contains.devtools/.env, skip the project name question entirely (D-20).COMPOSE_PROJECT_NAME - Announce:
仅当目录不存在时才执行此步骤。
.devtools/检查:
bash
test -d .devtools-
如果存在 → 跳至步骤3。
.devtools/ -
如果不存在 → 执行以下操作:
.devtools/- 提示:。
"正在创建.devtools/目录..." - 创建目录:
bash
mkdir -p .devtools - 向写入以下内容(请勿添加其他条目):
.devtools/.gitignore.env - 询问:
"用于Docker命名空间的项目名称?[默认值:从Git远程仓库或当前目录派生]"- 派生默认值:运行
basename $(git remote get-url origin 2>/dev/null || echo $(pwd)) | sed 's/\.git$//' - 设置。
COMPOSE_PROJECT_NAME=<用户输入或默认值>
- 派生默认值:运行
- 继续执行步骤3。
如果已存在且包含.devtools/.env,则完全跳过项目名称问题(D-20)。COMPOSE_PROJECT_NAME - 提示:
Step 3: Service Selection
步骤3:服务选择
If is already set from , skip this step.
SERVICE$ARGUMENTSAsk the user:
"Which service would you like to add? (redis / rabbitmq / postgres / mysql / mongodb)"
- Set (normalize to lowercase).
SERVICE=<user answer> - If the answer is not one of the five supported services, respond:
and stop.
"Service '<answer>' is not supported. Supported: redis, rabbitmq, postgres, mysql, mongodb."
Return to Step 1 to run the merge detection check for this service before continuing.
如果已通过设置,则跳过此步骤。
SERVICE$ARGUMENTS询问用户:
"您想要添加哪个服务?(redis / rabbitmq / postgres / mysql / mongodb)"
- 设置(转换为小写)。
SERVICE=<用户输入> - 如果输入的服务不在支持的五个服务范围内,回复:
并停止操作。
"服务'<输入内容>'不受支持。支持的服务:redis、rabbitmq、postgres、mysql、mongodb。"
返回步骤1,在继续之前对该服务执行合并检测检查。
Step 4: Read Service Metadata
步骤4:读取服务元数据
Read the metadata file for the selected service from the skill repo using:
bash
curl -fsSL "${SKILL_RAW_BASE}/compose-templates/${SERVICE}/metadata.json"Extract:
- — list of
parameters[]entries{ name, default, env_var, token } - — present or absent
ui_companion - — present or absent (used later for monitoring)
exporter
Store these for use in Step 5.
使用以下命令从技能仓库读取所选服务的元数据文件:
bash
curl -fsSL "${SKILL_RAW_BASE}/compose-templates/${SERVICE}/metadata.json"提取:
- —
parameters[]条目列表{ name, default, env_var, token } - — 存在或不存在
ui_companion - — 存在或不存在(稍后用于监控)
exporter
将这些存储起来供步骤5使用。
Step 5: Per-Service Q&A
步骤5:按服务提问
Ask each question individually using . Show the inline default on every
question as . Accept the user's answer or use the default if they press enter.
AskUserQuestion[default: X]使用逐个提出问题。每个问题都显示内联默认值。接受用户输入,若用户按回车键则使用默认值。
AskUserQuestion[default: X]Universal questions (all services):
通用问题(所有服务):
-
Port?
[default: <port from metadata>]- Store answer as .
ANSWERS[port]
- Store answer as
-
Image version/tag?
[default: <version from metadata>]- Store answer as .
ANSWERS[version]
- Store answer as
-
端口?
[default: <元数据中的端口>]- 将答案存储为。
ANSWERS[port]
- 将答案存储为
-
镜像版本/标签?
[default: <元数据中的版本>]- 将答案存储为。
ANSWERS[version]
- 将答案存储为
Per-service credential questions:
按服务的凭据问题:
redis
redis
(Port default: )
3.
[default: 6379]"Password? [optional — press enter to skip]"- If user presses enter → (empty string — Redis runs without auth).
ANSWERS[password]="" - Otherwise → .
ANSWERS[password]=<user input>
(默认端口:)
3.
[default: 6379]"密码?[可选——按回车键跳过]"- 如果用户按回车键 → (空字符串——Redis无认证运行)。
ANSWERS[password]="" - 否则 → 。
ANSWERS[password]=<用户输入>
rabbitmq
rabbitmq
(Port default: )
3. →
4. → (must be non-empty; re-ask if blank)
5. →
(Note: RabbitMQ management UI is always-on — bundled in the rabbitmq:-management image.
Step 6 "Enable UI companion?" is SKIPPED for RabbitMQ.)*
[default: 5672]"Username? [default: admin]"ANSWERS[username]"Password? (required — no default)"ANSWERS[password]"Management UI port? [default: 15672]"ANSWERS[ui_port](默认端口:)
3. →
4. → (必须非空;若为空则重新询问)
5. →
(注意:RabbitMQ管理UI始终启用——包含在rabbitmq:-management镜像中。
步骤6“启用UI伴生服务?”对RabbitMQ跳过。)*
[default: 5672]"用户名?[default: admin]"ANSWERS[username]"密码?(必填——无默认值)"ANSWERS[password]"管理UI端口?[default: 15672]"ANSWERS[ui_port]postgres
postgres
(Port default: )
3. →
4. → (re-ask if blank)
5. →
[default: 5432]"Username? [default: postgres]"ANSWERS[username]"Password? (required — no default)"ANSWERS[password]"Database name? [default: app]"ANSWERS[db_name](默认端口:)
3. →
4. → (若为空则重新询问)
5. →
[default: 5432]"用户名?[default: postgres]"ANSWERS[username]"密码?(必填——无默认值)"ANSWERS[password]"数据库名称?[default: app]"ANSWERS[db_name]mysql
mysql
(Port default: )
3. →
4. → (re-ask if blank)
5. →
6. →
(MYSQL_ROOT_PASSWORD — required by MariaDB/MySQL even though it has token: null in metadata.json)
7. (MariaDB is the default image variant. MariaDB 11 ≈ MySQL 8 compatible. If user needs MySQL:
they can override the version tag to use mysql:8 instead.)
[default: 3306]"Username? [default: app]"ANSWERS[username]"Password? (required — no default)"ANSWERS[password]"Database name? [default: app]"ANSWERS[db_name]"Root password? (required — no default)"ANSWERS[root_password](默认端口:)
3. →
4. → (若为空则重新询问)
5. →
6. →
(MYSQL_ROOT_PASSWORD——MariaDB/MySQL要求必填,即使其在metadata.json中token为null)
7. (MariaDB是默认镜像变体。MariaDB 11与MySQL 8兼容。如果用户需要MySQL:
他们可以覆盖版本标签以使用mysql:8。)
[default: 3306]"用户名?[default: app]"ANSWERS[username]"密码?(必填——无默认值)"ANSWERS[password]"数据库名称?[default: app]"ANSWERS[db_name]"Root密码?(必填——无默认值)"ANSWERS[root_password]mongodb
mongodb
(Port default: )
3. →
4. → (re-ask if blank)
[default: 27017]"Username? [default: admin]"ANSWERS[username]"Password? (required — no default)"ANSWERS[password](默认端口:)
3. →
4. → (若为空则重新询问)
[default: 27017]"用户名?[default: admin]"ANSWERS[username]"密码?(必填——无默认值)"ANSWERS[password]Step 6: UI Companion Prompt
步骤6:UI伴生服务提示
Skip this step entirely for — its management UI is always-on (handled in Step 5).
rabbitmqFor all other services (redis, postgres, mysql, mongodb) that have a entry
in their metadata:
ui_companionAsk: (default: N)
"Enable UI companion? [y/N]"-
If No → setand skip to Step 7.
ANSWERS[ui_enabled]=false -
If Yes → set.
ANSWERS[ui_enabled]=trueAsk:(default: N) →"Enable auth on UI? [y/N]"ANSWERS[ui_auth]=<true/false>Service-specific follow-ups when UI is enabled:postgres (pgAdmin credentials)
Ask:→"pgAdmin login email? [default: admin@local.dev]"Ask:ANSWERS[pgadmin_email]→"pgAdmin login password? (required)"(re-ask if blank)ANSWERS[pgadmin_password]mysql (phpMyAdmin — no extra credentials needed beyond service creds)
(No additional questions — phpMyAdmin connects using MYSQL_USER / MYSQL_PASSWORD.)mongodb (Mongo Express auth)
If: Ask:ANSWERS[ui_auth]=true→"Mongo Express username? [default: admin]"Ask:ANSWERS[me_username]→"Mongo Express password? (required)"(re-ask if blank)ANSWERS[me_password]redis (RedisInsight — no extra credentials needed)
(RedisInsight authenticates via the Redis password already captured in Step 5.)
对完全跳过此步骤——其管理UI始终启用(在步骤5中已处理)。
rabbitmq对于元数据中包含条目的所有其他服务(redis、postgres、mysql、mongodb):
ui_companion询问:(默认值:N)
"启用UI伴生服务?[y/N]"-
如果否 → 设置并跳至步骤7。
ANSWERS[ui_enabled]=false -
如果是 → 设置。
ANSWERS[ui_enabled]=true询问:(默认值:N)→"为UI启用认证?[y/N]"ANSWERS[ui_auth]=<true/false>启用UI时的服务特定后续问题:postgres(pgAdmin凭据)
询问:→"pgAdmin登录邮箱?[default: admin@local.dev]"询问:ANSWERS[pgadmin_email]→"pgAdmin登录密码?(必填)"(若为空则重新询问)ANSWERS[pgadmin_password]mysql(phpMyAdmin——无需额外凭据,使用服务凭据即可)
(无额外问题——phpMyAdmin使用MYSQL_USER / MYSQL_PASSWORD连接。)mongodb(Mongo Express认证)
如果: 询问:ANSWERS[ui_auth]=true→"Mongo Express用户名?[default: admin]"询问:ANSWERS[me_username]→"Mongo Express密码?(必填)"(若为空则重新询问)ANSWERS[me_password]redis(RedisInsight——无需额外凭据)
(RedisInsight使用步骤5中已捕获的Redis密码进行认证。)
Step 7: Optional Feature Prompts
步骤7:可选功能提示
Ask: (default: Y) →
"Also set up Taskfile tasks? [Y/n]"ANSWERS[taskfile]=<true/false>Ask: (default: N) →
"Also install monitoring (Grafana + Prometheus)? [y/N]"ANSWERS[monitoring]=<true/false>If :
Ask: →
(Default is intentionally weak — surfaced here so user can change it.)
ANSWERS[monitoring]=true"Grafana admin password? [default: admin]"ANSWERS[grafana_password]询问:(默认值:Y)→
"是否同时设置Taskfile任务?[Y/n]"ANSWERS[taskfile]=<true/false>询问:(默认值:N)→
"是否同时安装监控(Grafana + Prometheus)?[y/N]"ANSWERS[monitoring]=<true/false>如果:
询问: →
(默认值故意设置为弱密码——在此处展示以便用户修改。)
ANSWERS[monitoring]=true"Grafana管理员密码?[default: admin]"ANSWERS[grafana_password]Step 8: Configuration Summary + Confirmation Gate
步骤8:配置摘要 + 确认环节
Display a summary table of all collected values. Mask passwords with .
****Example layout (adapt to the actual service and answers):
Service: redis
Mode: standard install (or: alias install as "redis-cache")
─────────────────────────────────────────────
Port: 6379
Version: 7
Password: ****
UI companion: disabled
Taskfile tasks: yes
Monitoring: no
─────────────────────────────────────────────
Files to write:
.devtools/.gitignore (first install only)
.devtools/redis.compose.yml
.devtools/redis.Taskfile.yml (if Taskfile=yes)
.devtools/compose.yml (created or appended)
.devtools/Taskfile.yml (created on first install only)
.devtools/.env (appended)
.devtools/.env.example (appended)Ask:
"Write these files? [Y/n]"- If No → output and stop.
"Cancelled. Nothing written." - If Yes → continue to Step 9.
Do NOT write any files before this confirmation. Steps 9–13 perform all writes.
显示所有收集到的值的摘要表格。密码用掩码。
****示例布局(根据实际服务和答案调整):
服务: redis
模式: 标准安装 (或:别名安装为"redis-cache")
─────────────────────────────────────────────
端口: 6379
版本: 7
密码: ****
UI伴生服务: 已禁用
Taskfile任务: 是
监控: 否
─────────────────────────────────────────────
待写入文件:
.devtools/.gitignore (仅首次安装)
.devtools/redis.compose.yml
.devtools/redis.Taskfile.yml (如果Taskfile=yes)
.devtools/compose.yml (创建或追加内容)
.devtools/Taskfile.yml (仅首次安装时创建)
.devtools/.env (追加内容)
.devtools/.env.example (追加内容)询问:
"是否写入这些文件?[Y/n]"- 如果否 → 输出并停止操作。
"已取消。未写入任何内容。" - 如果是 → 继续执行步骤9。
**在确认前请勿写入任何文件。**步骤9–13执行所有写入操作。
Step 9: Write Per-Service Files
步骤9:写入按服务划分的文件
User confirmed "Yes" at Step 8. Proceed with file writes.
用户在步骤8中确认“是”。继续执行文件写入。
9a: Write Compose File
9a:写入Compose文件
Fetch the compose template from the skill repo:
bash
curl -fsSL "${SKILL_RAW_BASE}/compose-templates/${SERVICE}/${SERVICE}.compose.yml"For standard install (): Copy the file content verbatim.
MODE=standardSpecial case — Redis, no password: If and is empty
string (user pressed enter to skip), after loading the template content:
SERVICE=redisANSWERS[password]- Remove the argument from the
--requirepass ${REDIS_PASSWORD}line.command: - Remove from the
-a "${REDIS_PASSWORD}"command. Write the modified content (not the raw template) tohealthcheck.test..devtools/redis.compose.yml
For alias install (): Before writing, perform all string substitutions in the
file content — see Step 12 for the complete substitution map. Apply substitutions to the
in-memory copy before writing. Do NOT modify the original template file.
MODE=aliasWrite to the target project:
.devtools/<filename>.compose.ymlWhere is for standard, or for alias
(e.g. ).
<filename>${SERVICE}${SERVICE_SLUG}redis-cache从技能仓库获取Compose模板:
bash
curl -fsSL "${SKILL_RAW_BASE}/compose-templates/${SERVICE}/${SERVICE}.compose.yml"对于标准安装(): 直接复制文件内容。
MODE=standard特殊情况——Redis无密码: 如果且为空字符串(用户按回车键跳过),加载模板内容后:
SERVICE=redisANSWERS[password]- 从行中移除
command:参数。--requirepass ${REDIS_PASSWORD} - 从命令中移除
healthcheck.test。 将修改后的内容(而非原始模板)写入-a "${REDIS_PASSWORD}"。.devtools/redis.compose.yml
对于别名安装(): 写入前,对文件内容执行所有字符串替换——请参阅步骤12中的完整替换映射。在写入前对内存中的副本应用替换。请勿修改原始模板文件。
MODE=alias写入目标项目:
.devtools/<filename>.compose.yml其中对于标准安装是,对于别名安装是(例如)。
<filename>${SERVICE}${SERVICE_SLUG}redis-cache9b: Write Taskfile (if ANSWERS[taskfile]=true)
9b:写入Taskfile(如果ANSWERS[taskfile]=true)
Fetch the per-service Taskfile template from the skill repo:
bash
curl -fsSL "${SKILL_RAW_BASE}/taskfile-templates/${SERVICE}/${SERVICE}.Taskfile.yml"For alias install: Perform string substitutions (see Step 12) on the in-memory copy.
Write to the target project:
.devtools/<filename>.Taskfile.ymlWhere is for standard, or for alias.
<filename>${SERVICE}${SERVICE_SLUG}Note: Always write the per-service file (Step 9) BEFORE updating (Step 11).
This ensures never references a file that failed to write.
compose.ymlcompose.yml从技能仓库获取按服务划分的Taskfile模板:
bash
curl -fsSL "${SKILL_RAW_BASE}/taskfile-templates/${SERVICE}/${SERVICE}.Taskfile.yml"对于别名安装: 对内存中的副本执行字符串替换(请参阅步骤12)。
写入目标项目:
.devtools/<filename>.Taskfile.yml其中对于标准安装是,对于别名安装是。
<filename>${SERVICE}${SERVICE_SLUG}注意: 始终先写入按服务划分的文件(步骤9),再更新(步骤11)。
这确保永远不会引用写入失败的文件。
compose.ymlcompose.ymlStep 10: .env Management
步骤10:.env管理
10a: Write .devtools/.env
10a:写入.devtools/.env
Append a section block to (create the file if it does not exist):
.devtools/.envundefined向追加一个区块(如果文件不存在则创建):
.devtools/.envundefined── <SERVICE> ───────────────────────────────────────
── <SERVICE> ───────────────────────────────────────
<ENV_VAR_NAME>=<value>
...
For **standard** install — env var names from metadata `env_var` field:
| Service | Env vars to append |
|---------|-------------------|
| redis | REDIS_PORT, REDIS_VERSION, REDIS_PASSWORD (empty string if skipped) |
| rabbitmq | RABBITMQ_PORT, RABBITMQ_VERSION, RABBITMQ_USERNAME, RABBITMQ_PASSWORD, RABBITMQ_UI_PORT |
| postgres | POSTGRES_PORT, POSTGRES_VERSION, POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB, POSTGRES_UI_PORT (if UI enabled), PGADMIN_DEFAULT_EMAIL (if UI enabled), PGADMIN_DEFAULT_PASSWORD (if UI enabled) |
| mysql | MYSQL_PORT, MYSQL_VERSION, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_ROOT_PASSWORD, MYSQL_UI_PORT (if UI enabled) |
| mongodb | MONGODB_PORT, MONGODB_VERSION, MONGO_INITDB_ROOT_USERNAME, MONGO_INITDB_ROOT_PASSWORD, MONGODB_UI_PORT (if UI enabled), MONGO_EXPRESS_BASICAUTH (if UI enabled: `true` if auth, `false` if not), MONGO_EXPRESS_USER (if UI auth), MONGO_EXPRESS_PASSWORD (if UI auth) |
For **alias** install — prefix all env var names with `ENV_PREFIX_`:
e.g. `REDIS_CACHE_PORT`, `REDIS_CACHE_VERSION`, `REDIS_CACHE_PASSWORD`, etc.
**Conflict detection (D-13):** Before appending each key, check if the key already exists
in `.devtools/.env`. If it does:
- Mark the old line: append ` ## REPLACED` as an inline comment on that line.
- Append the new value on the next line.
- Record the conflict in a warnings list for the done summary.
If `COMPOSE_PROJECT_NAME` is not yet in `.devtools/.env`, prepend it as the very first entry.
Immediately after `COMPOSE_PROJECT_NAME`, if `COMPOSE_PROFILES` is not yet in `.devtools/.env`,
add it on the next line:
COMPOSE_PROJECT_NAME=<value>
COMPOSE_PROFILES=services
`COMPOSE_PROFILES=services` ensures `docker compose up` (with no `--profile` flag) starts
the core service containers. Without it the default profile is empty and all containers are
skipped. Never overwrite an existing `COMPOSE_PROFILES` entry — the user may have added `ui`
or `monitoring` to it.<ENV_VAR_NAME>=<value>
...
对于**标准**安装——环境变量名称来自元数据的`env_var`字段:
| 服务 | 要追加的环境变量 |
|---------|-------------------|
| redis | REDIS_PORT, REDIS_VERSION, REDIS_PASSWORD(如果跳过则为空字符串) |
| rabbitmq | RABBITMQ_PORT, RABBITMQ_VERSION, RABBITMQ_USERNAME, RABBITMQ_PASSWORD, RABBITMQ_UI_PORT |
| postgres | POSTGRES_PORT, POSTGRES_VERSION, POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB, POSTGRES_UI_PORT(如果UI启用), PGADMIN_DEFAULT_EMAIL(如果UI启用), PGADMIN_DEFAULT_PASSWORD(如果UI启用) |
| mysql | MYSQL_PORT, MYSQL_VERSION, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_ROOT_PASSWORD, MYSQL_UI_PORT(如果UI启用) |
| mongodb | MONGODB_PORT, MONGODB_VERSION, MONGO_INITDB_ROOT_USERNAME, MONGO_INITDB_ROOT_PASSWORD, MONGODB_UI_PORT(如果UI启用), MONGO_EXPRESS_BASICAUTH(如果UI启用:若认证则为`true`,否则为`false`), MONGO_EXPRESS_USER(如果UI启用认证), MONGO_EXPRESS_PASSWORD(如果UI启用认证) |
对于**别名**安装——所有环境变量名称前添加`ENV_PREFIX_`前缀:
例如`REDIS_CACHE_PORT`, `REDIS_CACHE_VERSION`, `REDIS_CACHE_PASSWORD`等。
**冲突检测(D-13):** 在追加每个键之前,检查该键是否已存在于`.devtools/.env`中。如果存在:
- 标记旧行:在该行末尾添加` ## REPLACED`作为内联注释。
- 在下行追加新值。
- 在完成总结中记录冲突警告。
如果`.devtools/.env`中尚未包含`COMPOSE_PROJECT_NAME`,则将其作为第一个条目前置。在`COMPOSE_PROJECT_NAME`之后,如果`.devtools/.env`中尚未包含`COMPOSE_PROFILES`,则在下一行添加:
COMPOSE_PROJECT_NAME=<value>
COMPOSE_PROFILES=services
`COMPOSE_PROFILES=services`确保`docker compose up`(不带`--profile`标志)启动核心服务容器。如果没有该设置,默认配置文件为空,所有容器都会被跳过。永远不要覆盖现有的`COMPOSE_PROFILES`条目——用户可能已添加`ui`或`monitoring`到其中。10b: Write .devtools/.env.example
10b:写入.devtools/.env.example
Append the same keys to (create if not exists) with dummy/placeholder
values only — never real credentials:
.devtools/.env.exampleundefined向追加相同的键(如果不存在则创建),但仅使用虚拟/占位符值——绝不使用真实凭据:
.devtools/.env.exampleundefined── <SERVICE> ───────────────────────────────────────
── <SERVICE> ───────────────────────────────────────
REDIS_PORT=6379
REDIS_VERSION=7
REDIS_PASSWORD=CHANGE_ME
REDIS_UI_PORT=5540
On the first service install, also add to `.devtools/.env.example`:COMPOSE_PROJECT_NAME=myapp
COMPOSE_PROFILES=services
Use obvious placeholder strings for credentials: `CHANGE_ME`, `admin@example.com`, etc.REDIS_PORT=6379
REDIS_VERSION=7
REDIS_PASSWORD=CHANGE_ME
REDIS_UI_PORT=5540
在首次安装服务时,还需向`.devtools/.env.example`添加:COMPOSE_PROJECT_NAME=myapp
COMPOSE_PROFILES=services
使用明显的占位符字符串作为凭据:`CHANGE_ME`, `admin@example.com`等。10c: Monitoring .env (if ANSWERS[monitoring]=true)
10c:监控.env(如果ANSWERS[monitoring]=true)
Append to :
.devtools/.envundefined向追加:
.devtools/.envundefined── Monitoring ──────────────────────────────────────
── Monitoring ──────────────────────────────────────
GRAFANA_ADMIN_USER=admin
GRAFANA_ADMIN_PASSWORD=<ANSWERS[grafana_password]>
Apply conflict detection (D-13) for `GRAFANA_ADMIN_USER` and `GRAFANA_ADMIN_PASSWORD`.
Append to `.devtools/.env.example` (dummy values only):GRAFANA_ADMIN_USER=admin
GRAFANA_ADMIN_PASSWORD=<ANSWERS[grafana_password]>
对`GRAFANA_ADMIN_USER`和`GRAFANA_ADMIN_PASSWORD`执行冲突检测(D-13)。
向`.devtools/.env.example`追加(仅使用虚拟值):── Monitoring ──────────────────────────────────────
── Monitoring ──────────────────────────────────────
GRAFANA_ADMIN_USER=admin
GRAFANA_ADMIN_PASSWORD=CHANGE_ME
undefinedGRAFANA_ADMIN_USER=admin
GRAFANA_ADMIN_PASSWORD=CHANGE_ME
undefined10d: Monitoring files (if ANSWERS[monitoring]=true)
10d:监控文件(如果ANSWERS[monitoring]=true)
Copy monitoring templates verbatim (no token substitution needed):
-
Fetch and write the compose template:bash
curl -fsSL "${SKILL_RAW_BASE}/compose-templates/monitoring/monitoring.compose.yml"Write fetched content toin the target project..devtools/monitoring.compose.yml -
If, fetch and write the Taskfile:
ANSWERS[taskfile]=truebashcurl -fsSL "${SKILL_RAW_BASE}/taskfile-templates/monitoring/monitoring.Taskfile.yml"Write fetched content toin the target project..devtools/monitoring.Taskfile.yml -
After writing(step 1 above), update
monitoring.compose.ymlto add the monitoring include (using the same create-or-append logic as Step 11a):.devtools/compose.ymlyaml- ./monitoring.compose.yml
Important: Write before updating include —
same write-order rule as Step 9 (Pitfall 6).
monitoring.compose.ymlcompose.yml直接复制监控模板(无需令牌替换):
-
获取并写入Compose模板:bash
curl -fsSL "${SKILL_RAW_BASE}/compose-templates/monitoring/monitoring.compose.yml"将获取的内容写入目标项目的。.devtools/monitoring.compose.yml -
如果,获取并写入Taskfile:
ANSWERS[taskfile]=truebashcurl -fsSL "${SKILL_RAW_BASE}/taskfile-templates/monitoring/monitoring.Taskfile.yml"将获取的内容写入目标项目的。.devtools/monitoring.Taskfile.yml -
写入后(上述步骤1),更新
monitoring.compose.yml以添加监控包含项(使用与步骤11a相同的创建或追加逻辑):.devtools/compose.ymlyaml- ./monitoring.compose.yml
重要提示: 先写入,再更新包含项——
与步骤9遵循相同的写入顺序规则(陷阱6)。
monitoring.compose.ymlcompose.ymlStep 11: Root File Management
步骤11:根文件管理
11a: Root Compose File (.devtools/compose.yml)
11a:根Compose文件(.devtools/compose.yml)
Check if exists:
.devtools/compose.ymlIf it does NOT exist (first service install):
Create with this content:
.devtools/compose.ymlyaml
undefined检查是否存在:
.devtools/compose.yml如果不存在(首次安装服务):
创建并写入以下内容:
.devtools/compose.ymlyaml
undefined.devtools/compose.yml
.devtools/compose.yml
Root compose aggregator — managed by dev-tools skill
根Compose聚合器——由dev-tools技能管理
Do not edit manually; run the skill to add or remove services.
请勿手动编辑;运行该技能以添加或移除服务。
include:
- ./<filename>.compose.yml
Where `<filename>` is `${SERVICE}` (standard) or `${SERVICE_SLUG}` (alias).
**If it DOES exist (subsequent service install):**
Read the file, locate the `include:` block, and append a new line:
```yaml
- ./<filename>.compose.ymlDo NOT rewrite the entire file — only add the new entry.
include:
- ./<filename>.compose.yml
其中`<filename>`是`${SERVICE}`(标准安装)或`${SERVICE_SLUG}`(别名安装)。
**如果存在(后续安装服务):**
读取文件,找到`include:`区块,并追加新行:
```yaml
- ./<filename>.compose.yml请勿重写整个文件——仅添加新条目。
11b: Root Taskfile (.devtools/Taskfile.yml)
11b:根Taskfile(.devtools/Taskfile.yml)
Check if exists:
.devtools/Taskfile.ymlbash
test -f .devtools/Taskfile.ymlIf it does NOT exist: Fetch and write the root Taskfile:
bash
curl -fsSL "${SKILL_RAW_BASE}/taskfile-templates/root/Taskfile.yml"Write the fetched content verbatim to .
.devtools/Taskfile.ymlIf it DOES exist: Do NOT overwrite it. The root Taskfile template already contains
for all 6 service includes — missing service files are silently skipped
at runtime. No append is needed.
optional: trueImportant: Never overwrite an existing . Users may have
customized it. The pattern makes per-install updates unnecessary.
.devtools/Taskfile.ymloptional: true检查是否存在:
.devtools/Taskfile.ymlbash
test -f .devtools/Taskfile.yml如果不存在: 获取并写入根Taskfile:
bash
curl -fsSL "${SKILL_RAW_BASE}/taskfile-templates/root/Taskfile.yml"将获取的内容直接写入。
.devtools/Taskfile.yml如果存在: 请勿覆盖它。根Taskfile模板已为所有6个服务包含项设置了——运行时会自动跳过缺失的服务文件。无需追加内容。
optional: true重要提示: 永远不要覆盖现有的。用户可能已对其进行自定义。模式使得无需在每次安装时更新该文件。
.devtools/Taskfile.ymloptional: trueStep 12: Alias Substitution (alias installs only)
步骤12:别名替换(仅别名安装)
Skip this step entirely for standard installs ().
MODE=standardFor alias installs, perform the following string substitutions throughout the compose file
content (in memory, before writing) and the Taskfile content (in memory, before writing).
Variables set in Step 1a:
- =
SERVICE_SLUG(e.g.${SERVICE}-${ALIAS}) — used in filenames and container namesredis-cache - =
SERVICE_SNAKE(e.g.${SERVICE}_${ALIAS}) — used in YAML keys, volumes, networksredis_cache - =
ENV_PREFIX(e.g.<SERVICE_UPPER>_<ALIAS_UPPER>) — used in env var namesREDIS_CACHE
标准安装()完全跳过此步骤。
MODE=standard对于别名安装,在Compose文件内容(内存中,写入前)和Taskfile内容(内存中,写入前)中执行以下字符串替换。
步骤1a中设置的变量:
- =
SERVICE_SLUG(例如${SERVICE}-${ALIAS})——用于文件名和容器名称redis-cache - =
SERVICE_SNAKE(例如${SERVICE}_${ALIAS})——用于YAML键、卷、网络redis_cache - =
ENV_PREFIX(例如<SERVICE_UPPER>_<ALIAS_UPPER>)——用于环境变量名称REDIS_CACHE
Compose file substitutions
Compose文件替换
| What | Old value (pattern) | New value |
|---|---|---|
| YAML service key | | |
| Container name suffix | | |
| Volume key declaration | | |
| Volume reference (under volumes:) | | |
| Network key declaration | | |
| Network reference (under networks:) | | |
| Env var names in content | | |
| Env var names in content | | |
| Env var names in content | | |
| Env var names in content | | |
| Env var names in content | | |
| Other service-specific env vars | | |
Service key note: YAML service keys must use underscore () — hyphens in
Compose service names cause network auto-naming issues. Container names and filenames use
hyphen () — that is correct and expected.
redis_cache:redis-cache| 替换对象 | 旧值(模式) | 新值 |
|---|---|---|
| YAML服务键 | | |
| 容器名称后缀 | | |
| 卷键声明 | | |
| 卷引用(在volumes:下) | | |
| 网络键声明 | | |
| 网络引用(在networks:下) | | |
| 内容中的环境变量名称 | | |
| 内容中的环境变量名称 | | |
| 内容中的环境变量名称 | | |
| 内容中的环境变量名称 | | |
| 内容中的环境变量名称 | | |
| 其他服务特定环境变量 | | |
服务键注意事项: YAML服务键必须使用下划线()——Compose服务名称中的连字符会导致网络自动命名问题。容器名称和文件名使用连字符()——这是正确且符合预期的。
redis_cache:redis-cache:Taskfile substitutions
Taskfile替换
Replace all references to the compose filename and service name within task commands:
- →
${SERVICE}.compose.yml${SERVICE_SLUG}.compose.yml - →
logs -f ${SERVICE}logs -f ${SERVICE_SNAKE} - →
restart ${SERVICE}restart ${SERVICE_SNAKE}
替换任务命令中对Compose文件名和服务名称的所有引用:
- →
${SERVICE}.compose.yml${SERVICE_SLUG}.compose.yml - →
logs -f ${SERVICE}logs -f ${SERVICE_SNAKE} - →
restart ${SERVICE}restart ${SERVICE_SNAKE}
Step 13: Done Summary
步骤13:完成总结
Output a completion summary:
✓ Done! Files written:List every file actually written (skip files that were skipped):
.devtools/.gitignore (first install)
.devtools/redis.compose.yml (or redis-cache.compose.yml for alias)
.devtools/redis.Taskfile.yml (if Taskfile=yes)
.devtools/compose.yml (created or updated)
.devtools/Taskfile.yml (if first install)
.devtools/.env (appended)
.devtools/.env.example (appended)Next steps:
Start service: task redis:up
With UI: task redis:up-ui
With monitoring: task redis:up-monitoring
Stop: task redis:downIf the service was installed with an alias, show the aliased task names:
Start service: task redis-cache:upIf any conflicts were found in , add a warning:
## REPLACED.devtools/.env⚠ Warning: The following keys were already present in .devtools/.env and have been replaced:
- REDIS_PORT (old value marked ## REPLACED)
Review .devtools/.env if this is unexpected.Always add the reminder:
⚠ Do not commit .devtools/.env — it contains real credentials.
.devtools/.gitignore already excludes it.<success_criteria>
- Service compose file exists at (or
.devtools/<service>.compose.yml)<service>-<alias>.compose.yml - Service Taskfile exists at (if Taskfile=yes)
.devtools/<service>.Taskfile.yml - contains all service env vars with real values
.devtools/.env - contains all service env var names with dummy/placeholder values
.devtools/.env.example - exists and contains
.devtools/.gitignore.env - exists and includes the new service's compose file
.devtools/compose.yml - exists (created or pre-existing)
.devtools/Taskfile.yml - starts the service successfully
task <service>:up - Re-running the skill for the same service asks alias-or-cancel (no silent overwrite)
- Re-running with an identical alias produces "already installed — nothing to do" </success_criteria>
输出完成总结:
✓ 完成!已写入文件:列出所有实际写入的文件(跳过未写入的文件):
.devtools/.gitignore (首次安装)
.devtools/redis.compose.yml (别名安装则为redis-cache.compose.yml)
.devtools/redis.Taskfile.yml (如果Taskfile=yes)
.devtools/compose.yml (已创建或更新)
.devtools/Taskfile.yml (如果是首次安装)
.devtools/.env (已追加内容)
.devtools/.env.example (已追加内容)后续步骤:
启动服务: task redis:up
带UI启动: task redis:up-ui
带监控启动: task redis:up-monitoring
停止服务: task redis:down如果服务使用别名安装,显示别名化的任务名称:
启动服务: task redis-cache:up如果在中发现任何冲突,添加警告:
.devtools/.env## REPLACED⚠ 警告:以下键已存在于.devtools/.env中并已被替换:
- REDIS_PORT (旧值已标记为## REPLACED)
如果此情况不符合预期,请检查.devtools/.env。始终添加提醒:
⚠ 请勿提交.devtools/.env —— 它包含真实凭据。
.devtools/.gitignore已将其排除在版本控制外。<success_criteria>
- 服务Compose文件存在于(或
.devtools/<service>.compose.yml)<service>-<alias>.compose.yml - 服务Taskfile存在于(如果Taskfile=yes)
.devtools/<service>.Taskfile.yml - 包含所有服务环境变量及真实值
.devtools/.env - 包含所有服务环境变量名称及虚拟/占位符值
.devtools/.env.example - 存在且包含
.devtools/.gitignore.env - 存在且包含新服务的Compose文件
.devtools/compose.yml - 存在(已创建或预先存在)
.devtools/Taskfile.yml - 可成功启动服务
task <service>:up - 对同一服务重新运行该技能会询问“别名或取消”(无静默覆盖)
- 使用相同别名重新运行会提示“已安装——无需执行任何操作” </success_criteria>