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
.devtools/.env
which is gitignored. </objective>
<context> Service requested: $ARGUMENTS
<objective> 通过将配置文件写入`.devtools/`目录,为当前项目添加Docker开发服务。支持的服务包括:Redis、RabbitMQ、PostgreSQL、MySQL/MariaDB、MongoDB。
在写入任何内容之前,该技能会询问端口、镜像版本和凭据信息。在创建任何文件之前,会显示配置摘要供用户确认。该技能可安全重复运行:它会检测已有的安装,要么干净退出,要么安装一个命名的第二个实例(别名)。所有凭据都会保存在
.devtools/.env
文件中,该文件已被设置为Git忽略。 </objective>
<context> 请求的服务:$ARGUMENTS

Service Registry

服务注册表

All template paths below are relative to
SKILL_RAW_BASE
(defined below) — fetch them remotely at runtime. The target project's CWD is separate — do NOT mix these paths.
ServiceCompose TemplateTaskfile TemplateMetadata
rediscompose-templates/redis/redis.compose.ymltaskfile-templates/redis/redis.Taskfile.ymlcompose-templates/redis/metadata.json
rabbitmqcompose-templates/rabbitmq/rabbitmq.compose.ymltaskfile-templates/rabbitmq/rabbitmq.Taskfile.ymlcompose-templates/rabbitmq/metadata.json
postgrescompose-templates/postgres/postgres.compose.ymltaskfile-templates/postgres/postgres.Taskfile.ymlcompose-templates/postgres/metadata.json
mysqlcompose-templates/mysql/mysql.compose.ymltaskfile-templates/mysql/mysql.Taskfile.ymlcompose-templates/mysql/metadata.json
mongodbcompose-templates/mongodb/mongodb.compose.ymltaskfile-templates/mongodb/mongodb.Taskfile.ymlcompose-templates/mongodb/metadata.json
monitoringcompose-templates/monitoring/monitoring.compose.ymltaskfile-templates/monitoring/monitoring.Taskfile.ymlcompose-templates/monitoring/metadata.json
Root Taskfile template:
taskfile-templates/root/Taskfile.yml
以下所有模板路径均相对于
SKILL_RAW_BASE
(定义如下)——在运行时远程获取。目标项目的CWD是独立的——请勿混淆这些路径。
服务Compose模板Taskfile模板元数据
rediscompose-templates/redis/redis.compose.ymltaskfile-templates/redis/redis.Taskfile.ymlcompose-templates/redis/metadata.json
rabbitmqcompose-templates/rabbitmq/rabbitmq.compose.ymltaskfile-templates/rabbitmq/rabbitmq.Taskfile.ymlcompose-templates/rabbitmq/metadata.json
postgrescompose-templates/postgres/postgres.compose.ymltaskfile-templates/postgres/postgres.Taskfile.ymlcompose-templates/postgres/metadata.json
mysqlcompose-templates/mysql/mysql.compose.ymltaskfile-templates/mysql/mysql.Taskfile.ymlcompose-templates/mysql/metadata.json
mongodbcompose-templates/mongodb/mongodb.compose.ymltaskfile-templates/mongodb/mongodb.Taskfile.ymlcompose-templates/mongodb/metadata.json
monitoringcompose-templates/monitoring/monitoring.compose.ymltaskfile-templates/monitoring/monitoring.Taskfile.ymlcompose-templates/monitoring/metadata.json
根Taskfile模板:
taskfile-templates/root/Taskfile.yml

Remote 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
npx skills add
— only SKILL.md is installed locally):
SKILL_RAW_BASE=https://raw.githubusercontent.com/Cyboooooorg/dev-tools/main
Fetch any template with:
bash
curl -fsSL "${SKILL_RAW_BASE}/<template-path>"
If
curl
is unavailable, use
wget -qO- "${SKILL_RAW_BASE}/<template-path>"
.
模板在运行时从技能的源仓库获取。以下所有模板读取操作均使用此基础URL(因此当通过
npx skills add
安装技能时,该技能仍可正常工作——仅SKILL.md会被安装到本地):
SKILL_RAW_BASE=https://raw.githubusercontent.com/Cyboooooorg/dev-tools/main
使用以下命令获取任意模板:
bash
curl -fsSL "${SKILL_RAW_BASE}/<template-path>"
如果
curl
不可用,请使用
wget -qO- "${SKILL_RAW_BASE}/<template-path>"

