Files
development-scripts-3darch/references/workflows.md
T
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

4.9 KiB

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:

    cp -R assets/module-example-v1 .scripts/<new-module>
    
  4. Rename throughout — every module-example-v1 path, MODULE_EXAMPLE_V1_, and _moduleExampleV1_:

    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

# 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.