---
name: monorepo-onboard
description: Adds a new component (submodule / package / workspace member) to a monorepo as a single atomic operation. Updates the component registry (`.gitmodules` / `package.json` workspaces / `Cargo.toml` / etc.), places or extends unified docs, updates CI/compose/env artifacts, and appends an entry to `_docs/_repo-config.yaml`. Intentionally monolithic — onboarding is one user intent that spans multiple artifact domains. Use when the user says "onboard X", "add service Y to the monorepo", "register new repo".
---

# Monorepo Onboard

Onboards a new component atomically. Spans registry + docs + CI + env + config in one coordinated run — because onboarding is a single user intent, and splitting it across multiple skills would fragment the user experience, cause duplicate input collection, and create inconsistent intermediate states in the config file.

## Why this skill is monolithic

Onboarding ONE component requires updating ~8 artifacts. If the user had to invoke `monorepo-document`, `monorepo-cicd`, and a registry skill separately, they would answer overlapping questions 2–3 times, and the config file would pass through invalid states between runs. Monolithic preserves atomicity and consistency.

Sync operations (after onboarding is done) ARE split by artifact — see `monorepo-document` and `monorepo-cicd`.

## Preconditions (hard gates)

1. `_docs/_repo-config.yaml` exists.
2. Top-level `confirmed_by_user: true`.
3. The component is NOT already in `components:` — if it is, redirect to `monorepo-document` or `monorepo-cicd` (it's an update, not an onboarding).

## Mitigations (M1–M7)

- **M1** Separation: this skill does not invoke `monorepo-discover` automatically. If `_repo-config.yaml` needs regeneration first, tell the user.
- **M3** Factual vs. interpretive vs. conventional: all user inputs below are CONVENTIONAL (project choices) — always ASK, never infer.
- **M4** Batch inputs in one question round.
- **M5** Skip over guess: if the user's answer doesn't match enumerable options in config (e.g., unknown deployment tier), stop and ask whether to extend config or adjust answer.
- **M6** Assumptions footer + config `assumptions_log` append.
- **M7** Drift detection: before writing anything, verify every artifact path that will be touched exists (or will be created) — stop on unexpected conditions.

## Required inputs (batch-ask, M4)

Collect ALL of these upfront. If any missing, stop and ask. Offer choices from config when the input has a constrained domain (e.g., `conventions.deployment_tiers`).

| Input | Example | Enumerable? |
| ----- | ------- | ----------- |
| `name` | `satellite-provider` | No — open-ended, follow `conventions.component_naming` |
| `location` | git URL / path | No |
| `stack` | `.NET 10`, `Python 3.12` | No — open-ended |
| `purpose` (one line) | "Fetches satellite imagery" | No |
| `doc_placement` | "extend `_docs/07_admin.md`" OR "new `_docs/NN_satellite.md`" | Yes — offer options based on `docs.*` |
| `ci_required` | Which pipelines (or "none") | Yes — infer from `ci.tooling` |
| `deployment_tier` | `edge` | Yes — `conventions.deployment_tiers` |
| `ports` | "5010/http" or "none" | No |
| `depends_on` | Other components called | Yes — list from `components:` names |
| `env_vars` | Name + placeholder value | No (never real secrets) |

If the user provides an answer outside the enumerable set (e.g., deployment tier not in config), **stop** and ask whether to extend the config or pick from the existing set (M5).

## Workflow

### Phase 1: Drift check (M7)

Before writing:

1. Verify `repo.component_registry` exists on disk.
2. Verify `docs.root` exists.
3. If `doc_placement` = extend existing doc, verify that doc exists.
4. Verify every file in `ci.orchestration_files` and `ci.env_template` exists.
5. Verify `ci.service_registry_doc` exists (if set).

Any missing → stop, ask whether to run `monorepo-discover` first or proceed skipping that artifact.

### Phase 2: Register in component registry

Based on `repo.type`:

| Registry | Action |
| -------- | ------ |
| `git-submodules` | Append `[submodule "<name>"]` stanza to `.gitmodules`. Preserve existing indentation style exactly. |
| `npm-workspaces` | Add path to `workspaces` array in `package.json`. Preserve JSON formatting. |
| `pnpm-workspace` | Add to `packages:` in `pnpm-workspace.yaml`. |
| `cargo-workspace` | Add to `members:` in `Cargo.toml`. |
| `go-workspace` | Add to `use (...)` block in `go.work`. |
| `adhoc` | Update the registry file that config points to. |

**Do NOT run** `git submodule add`, `npm install`, or equivalent commands. Produce the text diff; the user runs the actual registration command after review.

### Phase 3: Root README update

If the root README contains a component/services table (check `repo.root_readme`):

1. Insert a new row following existing ordering (alphabetical or deployment-order — match what's there).
2. Match column widths and punctuation exactly.

If there's an ASCII architecture diagram and `deployment_tier` implies new runtime presence, **ask** the user where to place the new box — don't invent a position.

### Phase 4: Unified docs placement

**If extending an existing doc**:

1. Read the target file.
2. Add a new H2 section at the appropriate position. If ambiguous (the file has multiple possible sections), ask.
3. Update file's internal TOC if present.
4. Update `docs.index` ONLY if that index has a cross-reference table that includes sub-sections (check the file).

**If creating a new doc file**:

1. Determine the filename via `docs.file_convention` and `docs.next_unused_prefix` (e.g., `13_satellite_provider.md`).
2. Create using this template:
   ```markdown
   # <Component Name>

   ## Overview
   <expanded purpose from user input>

   ## API
   <endpoints or "None">

   ## Data model
   <if applicable, else "None">

   ## Configuration
   <env vars from user input>
   ```
3. Update `docs.index` (`_docs/README.md` or equivalent):
   - Add row to docs table, matching existing format
   - If the component introduces a permission AND the index has a permission → feature matrix, update that too

4. After creating, update `docs.next_unused_prefix` in `_docs/_repo-config.yaml`.

### Phase 5: Cross-cutting docs

For each `docs.cross_cutting` entry whose `owns:` matches a fact provided by the user, update that doc:

- `depends_on` non-empty → architecture/communication doc
- New schema/tables → schema doc (ask user for schema details if not provided)
- New permission/role → permissions doc

If a cross-cutting concern is implied by inputs but has no owner in config → add to `unresolved:` in config and ask.

### Phase 6: CI/CD integration

Update:

- **`ci.service_registry_doc`**: add new row to the service table in that file (if set). Match existing format.
- **Orchestration files** (`ci.orchestration_files`): add service block if component is a runtime service. Use `ci.image_tag_format` for the image string. Include `depends_on`, `ports`, `environment`, `volumes` based on user inputs and existing service-block structure.
- **`ci.env_template`**: append new env vars with placeholder values. NEVER real secrets.

### Phase 7: Per-component CI — guidance ONLY

For `<component>/.woodpecker/*.yml`, `<component>/.github/workflows/*`, etc.:

**Do NOT create these files.** They live inside the component's own repo/workspace.

Instead, output the `ci.pipeline_template` (from config) customized for this component, so the user can copy it into the component's workspace themselves.

### Phase 8: Update `_docs/_repo-config.yaml`

Append new entry to `components:`:

```yaml
  - name: <name>
    path: <path>/
    stack: <stack>
    confirmed: true            # user explicitly onboarded = confirmed
    evidence: [user_onboarded]
    primary_doc: <new doc path>
    secondary_docs: [...]
    ci_config: <component>/.<ci_tool>/  # expected location
    deployment_tier: <tier>
    ports: [...]
    depends_on: [...]
    env_vars: [...]
```

If `docs.next_unused_prefix` was consumed, increment it.

Append to `assumptions_log:`:

```yaml
  - date: <date>
    skill: monorepo-onboard
    run_notes: "Onboarded <name>"
    assumptions:
      - "<list>"
```

Do NOT change `confirmed_by_user` — only human sets that.

### Phase 9: Verification report (M6 footer)

```
monorepo-onboard run complete — onboarded `<name>`.

Files modified (N):
  - .gitmodules — added submodule entry
  - README.md — added row in Services table
  - _docs/NN_<name>.md — created
  - _docs/README.md — added index row + permission-matrix row
  - _docs/00_top_level_architecture.md — added to Communication section
  - docker-compose.run.yml — added service block
  - .env.example — added <NAME>_API_KEY placeholder
  - ci_steps.md — added service-table row
  - _docs/_repo-config.yaml — recorded component + updated next_unused_prefix

Files NOT modified but the user must handle:
  - <component>/.woodpecker/build-*.yml — create inside the component's own workspace
    (template below)
  - CI system UI — activate the new repo

Next manual actions:
  1. Actually add the component: `git submodule add <url> <path>` (or equivalent)
  2. Create per-component CI config using the template
  3. Activate the repo in your CI system
  4. Review the full diff, then commit with `<commit_prefix> Onboard <name>`

Pipeline template for <name>:
<rendered ci.pipeline_template with <service> replaced>

Assumptions used this run:
  - Doc filename convention: <from config>
  - Image tag format: <from config>
  - Alphabetical ordering in Services table (observed)
```

## What this skill will NEVER do

- Run `git submodule add`, `npm install`, or any network/install-touching command
- Create per-component CI configs inside component directories
- Invent env vars, ports, permissions, or ticket IDs — all from user
- Auto-commit
- Reorder existing table rows beyond inserting the new one
- Set `confirmed_by_user: true` in config
- Touch a file outside the explicit scope

## Rollback (pre-commit)

Before the user commits, revert is straightforward:

```bash
git checkout -- <every file listed in the report>
```

For the new doc file, remove it explicitly:

```bash
rm _docs/NN_<name>.md
```

The component itself (if already registered via `git submodule add` or workspace install) requires manual cleanup — outside this skill's scope.

## Edge cases

- **Component already in config** (not registry) or vice versa → state mismatch. Redirect to `monorepo-discover` to reconcile.
- **User input contradicts config convention** (e.g., new deployment tier not in `conventions.deployment_tiers`): stop, ask — extend config, or choose from existing.
- **`docs.next_unused_prefix` collides with an existing file** (race condition): bump and retry once; if still colliding, stop.
- **No `docs.root` in config**: cannot place a doc. Ask user to run `monorepo-discover` or manually set it in the config first.
