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>
2.8 KiB
Module Patterns
A decision guide for what kind of module you are building and how it should connect to the others.
1. Module type
| Module type | Has api/ |
Has Taskfile.yml |
Example |
|---|---|---|---|
| Support-only library | No | No | loggers |
| Shared foundation with public commands | Yes | Optional / no | base |
| Feature module | Yes | Usually yes | kube, github, data-migration |
| Wrapper around an external CLI | Yes | Usually yes | helm, openshift, github |
Pick the type before creating any file — it decides whether api/ and Taskfile.yml exist at
all, and adding them later means reworking every consumer that has already started sourcing
the module.
A module with no user-facing command is a support library. Do not give it an api/ directory
speculatively; every file in api/ is a public interface someone may come to depend on.
2. Dependency sourcing
| You need | Source |
|---|---|
| Logging | ./.scripts/loggers/lib/--index-api.sh |
| Shared base functions | ./.scripts/base/lib/--index-api.sh |
| Another module's exported functions | that module's lib/--index-api.sh |
Your own module's full runtime, from its api/ wrapper |
your lib/--index.sh |
The rule underneath: --index-api.sh is the public edge between modules; --index.sh is a
module's own private entrypoint. Sourcing another module's --index.sh runs its reader and
validator inside your command — importing its defaults, its required-input checks, and in
base's case its .env loading. Symptoms show up as variables nobody set, or a validation
failure naming a module the user never invoked.
3. Command exposure
Three independent decisions, in increasing order of commitment:
lib/only — internal. Reachable from other modules that source your--index-api.sh.api/<command>.sh— user-facing. Someone can run it directly from the repository root.- Module
Taskfile.yml— discoverable throughtask --list-all. - Root
Taskfile.ymlinclude — a stable public namespace, effectively permanent.
Escalate only as far as the command genuinely needs. Each step is easy to add later and disruptive to withdraw, because each one is a promise someone may already be relying on.
4. Common mistakes
- Putting full implementation logic into
api/*.sh. - Adding a
lib/-*.shfile and forgetting to source it fromlib/--index-api.sh. - Parsing CLI flags in implementation files instead of
--env-vars-reader.sh. - Printing secrets in logs.
- Sourcing
base/lib/--index.shfrom a library function and unexpectedly loading.env. - Adding root Taskfile includes for experimental modules.
- Giving a support-only library an
api/directory it does not need. - Mixing function prefixes inside one module after a rename.