Files
development-scripts-3darch/SKILL.md
T

226 lines
12 KiB
Markdown

---
name: development-scripts--3darch
description: >
Create, refactor, review, document, and maintain shell script modules under a repository's
.scripts/ directory — the api/ + lib/ split, the --index.sh / --index-api.sh /
--env-vars-reader.sh / --env-vars-validator.sh bootstrap chain, module and root Taskfile.yml
integration, logging through the shared loggers module, and shared helpers from the base
module. Use when adding a new script module or a new command to an existing one; writing an
api/ wrapper or a lib/ implementation function; adding a CLI flag or a required environment
variable; wiring a module into task; debugging a script that produces no output, cannot find
a function, or unexpectedly loads .env; or reviewing shell module work for naming, sourcing
order, and secret-safety — even when the user only says ".scripts", "Taskfile", "task
runner", "shell module", or names a specific module like loggers or base.
license: Proprietary
metadata:
author: workspace-skills-code-agent
version: "1.0"
spec: agentskills.io/specification
compatibility: Requires bash. Taskfile (task) needed only for task-runner integration. Designed for Cline, Claude Code, GitHub Copilot, OpenAI Codex, and other compatible agent environments
---
# Repository Script Modules
## 3D Architecture Wizzard Project Adoption
This is the primary project-adopted skill for **3D Architecture Wizzard** (`3darch`).
- Central source: https://gitea.lego-cloud.eu/home-v1-skills-code-agent/development-scripts
- Source branch: `test`
- Source commit: `5960d5e74713e6b95a403962f479b2b97cb76286`
- Adopted repository: https://gitea.lego-cloud.eu/corp-v1-3darch-skills-code-agent/development-scripts--3darch
- Application: https://gitea.lego-cloud.eu/corp-v1-3darch/corp-v1-3darch
- Documentation: https://gitea.lego-cloud.eu/corp-v1-3darch/corp-v1-3darch-documentation
- Environment namespace: `CORP_V1_3DARCH_*`
- Global diagram skill: https://gitea.lego-cloud.eu/home-v1-skills-code-agent/drawio-main
- Global glossary skill: https://gitea.lego-cloud.eu/home-v1-skills-code-agent/corp-v1--glossary
- Project automation: none; no scheduler job is authorized.
Project engineering peers:
- `development-branching-strategy--3darch` — https://gitea.lego-cloud.eu/corp-v1-3darch-skills-code-agent/development-branching-strategy--3darch
- `development-gitops-argo-cd--3darch` — https://gitea.lego-cloud.eu/corp-v1-3darch-skills-code-agent/development-gitops-argo-cd--3darch
- `development-monorepo-pnpm--3darch` — https://gitea.lego-cloud.eu/corp-v1-3darch-skills-code-agent/development-monorepo-pnpm--3darch
- `development-scripts--3darch` — https://gitea.lego-cloud.eu/corp-v1-3darch-skills-code-agent/development-scripts--3darch
- `devsecops-ci-cd-gitea--3darch` — https://gitea.lego-cloud.eu/corp-v1-3darch-skills-code-agent/devsecops-ci-cd-gitea--3darch
- `documentation-docusaurus--3darch` — https://gitea.lego-cloud.eu/corp-v1-3darch-skills-code-agent/documentation-docusaurus--3darch
- `template-engine-copier--3darch` — https://gitea.lego-cloud.eu/corp-v1-3darch-skills-code-agent/template-engine-copier--3darch
Work rules for shell automation organised as modules under a repository's `.scripts/`
directory, with a strict public/private split and a fixed sourcing order.
The whole model rests on one idea: **`api/` is what people run, `lib/` is what the code
calls, and a single bootstrap chain guarantees that by the time an implementation function
runs, its environment has been read, validated, and its dependencies sourced.**
## Scope routing
Pick the reference that matches the change; do not load all of them.
| The change touches | Read |
|---|---|
| A reader, validator, implementation function, or `api/` wrapper | `references/module-anatomy.md` |
| The `loggers` or `base` module, or logging that produces no output | `references/shared-modules.md` |
| `.env` files, per-environment layers, or shipping `.scripts/` into a rendered repo | `references/environment-model.md` |
| A module `Taskfile.yml` or the root `Taskfile.yml` | `references/taskfile.md` |
| Creating a module, changing one, or checking work before delivery | `references/workflows.md` |
| Deciding what kind of module something should be | `references/module-patterns.md` |
Copy-ready modules live in `assets/`: `module-example-v1/` is the scaffold for a new module;
`loggers/` and `base/` are working reference implementations.
## 1. Repository model
```text
<target-repository>/
Taskfile.yml # root task runner, includes module Taskfiles
.scripts/
<module>/
api/ # public command wrappers — what users run
lib/ # implementation functions — what the code calls
Taskfile.yml # only when the module is exposed through task
```
Commands always run **from the repository root**, never from inside the module:
```bash
./.scripts/<module>/api/<command>.sh [args]
task <module-alias>:<task-name> -- [args]
```
Every `.` source path in every file is written relative to the repository root
(`. ./.scripts/loggers/lib/--index-api.sh`). This is why running a script from inside its own
directory fails to find its dependencies — that is the convention working as designed, not a
bug to patch with `dirname "$0"`.
## 2. Module anatomy
```text
.scripts/<module>/
api/
<command-name>.sh
lib/
--env-vars-reader.sh # defaults + CLI flag parsing
--env-vars-validator.sh # required-input checks
--index-api.sh # sources dependencies + this module's implementations
--index.sh # full runtime bootstrap
-<command-name>.sh # one implementation function per command
Taskfile.yml # optional
```
| File | Responsibility |
|---|---|
| `api/<command>.sh` | Thin public entrypoint. Sources `lib/--index.sh`, calls one function. |
| `lib/-<command>.sh` | The command implementation function. |
| `lib/--index-api.sh` | Sources upstream module APIs, then this module's implementation files. |
| `lib/--index.sh` | Runtime bootstrap: reader, then validator, then API index. |
| `lib/--env-vars-reader.sh` | Exports defaults and parses CLI arguments into environment variables. |
| `lib/--env-vars-validator.sh` | Validates required variables, failing with an actionable log. |
| `Taskfile.yml` | Maps task names to `api/` scripts, forwarding `{{.CLI_ARGS}}`. |
Not every module has every file — a support-only library like `loggers` has no `api/` and no
`Taskfile.yml`. See `references/module-patterns.md`.
## 3. Standard runtime flow
```text
api/<command>.sh
└── source lib/--index.sh
├── source lib/--env-vars-reader.sh # defaults + CLI flags → env vars
├── source lib/--env-vars-validator.sh # required vars present?
└── source lib/--index-api.sh
├── source dependencies (loggers, base, …)
└── source lib/-<command>.sh # defines the function
└── call _<moduleNamespace>_<commandFunction>
```
**The order is load-bearing.** The reader runs before the validator so the validator has
something to check; both run before the API index so implementation functions see a
fully-prepared environment. Reordering produces failures that look like missing variables.
Arguments reach the reader because sourcing happens with the wrapper's own arguments still in
scope — this is why `api/` wrappers need no argument forwarding of their own.
## 4. Naming conventions
| Kind | Convention | Example |
|---|---|---|
| Module directory | lowercase kebab-case | `module-example-v1`, `repositories-nodejs` |
| Public command | lowercase kebab-case, action-oriented | `initialize-one.sh`, `find-many-by-query.sh` |
| Implementation file | single leading dash | `lib/-initialize-one.sh` |
| Index / lifecycle file | double leading dash | `lib/--index.sh`, `lib/--env-vars-reader.sh` |
| Function | `_<moduleNamespace>_<actionName>` | `_moduleExampleV1_initializeOne` |
| Environment variable | uppercase module prefix | `MODULE_EXAMPLE_V1_OUTPUT_DIR` |
Kebab-case module names convert to camelCase function namespaces:
| Module | Function prefix | Env prefix |
|---|---|---|
| `module-example-v1` | `_moduleExampleV1_` | `MODULE_EXAMPLE_V1_` |
| `repositories-nodejs` | `_repositoriesNodejs_` | `REPOSITORIES_NODEJS_` |
| `operation-utilities` | `_operationUtilities_` | `OPERATION_UTILITIES_` |
The dash count is not decoration — it is how you tell at a glance whether a file defines a
command (`-name.sh`) or wires the module together (`--name.sh`).
## 5. Non-negotiable rules
- **`api/` wrappers stay thin.** Source `lib/--index.sh`, call one function, nothing else. No
implementation, no argument parsing, no validation.
- **CLI flags are parsed only in `--env-vars-reader.sh`.** Never in an implementation file.
- **Every new `lib/-*.sh` gets added to `lib/--index-api.sh`.** Forgetting this is the most
common cause of "command not found" for a function that plainly exists.
- **Readers preserve already-exported values** — `export X="${X:-default}"` — so a caller can
override any setting before invoking the module. A module reader never sources `.env` files
itself; the `base` module owns that. See `references/environment-model.md`.
- **Log through `_loggers_*` helpers, never raw `echo`.** Loggers write to `stderr`, keeping
`stdout` clean for real output.
- **Never log secrets.** Redact tokens, API keys, passwords, and kube config.
- **Quote variable expansions** unless word splitting is intended.
- **`return` non-zero from implementation functions; reserve `exit 1` for validators and
bootstrap.** An `exit` inside a sourced library kills the caller's shell.
## 6. Creating a module
Full walkthrough in `references/workflows.md`. The short path:
1. Copy `assets/module-example-v1/` to `.scripts/<new-module>/`.
2. Replace every `module-example-v1` path, the `MODULE_EXAMPLE_V1_` env prefix, and the
`_moduleExampleV1_` function prefix.
3. Add implementation files as `lib/-<command>.sh` and source them from `lib/--index-api.sh`.
4. Add `api/<command>.sh` wrappers for user-facing commands only.
5. Add a module `Taskfile.yml`, and a root include only if the namespace is stable.
6. Validate (section 7).
## 7. Validation
```bash
# Syntax-check every script in the module
find .scripts/<module> -name '*.sh' -print0 | xargs -0 -n1 bash -n
# Confirm task exposure resolves
task --list
# Run the command itself, from the repository root
./.scripts/<module>/api/<command>.sh --dry-run
```
`bash -n` catches syntax errors but **not** a missing entry in `--index-api.sh` — that only
surfaces at call time. Always run the command once, from the repository root, before
delivering. A dry-run flag is worth adding precisely so this check is cheap.
## 8. Mistakes to avoid
- Putting implementation logic into `api/*.sh`.
- Adding a `lib/-*.sh` file and forgetting to source it from `lib/--index-api.sh`.
- Parsing CLI flags in an implementation function instead of the reader.
- Sourcing `base/lib/--index.sh` from a library function — it reads `.env` and
environment-specific files as a side effect. Use `base/lib/--index-api.sh` when you only
need shared functions.
- Writing source paths relative to the script instead of the repository root.
- Using `exit` inside a sourced implementation function.
- Printing secrets, or documenting their values.
- Adding a root `Taskfile.yml` include for an experimental module.
- Assuming logging works because the code compiles — a logger whose level flags were never
exported is silent and returns 0. See `references/shared-modules.md` §3.