Template Format Note

模板格式说明

Compose templates already use
${ENV_VAR}
references (e.g.
${REDIS_PORT}
) — they do NOT contain
{{TOKEN}}
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>
Compose模板已使用
${ENV_VAR}
引用(例如
${REDIS_PORT}
)——它们不包含
{{TOKEN}}
占位符。对于标准安装,直接复制模板内容即可。仅在别名/多实例安装时才需要进行字符串替换(重命名环境变量、容器名称、卷名称)。 </context>
<process>

Step 1: Detect Installation State

步骤1:检测安装状态

Determine the service name:
  • If
    $ARGUMENTS
    is not empty,
    SERVICE=$ARGUMENTS
    (normalize to lowercase).
  • If
    $ARGUMENTS
    is empty, skip to Step 3 to ask the user to select a service.
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
    (转换为小写)。
  • 如果
    $ARGUMENTS
    为空,则跳至步骤3,让用户选择服务。
检查该服务是否已安装:
bash
test -f .devtools/${SERVICE}.compose.yml
  • 如果文件不存在 → 继续执行步骤2
  • 如果文件存在 → 进入步骤1a

Step 1a: Merge Detection

步骤1a:合并检测

The service is already installed. Inform the user:
"
${SERVICE}
is already installed in
.devtools/
."
Ask:
"Add another instance with an alias, or cancel? [alias/cancel]"
  • If user answers cancel → output
    "Nothing written. Exiting."
    and stop.
  • If user provides an alias (e.g.
    cache
    ,
    session
    ):
    • Set
      ALIAS=<alias>
      (lowercase, letters/numbers/hyphens only).
    • Set
      SERVICE_SLUG=${SERVICE}-${ALIAS}
      (e.g.
      redis-cache
      ).
    • Set
      SERVICE_SNAKE=${SERVICE}_${ALIAS}
      (e.g.
      redis_cache
      ) — used for YAML service keys, volume keys, network keys.
    • Set
      ENV_PREFIX=<SERVICE_UPPER>_<ALIAS_UPPER>
      (e.g.
      REDIS_CACHE
      ) — used for env var names.
    • Check if alias already installed:
      bash
      test -f .devtools/${SERVICE_SLUG}.compose.yml
    • If file exists → output
      "${SERVICE_SLUG} is already installed — nothing to do."
      and stop. (MERGE-04)
    • If file does not exist → set
      MODE=alias
      and continue to Step 3.
  • No alias set and no existing file → set
    MODE=standard
    and continue to Step 2.
该服务已安装。告知用户:
"
${SERVICE}
已安装在
.devtools/
目录中。"
询问:
"是否使用别名添加另一个实例,还是取消?[alias/cancel]"
  • 如果用户回答cancel → 输出
    "未写入任何内容。正在退出。"
    并停止操作。
  • 如果用户提供别名(例如
    cache
    session
    ):
    • 设置
      ALIAS=<alias>
      (仅允许小写字母/数字/连字符)。
    • 设置
      SERVICE_SLUG=${SERVICE}-${ALIAS}
      (例如
      redis-cache
      )。
    • 设置
      SERVICE_SNAKE=${SERVICE}_${ALIAS}
      (例如
      redis_cache
      )——用于YAML服务键、卷键、网络键。
    • 设置
      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
.devtools/
does not yet exist.
Check:
bash
test -d .devtools
  • If
    .devtools/
    exists → skip to Step 3.
  • If
    .devtools/
    does not exist → proceed:
    1. Announce:
      "Creating .devtools/ directory..."
      .
    2. Create the directory:
      bash
      mkdir -p .devtools
    3. Write
      .devtools/.gitignore
      with exactly this content (do not add any other entries):
      .env
    4. 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>
        .
    5. Continue to Step 3.
    If
    .devtools/.env
    already exists and contains
    COMPOSE_PROJECT_NAME
    , skip the project name question entirely (D-20).
