11 KiB
name, description
| name | description |
|---|---|
| monorepo-onboard | 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)
_docs/_repo-config.yamlexists.- Top-level
confirmed_by_user: true. - The component is NOT already in
components:— if it is, redirect tomonorepo-documentormonorepo-cicd(it's an update, not an onboarding).
Mitigations (M1–M7)
- M1 Separation: this skill does not invoke
monorepo-discoverautomatically. If_repo-config.yamlneeds 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_logappend. - 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:
- Verify
repo.component_registryexists on disk. - Verify
docs.rootexists. - If
doc_placement= extend existing doc, verify that doc exists. - Verify every file in
ci.orchestration_filesandci.env_templateexists. - Verify
ci.service_registry_docexists (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):
- Insert a new row following existing ordering (alphabetical or deployment-order — match what's there).
- 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:
- Read the target file.
- Add a new H2 section at the appropriate position. If ambiguous (the file has multiple possible sections), ask.
- Update file's internal TOC if present.
- Update
docs.indexONLY if that index has a cross-reference table that includes sub-sections (check the file).
If creating a new doc file:
-
Determine the filename via
docs.file_conventionanddocs.next_unused_prefix(e.g.,13_satellite_provider.md). -
Create using this template:
# <Component Name> ## Overview <expanded purpose from user input> ## API <endpoints or "None"> ## Data model <if applicable, else "None"> ## Configuration <env vars from user input> -
Update
docs.index(_docs/README.mdor 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
-
After creating, update
docs.next_unused_prefixin_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_onnon-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. Useci.image_tag_formatfor the image string. Includedepends_on,ports,environment,volumesbased 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::
- 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::
- 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: truein config - Touch a file outside the explicit scope
Rollback (pre-commit)
Before the user commits, revert is straightforward:
git checkout -- <every file listed in the report>
For the new doc file, remove it explicitly:
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-discoverto 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_prefixcollides with an existing file (race condition): bump and retry once; if still colliding, stop.- No
docs.rootin config: cannot place a doc. Ask user to runmonorepo-discoveror manually set it in the config first.