Contributing
June 23, 2026 · View on GitHub
Naming Conventions
Action Directories
Use the <active-verb>-<purpose> pattern:
- ✅
enable-auto-merge-on-pr,setup-go-toolchain,login-to-ghcr - ❌
auto-merge-action,go-setup,ghcr
Inputs and Outputs
Use kebab-case for all action inputs, including secret-backed ones. Workflow inputs can keep their own conventions:
- ✅
app-id,go-version,github-token,app-private-key - ❌
app_id,goVersion,GITHUB_TOKEN,APP_PRIVATE_KEY
Action Structure
Each action directory must contain:
action.yaml— Action metadata withname,description,author: devantler-tech, inputs, and stepsREADME.md— Documentation following the template
README Template
# <Action Name>
<One-line description>
## Inputs
| Name | Description | Required | Default |
|------|-------------|----------|---------|
## Outputs
| Name | Description |
|------|-------------|
## Usage
### <Scenario>
\`\`\`yaml
steps:
- uses: devantler-tech/actions/<action-name>@main
with:
...
\`\`\`
Action Type
Prefer composite actions over JavaScript or Docker actions unless complexity demands otherwise.
Testing
Every action must have a corresponding test workflow at .github/workflows/test-<action-name>.yaml that:
- Triggers on
pull_requestandpushtomain - Uses
step-security/harden-runneras the first step - Checks out with
persist-credentials: false - Verifies the action works as expected
Security
- Run zizmor to scan for GitHub Actions vulnerabilities
- Pin third-party actions to commit SHAs (enforced by
zizmor.yml) - Actions under
actions/*,github/*, anddevantler-tech/*may use tag-based refs - External action pin comment convention. Annotate each third-party SHA pin so a
reader can tell at a glance whether it tracks a tag or a branch:
- Pinned to a release tag →
# v<version>(e.g.# v6.0.2). This is the default; 12/13 third-party pins use it. - Pinned to a branch commit because the upstream publishes no tags or releases
(main-tracked only) →
# <branch> (no upstream releases)(e.g.# main (no upstream releases)). This keeps the comment honest — it names the branch and why there is no version — so a future re-pin to a newer branch commit isn't mistaken for a floating@mainref. The lone such dep today isHomebrew/actions/setup-homebrewinsetup-ksail-cli.
- Pinned to a release tag →
Reliability
A composite step that performs a network pull — a Homebrew tap/install, a registry login, a tool/toolchain download — can fail a required CI check on a transient registry/network flake (a GHCR 5xx, a DNS/TLS blip) rather than on a real defect, blocking unrelated PRs across every consumer repo. Wrap such pulls in the shared bounded-retry helper so infra noise can't masquerade as a failure:
retry() { bash "${GITHUB_ACTION_PATH}/../.scripts/retry.sh" "$@"; }
retry brew install <formula>
.scripts/retry.sh retries with exponential backoff (tunable via
RETRY_MAX_ATTEMPTS, RETRY_BASE_DELAY, RETRY_MAX_DELAY) and exits non-zero
with the command's last status once attempts are exhausted, so a genuine failure
still reds the check. Only wrap the network commands — leave local operations
unwrapped. It is used by setup-ksail-cli (brew tap / brew install), by the
shared .scripts/ensure-gh-skill.sh (the gh release download), and by
setup-agent-skills / update-agent-skills (gh skill install / gh skill update registry pulls) — covering every shell-based network pull in the suite as
part of the reliability pillar
(#247).
Commits
Use semantic commits:
feat:— New action or featurefix:— Bug fixdocs:— Documentation changeschore:— Maintenance tasksci:— CI/CD changes