Files
oleg-lukasonokandClaude Opus 5 31a5408a6c Add development-scripts agent skill
Ports generic-scripts-module-v1 into a routed skill: module anatomy, shared
loggers/base modules, Taskfile integration, workflows, and pattern decisions.

Fixes a latent defect in the loggers example that silenced all logging in the
module scaffold: loggers/lib/--index-api.sh now sources --env-vars-reader.sh,
and the reader preserves already-exported values so caller overrides still win.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 22:18:55 +03:00

119 lines
4.9 KiB
Markdown

# Workflows
Creating a module, changing an existing one, and the checks to run before delivering either.
---
## 1. Creating a new module
1. **Confirm the module name and namespace** — the kebab-case directory name, the
`_camelCase_` function prefix, and the `UPPER_SNAKE_` environment prefix all derive from it
and must agree.
2. **Inspect nearby modules** for a comparable pattern before designing a new one. Matching an
existing module beats inventing a variant.
3. **Copy the scaffold:**
```bash
cp -R assets/module-example-v1 .scripts/<new-module>
```
4. **Rename throughout** — every `module-example-v1` path, `MODULE_EXAMPLE_V1_`, and
`_moduleExampleV1_`:
```bash
cd .scripts/<new-module>
grep -rl 'module-example-v1\|MODULE_EXAMPLE_V1_\|_moduleExampleV1_' . | while read -r f; do
sed -i '' \
-e 's|module-example-v1|<new-module>|g' \
-e 's|MODULE_EXAMPLE_V1_|<NEW_MODULE>_|g' \
-e 's|_moduleExampleV1_|_<newModule>_|g' "$f"
done
grep -rn 'module-example-v1\|MODULE_EXAMPLE_V1_\|_moduleExampleV1_' . || echo "rename complete"
```
(`sed -i ''` is BSD/macOS; use `sed -i` on GNU.)
5. **Set the defaults and flags** in `lib/--env-vars-reader.sh`, using `${VAR:-default}`.
6. **Set the required-input checks** in `lib/--env-vars-validator.sh`.
7. **Write implementation files** as `lib/-<command>.sh`, one function each.
8. **Source every implementation file** from `lib/--index-api.sh`.
9. **Add `api/<command>.sh` wrappers** for user-facing commands only.
10. **Add a module `Taskfile.yml`**, and a root include only if the namespace is stable —
`references/taskfile.md`.
11. **Make scripts executable** where they will be invoked directly:
`chmod +x .scripts/<new-module>/api/*.sh`.
12. **Validate** — section 3.
13. **Update the repository's script documentation** if it has a memory bank or equivalent.
---
## 2. Changing an existing module
1. **Read `lib/--index.sh` and `lib/--index-api.sh` first.** They show what the module loads
and in what order, which determines where a change can safely go.
2. **Decide which layer the change belongs to:**
| The change is | It belongs in |
|---|---|
| A new user-facing command | `api/` + `lib/-<command>.sh` + `--index-api.sh` |
| New behaviour in an existing command | that command's `lib/-<command>.sh` |
| A new CLI flag or default | `--env-vars-reader.sh` |
| A new required input | `--env-vars-validator.sh` |
| Task-runner exposure | module `Taskfile.yml`, and the root include if public |
3. **Preserve the existing naming and function prefixes.** Consistency inside a module beats
matching a newer convention used elsewhere — mixed prefixes in one module are worse than an
old prefix used uniformly.
4. **Add every new `lib/-*.sh` to `--index-api.sh`** as you create it, not afterwards.
5. **Add `api/` wrappers only for user-facing commands**; internal helpers stay in `lib/`.
6. **Validate** — section 3.
7. **Update the script documentation** when public behaviour changes.
---
## 3. Validation checklist
- [ ] Public commands are under `api/`; reusable implementation is under `lib/`.
- [ ] `api/` wrappers are thin — source `lib/--index.sh`, call one function.
- [ ] `lib/--index.sh` sources reader, validator, API index, in that order.
- [ ] `lib/--index-api.sh` sources every implementation file the wrappers need.
- [ ] New CLI flags are parsed in `--env-vars-reader.sh`, using `${VAR:-default}`.
- [ ] Required variables are validated before use.
- [ ] Logs use `_loggers_*` helpers, and logging actually produces output.
- [ ] No secret values are printed or documented.
- [ ] Implementation functions `return` rather than `exit`.
- [ ] Taskfile entries invoke `./.scripts/<module>/api/<command>.sh {{.CLI_ARGS}}`.
- [ ] A root `Taskfile.yml` include was added only if intended.
- [ ] `bash -n` passes for every changed script.
- [ ] The command was actually run once from the repository root.
- [ ] Script documentation is updated when public behaviour changed.
---
## 4. Validation commands
```bash
# Syntax check every script in the module
find .scripts/<module> -name '*.sh' -print0 | xargs -0 -n1 bash -n
# Every implementation file is wired into the API index.
# Note the `--` before the pattern: implementation basenames start with a dash,
# which grep would otherwise parse as an option flag and report every file.
cd .scripts/<module>
for f in lib/-*.sh; do
case "$f" in lib/--*) continue;; esac
grep -qF -- "$(basename "$f")" lib/--index-api.sh || echo "NOT INDEXED: $f"
done
# Task exposure resolves
task --list-all
# Run it — the only check that proves the wiring works
./.scripts/<module>/api/<command>.sh --dry-run
```
`bash -n` proves a file parses. It does **not** prove a function is reachable, that a flag is
handled, or that logging is bootstrapped — all three fail silently at runtime while every
static check passes. The final run is the one that matters; a `--dry-run` flag exists to make
it cheap and safe.