---
name: monorepo-cicd
description: Syncs CI/CD and infrastructure configuration at the monorepo root (compose files, install scripts, env templates, CI service tables) after one or more components changed. Reads `_docs/_repo-config.yaml` (produced by monorepo-discover) to know which CI artifacts are in play and how they're structured. Touches ONLY CI/infra files — never documentation, component directories, or per-component CI configs. Use when a component added/changed a Dockerfile path, port, env var, image tag format, or runtime dependency.
---

# Monorepo CI/CD

Propagates component changes into the repo-level CI/CD and infrastructure artifacts. Strictly scoped — never edits docs, component internals, or per-component CI configs.

## Scope — explicit

| In scope | Out of scope |
| -------- | ------------ |
| `docker-compose.*.yml` at repo root | Unified docs in `_docs/*.md` → use `monorepo-document` |
| `.env.example` / `.env.template` | Root `README.md` documentation → `monorepo-document` |
| Install scripts (`ci-*.sh`, `setup.sh`, etc.) | Per-component CI configs (`<component>/.woodpecker/*`, `<component>/.github/*`) |
| CI service-registry docs (`ci_steps.md` or similar — the human-readable index of pipelines; in scope only if the config says so under `ci.service_registry_doc`) | Component source code, Dockerfiles, or internal docs |
| Kustomization / Helm manifests at repo root | `_docs/_repo-config.yaml` itself (only `monorepo-discover` and `monorepo-onboard` write it) |

If a component change needs doc updates too, tell the user to also run `monorepo-document`.

**Special case**: `ci.service_registry_doc` (e.g., `ci_steps.md`) is a **CI artifact that happens to be markdown**. It's in this skill's scope, not `monorepo-document`'s, because it describes the pipeline/service topology — not user-facing feature docs.

## Preconditions (hard gates)

1. `_docs/_repo-config.yaml` exists.
2. Top-level `confirmed_by_user: true`.
3. `ci.*` section is populated in config (not empty).
4. Components-in-scope have confirmed CI mappings, OR user explicitly approves inferred ones.

If any gate fails, redirect to `monorepo-discover` or ask for confirmation.

## Mitigations (M1–M7)

- **M1** Separation: this skill only touches CI/infra files; no docs, no component internals.
- **M3** Factual vs. interpretive: image tag format, port numbers, env var names — FACTUAL, read from code. Doc cross-references — out of scope entirely (belongs to `monorepo-document`).
- **M4** Batch questions at checkpoints.
- **M5** Skip over guess: component with no CI mapping → skip and report.
- **M6** Assumptions footer + append to `_repo-config.yaml` `assumptions_log`.
- **M7** Drift detection: verify every file in `ci.orchestration_files`, `ci.install_scripts`, `ci.env_template` exists; stop if not.

## Workflow

### Phase 1: Drift check (M7)

Verify every CI file listed in config exists on disk. Missing file → stop, ask user:
- Run `monorepo-discover` to refresh, OR
- Skip the missing file (recorded in report)

Do NOT recreate missing infra files automatically.

### Phase 2: Determine scope

Ask the user (unless specified):