仅当
.devtools/
目录不存在时才执行此步骤。
检查:
bash
test -d .devtools
  • 如果
    .devtools/
    存在 → 跳至步骤3
  • 如果
    .devtools/
    不存在 → 执行以下操作:
    1. 提示:
      "正在创建.devtools/目录..."
    2. 创建目录:
      bash
      mkdir -p .devtools
    3. .devtools/.gitignore
      写入以下内容(请勿添加其他条目):
      .env
    4. 询问:
      "用于Docker命名空间的项目名称?[默认值:从Git远程仓库或当前目录派生]"
      • 派生默认值:运行
        basename $(git remote get-url origin 2>/dev/null || echo $(pwd)) | sed 's/\.git$//'
      • 设置
        COMPOSE_PROJECT_NAME=<用户输入或默认值>
    5. 继续执行步骤3
    如果
    .devtools/.env
    已存在且包含
    COMPOSE_PROJECT_NAME
    ,则完全跳过项目名称问题(D-20)。

Step 3: Service Selection

步骤3:服务选择

If
SERVICE
is already set from
$ARGUMENTS
, skip this step.
Ask the user:
"Which service would you like to add? (redis / rabbitmq / postgres / mysql / mongodb)"
  • Set
    SERVICE=<user answer>
    (normalize to lowercase).
  • If the answer is not one of the five supported services, respond:
    "Service '<answer>' is not supported. Supported: redis, rabbitmq, postgres, mysql, mongodb."
    and stop.
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:
  • parameters[]
    — list of
    { name, default, env_var, token }
    entries
  • ui_companion
    — present or absent
  • exporter
    — present or absent (used later for monitoring)
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
AskUserQuestion
. Show the inline default on every question as
[default: X]
. Accept the user's answer or use the default if they press enter.
使用
AskUserQuestion
逐个提出问题。每个问题都显示内联默认值
[default: X]
。接受用户输入,若用户按回车键则使用默认值。

Universal questions (all services):

通用问题(所有服务):

  1. Port?
    [default: <port from metadata>]
    • Store answer as
      ANSWERS[port]
      .
  2. Image version/tag?
    [default: <version from metadata>]
    • Store answer as
      ANSWERS[version]
      .

  1. 端口?
    [default: <元数据中的端口>]
    • 将答案存储为
      ANSWERS[port]
  2. 镜像版本/标签?
    [default: <元数据中的版本>]
    • 将答案存储为
      ANSWERS[version]

Per-service credential questions:

按服务的凭据问题:

redis

redis

(Port default:
[default: 6379]
)
3.
"Password? [optional — press enter to skip]"
  • If user presses enter →
    ANSWERS[password]=""
    (empty string — Redis runs without auth).
  • Otherwise →
    ANSWERS[password]=<user input>
    .
(默认端口:
[default: 6379]
)
3.
"密码?[可选——按回车键跳过]"
  • 如果用户按回车键 →
    ANSWERS[password]=""
    (空字符串——Redis无认证运行)。
  • 否则 →
    ANSWERS[password]=<用户输入>

rabbitmq

rabbitmq

(Port default:
[default: 5672]
)
3.
"Username? [default: admin]"
ANSWERS[username]
4.
"Password? (required — no default)"
ANSWERS[password]
(must be non-empty; re-ask if blank) 5.
"Management UI port? [default: 15672]"
ANSWERS[ui_port]
(Note: RabbitMQ management UI is always-on — bundled in the rabbitmq:-management image. Step 6 "Enable UI companion?" is SKIPPED for RabbitMQ.)*
(默认端口:
[default: 5672]
)
3.
"用户名?[default: admin]"
ANSWERS[username]
4.
"密码?(必填——无默认值)"
ANSWERS[password]
(必须非空;若为空则重新询问) 5.
"管理UI端口?[default: 15672]"
ANSWERS[ui_port]
(注意:RabbitMQ管理UI始终启用——包含在rabbitmq:-management镜像中。 步骤6“启用UI伴生服务?”对RabbitMQ跳过。)*

postgres

postgres

(Port default:
[default: 5432]
)
3.
"Username? [default: postgres]"
ANSWERS[username]
4.
"Password? (required — no default)"
ANSWERS[password]
(re-ask if blank) 5.
"Database name? [default: app]"
ANSWERS[db_name]
(默认端口:
[default: 5432]
)
3.
"用户名?[default: postgres]"
ANSWERS[username]
4.
"密码?(必填——无默认值)"
ANSWERS[password]
(若为空则重新询问) 5.
"数据库名称?[default: app]"
ANSWERS[db_name]

mysql

mysql

(Port default:
[default: 3306]
)
3.
"Username? [default: app]"
ANSWERS[username]
4.
"Password? (required — no default)"
ANSWERS[password]
(re-ask if blank) 5.
"Database name? [default: app]"
ANSWERS[db_name]
6.
"Root password? (required — no default)"
ANSWERS[root_password]
(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]
)
3.
"用户名?[default: app]"
ANSWERS[username]
4.
"密码?(必填——无默认值)"
ANSWERS[password]
(若为空则重新询问) 5.
"数据库名称?[default: app]"
ANSWERS[db_name]
6.
"Root密码?(必填——无默认值)"
ANSWERS[root_password]
(MYSQL_ROOT_PASSWORD——MariaDB/MySQL要求必填,即使其在metadata.json中token为null) 7. (MariaDB是默认镜像变体。MariaDB 11与MySQL 8兼容。如果用户需要MySQL: 他们可以覆盖版本标签以使用mysql:8。)

mongodb

mongodb

(Port default:
[default: 27017]
)
3.
"Username? [default: admin]"
ANSWERS[username]
4.
"Password? (required — no default)"
ANSWERS[password]
(re-ask if blank)
(默认端口:
[default: 27017]
)
3.
"用户名?[default: admin]"
ANSWERS[username]
4.
"密码?(必填——无默认值)"
ANSWERS[password]
(若为空则重新询问)

Step 6: UI Companion Prompt

步骤6:UI伴生服务提示

Skip this step entirely for
rabbitmq
— its management UI is always-on (handled in Step 5).
For all other services (redis, postgres, mysql, mongodb) that have a
ui_companion
entry in their metadata:
Ask:
"Enable UI companion? [y/N]"
(default: N)
  • If No → set
    ANSWERS[ui_enabled]=false
    and skip to Step 7.
  • If Yes → set
    ANSWERS[ui_enabled]=true
    .
    Ask:
    "Enable auth on UI? [y/N]"
    (default: 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]"
    ANSWERS[pgadmin_email]
    Ask:
    "pgAdmin login password? (required)"
    ANSWERS[pgadmin_password]
    (re-ask if blank)

    mysql (phpMyAdmin — no extra credentials needed beyond service creds)

    (No additional questions — phpMyAdmin connects using MYSQL_USER / MYSQL_PASSWORD.)

    mongodb (Mongo Express auth)

    If
    ANSWERS[ui_auth]=true
    : Ask:
    "Mongo Express username? [default: admin]"
    ANSWERS[me_username]
    Ask:
    "Mongo Express password? (required)"
    ANSWERS[me_password]
    (re-ask if blank)

    redis (RedisInsight — no extra credentials needed)

    (RedisInsight authenticates via the Redis password already captured in Step 5.)