> Which components changed? (a) list them, (b) auto-detect, (c) skip detection (I'll apply specific changes).

For **auto-detect**, for each component:

```bash
git -C <path> log --oneline -20    # submodule
# or
git log --oneline -20 -- <path>    # monorepo subfolder
```

Flag commits that touch CI-relevant concerns:

- Dockerfile additions, renames, or path changes
- CI pipeline files (`<component>/.woodpecker/*`, `<component>/.github/workflows/*`, etc.)
- New exposed ports
- New environment variables consumed by the component
- Changes to image name / tag format
- New dependency on another service (e.g., new DB, new broker)

Present the flagged list; confirm.

### Phase 3: Classify changes per component

| Change type | Target CI files |
| ----------- | --------------- |
| Dockerfile path moved/renamed | `ci.service_registry_doc` service table; per-component CI is OUT OF SCOPE (tell user to update it) |
| New port exposed | `ci.service_registry_doc` ports section (if infra port); component's service block in orchestration file |
| Registry URL changed | `ci.install_scripts` (all of them); `ci.env_template`; `ci.service_registry_doc` |
| Branch naming convention changed | All `ci.install_scripts`; all `ci.orchestration_files` referencing the branch; `ci.service_registry_doc` |
| New runtime env var | `ci.env_template`; component's service block in orchestration file |
| New infrastructure component (DB, cache, broker) | Relevant `ci.orchestration_files`; `ci.service_registry_doc` architecture section |
| New image tag format | All `ci.orchestration_files`; `ci.install_scripts`; `ci.service_registry_doc` |
| Watchtower/polling config change | Specific `ci.orchestration_files`; `ci.service_registry_doc` |

If a change type isn't covered here or in the config, add to an unresolved list and skip (M5).

### Phase 4: Apply edits

For each (change → target file) pair:

1. Read the target file.
2. Locate the service block / table row / section.
3. Edit carefully:
   - **Orchestration files (compose/kustomize/helm)**: YAML; preserve indentation, anchors, and references exactly. Match existing service-block structure. Never reformat unchanged lines.
   - **Install scripts (`*.sh`)**: shell; any edit must remain **idempotent**. Re-running the script on an already-configured host must not break it. If an edit cannot be made idempotent, flag for the user and skip.
   - **`.env.example`**: append new vars at the appropriate section; never remove user's local customizations (file is in git, so comments may be significant).
   - **`ci.service_registry_doc`** (markdown): preserve column widths, ordering (alphabetical or compose-order — whichever existed), ASCII diagrams.

### Phase 5: Skip-and-report (M5)

Skip a component if:

- No `ci_config` in its config entry AND no entry in config's CI mappings
- `confirmed: false` on its mapping and user didn't approve
- Component's Dockerfile path declared in config doesn't exist on disk — surface contradiction
- Change type unrecognized — skip, report for manual handling

### Phase 6: Idempotency / lint check

- Shell: if `shellcheck` available, run on any edited `*.sh`.
- YAML: if `yamllint` or `prettier` available, run on edited `*.yml` / `*.yaml`.
- For edited install scripts, **mentally re-run** the logic: would a second invocation crash, duplicate, or corrupt? Flag anything that might.

Skip linters silently if none configured — don't install tools.

### Phase 7: Report + assumptions footer (M6)

```
monorepo-cicd run complete.

CI files updated (N):
  - docker-compose.run.yml — added `loader` service block
  - .env.example — added LOADER_BUCKET_NAME placeholder
  - ci_steps.md — added `loader` row in service table

Skipped (K):
  - satellite-provider: no ci_config in repo-config.yaml
  - detections: Dockerfile path in config (admin/src/Dockerfile) does not exist on disk

Manual actions needed (M):
  - Update `<submodule>/.woodpecker/*.yml` inside the submodule's own workspace
    (per-component CI is not maintained by this skill)

Assumptions used this run:
  - image tag format: ${REGISTRY}/${NAME}:${BRANCH}-${ARCH_TAG} (confirmed in config)
  - target branch for triggers: [stage, main] (confirmed in config)

Next step: review the diff, then commit with
`<commit_prefix> Sync CI after <components>` (or your own message).
```

Append run entry to `_docs/_repo-config.yaml` `assumptions_log:`.

## What this skill will NEVER do

- Modify files inside component directories
- Edit unified docs under `docs.root`
- Edit per-component CI configs (`.woodpecker/*`, `.github/*`, etc.)
- Auto-generate CI pipeline YAML for components (only provide template guidance)
- Set `confirmed_by_user` or `confirmed:` flags
- Auto-commit
- Install tools (shellcheck, yamllint, etc.) — use if present, skip if absent

## Edge cases

- **Compose file has service blocks for components NOT in config**: note in report; ask user whether to rediscover (`monorepo-discover`) or leave them alone.
- **`.env.example` has entries for removed components**: don't auto-remove; flag to user.
- **Install script edit cannot be made idempotent**: don't save; ask user to handle manually.
- **Branch trigger vs. runtime branch mismatch**: if config says triggers are `[stage, main]` but a compose file references a branch tag `develop`, stop and ask.