rabbitmq
完全跳过此步骤
——其管理UI始终启用(在步骤5中已处理)。
对于元数据中包含
ui_companion
条目的所有其他服务(redis、postgres、mysql、mongodb):
询问:
"启用UI伴生服务?[y/N]"
(默认值:N)
  • 如果 → 设置
    ANSWERS[ui_enabled]=false
    并跳至步骤7
  • 如果 → 设置
    ANSWERS[ui_enabled]=true
    询问:
    "为UI启用认证?[y/N]"
    (默认值: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:
"Also set up Taskfile tasks? [Y/n]"
(default: Y) →
ANSWERS[taskfile]=<true/false>
Ask:
"Also install monitoring (Grafana + Prometheus)? [y/N]"
(default: N) →
ANSWERS[monitoring]=<true/false>
If
ANSWERS[monitoring]=true
: Ask:
"Grafana admin password? [default: admin]"
ANSWERS[grafana_password]
(Default is intentionally weak — surfaced here so user can change it.)
询问:
"是否同时设置Taskfile任务?[Y/n]"
(默认值:Y)→
ANSWERS[taskfile]=<true/false>
询问:
"是否同时安装监控(Grafana + Prometheus)?[y/N]"
(默认值: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
    "Cancelled. Nothing written."
    and stop.
  • 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 (
MODE=standard
):
Copy the file content verbatim.
Special case — Redis, no password: If
SERVICE=redis
and
ANSWERS[password]
is empty string (user pressed enter to skip), after loading the template content:
  • Remove the
    --requirepass ${REDIS_PASSWORD}
    argument from the
    command:
    line.
  • Remove
    -a "${REDIS_PASSWORD}"
    from the
    healthcheck.test
    command. Write the modified content (not the raw template) to
    .devtools/redis.compose.yml
    .
For alias install (
MODE=alias
):
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.
Write to the target project:
.devtools/<filename>.compose.yml
Where
<filename>
is
${SERVICE}
for standard, or
${SERVICE_SLUG}
for alias (e.g.
redis-cache
).
从技能仓库获取Compose模板:
bash
curl -fsSL "${SKILL_RAW_BASE}/compose-templates/${SERVICE}/${SERVICE}.compose.yml"
对于标准安装(
MODE=standard
):
直接复制文件内容。
特殊情况——Redis无密码: 如果
SERVICE=redis
ANSWERS[password]
为空字符串(用户按回车键跳过),加载模板内容后:
  • command:
    行中移除
    --requirepass ${REDIS_PASSWORD}
    参数。
  • healthcheck.test
    命令中移除
    -a "${REDIS_PASSWORD}"
    。 将修改后的内容(而非原始模板)写入
    .devtools/redis.compose.yml
对于别名安装(
MODE=alias
):
写入前,对文件内容执行所有字符串替换——请参阅步骤12中的完整替换映射。在写入前对内存中的副本应用替换。请勿修改原始模板文件。
写入目标项目:
.devtools/<filename>.compose.yml
其中
<filename>
对于标准安装是
${SERVICE}
,对于别名安装是
${SERVICE_SLUG}
(例如
redis-cache
)。

9b: 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.yml
Where
<filename>
is
${SERVICE}
for standard, or
${SERVICE_SLUG}
for alias.
Note: Always write the per-service file (Step 9) BEFORE updating
compose.yml
(Step 11). This ensures
compose.yml
never references a file that failed to write.
从技能仓库获取按服务划分的Taskfile模板:
bash
curl -fsSL "${SKILL_RAW_BASE}/taskfile-templates/${SERVICE}/${SERVICE}.Taskfile.yml"
对于别名安装: 对内存中的副本执行字符串替换(请参阅步骤12)。
写入目标项目:
.devtools/<filename>.Taskfile.yml
其中
<filename>
对于标准安装是
${SERVICE}
,对于别名安装是
${SERVICE_SLUG}
注意: 始终先写入按服务划分的文件(步骤9),再更新
compose.yml
(步骤11)。 这确保
compose.yml
永远不会引用写入失败的文件。

Step 10: .env Management

步骤10:.env管理

10a: Write .devtools/.env

10a:写入.devtools/.env

Append a section block to
.devtools/.env
(create the file if it does not exist):
undefined
.devtools/.env
追加一个区块(如果文件不存在则创建):
undefined

── <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
.devtools/.env.example
(create if not exists) with dummy/placeholder values only — never real credentials:
undefined
.devtools/.env.example
追加相同的键(如果不存在则创建),但仅使用虚拟/占位符值——绝不使用真实凭据:
undefined

── <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/.env
:
undefined
.devtools/.env
追加:
undefined

── 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
undefined
GRAFANA_ADMIN_USER=admin GRAFANA_ADMIN_PASSWORD=CHANGE_ME
undefined

10d: Monitoring files (if ANSWERS[monitoring]=true)

10d:监控文件(如果ANSWERS[monitoring]=true)

Copy monitoring templates verbatim (no token substitution needed):
  1. Fetch and write the compose template:
    bash
    curl -fsSL "${SKILL_RAW_BASE}/compose-templates/monitoring/monitoring.compose.yml"
    Write fetched content to
    .devtools/monitoring.compose.yml
    in the target project.
  2. If
    ANSWERS[taskfile]=true
    , fetch and write the Taskfile:
    bash
    curl -fsSL "${SKILL_RAW_BASE}/taskfile-templates/monitoring/monitoring.Taskfile.yml"
    Write fetched content to
    .devtools/monitoring.Taskfile.yml
    in the target project.
  3. After writing
    monitoring.compose.yml
    (step 1 above), update
    .devtools/compose.yml
    to add the monitoring include (using the same create-or-append logic as Step 11a):
    yaml
      - ./monitoring.compose.yml
Important: Write
monitoring.compose.yml
before updating
compose.yml
include — same write-order rule as Step 9 (Pitfall 6).
直接复制监控模板(无需令牌替换):
  1. 获取并写入Compose模板:
    bash
    curl -fsSL "${SKILL_RAW_BASE}/compose-templates/monitoring/monitoring.compose.yml"
    将获取的内容写入目标项目的
    .devtools/monitoring.compose.yml
  2. 如果
    ANSWERS[taskfile]=true
    ,获取并写入Taskfile:
    bash
    curl -fsSL "${SKILL_RAW_BASE}/taskfile-templates/monitoring/monitoring.Taskfile.yml"
    将获取的内容写入目标项目的
    .devtools/monitoring.Taskfile.yml
  3. 写入
    monitoring.compose.yml
    后(上述步骤1),更新
    .devtools/compose.yml
    以添加监控包含项(使用与步骤11a相同的创建或追加逻辑):
    yaml
      - ./monitoring.compose.yml
重要提示: 先写入
monitoring.compose.yml
,再更新
compose.yml
包含项—— 与步骤9遵循相同的写入顺序规则(陷阱6)。

Step 11: Root File Management

步骤11:根文件管理

11a: Root Compose File (.devtools/compose.yml)

11a:根Compose文件(.devtools/compose.yml)

Check if
.devtools/compose.yml
exists:
If it does NOT exist (first service install): Create
.devtools/compose.yml
with this content:
yaml
undefined
检查
.devtools/compose.yml
是否存在:
如果不存在(首次安装服务): 创建
.devtools/compose.yml
并写入以下内容:
yaml
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.yml
Do 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
.devtools/Taskfile.yml
exists:
bash
test -f .devtools/Taskfile.yml
If 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.yml
.
If it DOES exist: Do NOT overwrite it. The root Taskfile template already contains
optional: true
for all 6 service includes — missing service files are silently skipped at runtime. No append is needed.
Important: Never overwrite an existing
.devtools/Taskfile.yml
. Users may have customized it. The
optional: true
pattern makes per-install updates unnecessary.
检查
.devtools/Taskfile.yml
是否存在:
bash
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.yml
。用户可能已对其进行自定义。
optional: true
模式使得无需在每次安装时更新该文件。

Step 12: Alias Substitution (alias installs only)

步骤12:别名替换(仅别名安装)

Skip this step entirely for standard installs (
MODE=standard
).
For 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
    =
    ${SERVICE}-${ALIAS}
    (e.g.
    redis-cache
    ) — used in filenames and container names
  • SERVICE_SNAKE
    =
    ${SERVICE}_${ALIAS}
    (e.g.
    redis_cache
    ) — used in YAML keys, volumes, networks
  • ENV_PREFIX
    =
    <SERVICE_UPPER>_<ALIAS_UPPER>
    (e.g.
    REDIS_CACHE
    ) — used in env var names
标准安装(
MODE=standard
)完全跳过此步骤。
对于别名安装,在Compose文件内容(内存中,写入前)和Taskfile内容(内存中,写入前)中执行以下字符串替换。
步骤1a中设置的变量:
  • SERVICE_SLUG
    =
    ${SERVICE}-${ALIAS}
    (例如
    redis-cache
    )——用于文件名和容器名称
  • SERVICE_SNAKE
    =
    ${SERVICE}_${ALIAS}
    (例如
    redis_cache
    )——用于YAML键、卷、网络
  • ENV_PREFIX
    =
    <SERVICE_UPPER>_<ALIAS_UPPER>
    (例如
    REDIS_CACHE
    )——用于环境变量名称

Compose file substitutions

Compose文件替换

WhatOld value (pattern)New value
YAML service key
${SERVICE}:
${SERVICE_SNAKE}:
Container name suffix
-${SERVICE}
-${SERVICE_SLUG}
Volume key declaration
${SERVICE}_data:
${SERVICE_SNAKE}_data:
Volume reference (under volumes:)
${SERVICE}_data
${SERVICE_SNAKE}_data
Network key declaration
${SERVICE}_net:
${SERVICE_SNAKE}_net:
Network reference (under networks:)
${SERVICE}_net
${SERVICE_SNAKE}_net
Env var names in content
${SERVICE_UPPER}_PORT
${ENV_PREFIX}_PORT
Env var names in content
${SERVICE_UPPER}_VERSION
${ENV_PREFIX}_VERSION
Env var names in content
${SERVICE_UPPER}_PASSWORD
${ENV_PREFIX}_PASSWORD
Env var names in content
${SERVICE_UPPER}_USERNAME
${ENV_PREFIX}_USERNAME
Env var names in content
${SERVICE_UPPER}_UI_PORT
${ENV_PREFIX}_UI_PORT
Other service-specific env vars
${SERVICE_UPPER}_*
${ENV_PREFIX}_*
Service key note: YAML service keys must use underscore (
redis_cache:
) — hyphens in Compose service names cause network auto-naming issues. Container names and filenames use hyphen (
redis-cache
) — that is correct and expected.
替换对象旧值(模式)新值
YAML服务键
${SERVICE}:
${SERVICE_SNAKE}:
容器名称后缀
-${SERVICE}
-${SERVICE_SLUG}
卷键声明
${SERVICE}_data:
${SERVICE_SNAKE}_data:
卷引用(在volumes:下)
${SERVICE}_data
${SERVICE_SNAKE}_data
网络键声明
${SERVICE}_net:
${SERVICE_SNAKE}_net:
网络引用(在networks:下)
${SERVICE}_net
${SERVICE_SNAKE}_net
内容中的环境变量名称
${SERVICE_UPPER}_PORT
${ENV_PREFIX}_PORT
内容中的环境变量名称
${SERVICE_UPPER}_VERSION
${ENV_PREFIX}_VERSION
内容中的环境变量名称
${SERVICE_UPPER}_PASSWORD
${ENV_PREFIX}_PASSWORD
内容中的环境变量名称
${SERVICE_UPPER}_USERNAME
${ENV_PREFIX}_USERNAME
内容中的环境变量名称
${SERVICE_UPPER}_UI_PORT
${ENV_PREFIX}_UI_PORT
其他服务特定环境变量
${SERVICE_UPPER}_*
${ENV_PREFIX}_*
服务键注意事项: YAML服务键必须使用下划线(
redis_cache:
)——Compose服务名称中的连字符会导致网络自动命名问题。容器名称和文件名使用连字符(
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:down
If the service was installed with an alias, show the aliased task names:
  Start service:    task redis-cache:up
If any
## REPLACED
conflicts were found in
.devtools/.env
, add a warning:
⚠ 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.
</process>
<success_criteria>
  • Service compose file exists at
    .devtools/<service>.compose.yml
    (or
    <service>-<alias>.compose.yml
    )
  • Service Taskfile exists at
    .devtools/<service>.Taskfile.yml
    (if Taskfile=yes)
  • .devtools/.env
    contains all service env vars with real values
  • .devtools/.env.example
    contains all service env var names with dummy/placeholder values
  • .devtools/.gitignore
    exists and contains
    .env
  • .devtools/compose.yml
    exists and includes the new service's compose file
  • .devtools/Taskfile.yml
    exists (created or pre-existing)
  • task <service>:up
    starts the service successfully
  • 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已将其排除在版本控制外。
</process>
<success_criteria>
  • 服务Compose文件存在于
    .devtools/<service>.compose.yml
    (或
    <service>-<alias>.compose.yml
  • 服务Taskfile存在于
    .devtools/<service>.Taskfile.yml
    (如果Taskfile=yes)
  • .devtools/.env
    包含所有服务环境变量及真实值
  • .devtools/.env.example
    包含所有服务环境变量名称及虚拟/占位符值
  • .devtools/.gitignore
    存在且包含
    .env
  • .devtools/compose.yml
    存在且包含新服务的Compose文件
  • .devtools/Taskfile.yml
    存在(已创建或预先存在)
  • task <service>:up
    可成功启动服务
  • 对同一服务重新运行该技能会询问“别名或取消”(无静默覆盖)
  • 使用相同别名重新运行会提示“已安装——无需执行任何操作” </success_criteria>