Guidance for Claude Code in this repository.
Reusable GitHub Actions for Gforce-Innovation-Kft: TypeScript actions (strict,
class-based singleton architecture, single shared source tree), composite actions,
and callable workflows for Salesforce CI/CD pipelines.
Per-asset reference (inputs/outputs/permissions + per-asset traps for every action
and workflow): docs/claude-actions-reference.md —
read the entry for any asset before changing it. The action.yml / workflow file
is the contract; the reference carries the rationale the YAML cannot.
Recorded in ADR 0002. Two rules:
- Actions are
<domain>-<object>-<verb>, domain ∈sf·aws·github·git. Sosf-package-create,aws-secret-get. Never verb-first. - Workflows with
workflow_callarereusable-<domain>-<name>.yml; unprefixed workflows are this repo's own CI. (GitHub forbids subdirectories under.github/workflows/, so the name is the only separator.)
Single branch: main. develop was merged and deleted on 2026-08-06 — nothing in
this repo may reference @develop.
Everything here is consumed by other repositories — a change is never local.
docs/usage-catalog.md lists every known consumer of every
asset (repo, file, pinned ref); machine-readable twin in docs/usage-catalog.json.
Required before renaming/removing an input, output, or file, and before changing a default:
- Read the catalog entry for the asset. Note each consumer's pinned ref —
@mainbreaks on merge;@v1/@v2is insulated until that tag moves. - Zero consumers shown → confirm with the human (the scan sees default branches in this org only).
- Regenerate after renames/new consumers:
./.github/scripts/build-usage-catalog.sh(needsgh+jq); CI refreshes weekly. Regenerate onmainright after a rename. - A changed default is a breaking change when the old behaviour was load-bearing
(e.g.
container-user: root → 1001waits on sf-docker-images v3.0.0).
- Actions:
Gforce-Innovation-Kft/shared-github-actions/.github/actions/<name>@v2 - Workflows:
Gforce-Innovation-Kft/shared-github-actions/.github/workflows/reusable-<name>.yml@v2 v2carries the ADR 0002 names;v1is frozen pre-rename — anything added since 404s at@v1. Re-point consumers to@v2when they migrate.- Self-references inside reusable workflows must be absolute (a
./ref resolves against the CALLER's repo). All are pinned to floating@v2; moving them to@vX+1is a release step (ADR 0002, decision 6) — never point them at a branch.
System map:
docs/pipeline-map.md(mermaid — editing the diagrams is how to specify a change). Code layering inside a TypeScript action is a separate thing:docs/architecture.md.
| Layer | Lives in | Contract |
|---|---|---|
| L1 | .github/actions/<name>/ |
One SF/CLI operation. No routing, no context. |
| L2 | reusable-sf-*.yml (workflow_call) |
Composes L1 into a business pipeline. Typed inputs/outputs, explicit secrets:. |
| L3 | reusable-sf-ops-dispatch.yml |
Single external entry point for Salesforce. Validates, routes to one path, reports back. |
| L4 | consumer repos | Thin uses: callers. Not here. |
Rules: L1 never calls L1 (routing belongs in L2/L3); L3 inlines no Salesforce logic;
no pass-through layers; nesting caps at 4 and L4→L3→L2→action spends three. Composite
actions have no secrets context — secrets arrive as inputs.
All implementation lives in gforce-gha-src/ — the only .ts outside it is each
action's entry point (.github/actions/<name>/index.ts: getInput → Orchestrator.execute
→ setOutput, zero logic, committed esbuild dist/index.js).
Layout: actions/<name> (Orchestrator + Validator singletons) · clients/github
(sub-clients + GitHubClient facade, one thin wrapper per endpoint) · services
(business workflows + sanctioned runner-API wrappers) · libraries/salesforce
(ApexTestSelectionService, selectors, package.xml parsing) · {types,utils,__tests__}.
Every class is a singleton (getInstance/resetInstance); one shared Octokit; services
only touch the facade. Errors are throw-based, caught in the entry; expected outcomes are
typed values. Tests: method_scenario_expectedResult, Given/When/Then, mock at the
singleton boundary, 95% coverage gate.
Adding an action: docs/typescript-action-authoring.md; rationale in
docs/architecture.md. Before any PR: npm run all (format + lint + typecheck +
bundle + test + dist:verify) must pass.
- Reusable workflows:
workflow_callwith typed inputs/outputs. Composite actions:.github/actions/<name>/action.yml,using: "composite", every shell stepshell: bash. - Commit prefixes:
Add:Fix:Update:Docs:Test:Refactor:. - Clean up credentials in an
if: always()step. - Third-party actions pin to the floating major tag (
actions/checkout@v7) — never@main, never mixed styles. Security-critical or unknown publishers: pin the SHA and say why in a comment. - Dependabot
directories:must list every action directory containing auses:(today:aws-secret-get,sf-org-login) — a new composite with a third-partyuses:must be added or it goes unwatched.
ci-sf-ops-dispatch-smoke.ymlmust grant the widest permissions any dispatcher job requests (contents: write) even for dry runs — GitHub validates the whole call graph up front, and astartup_failureproduces NO check run (looks like passing).catalog-refresh.yml: the catalog is generated — never hand-edit.release.yml: a major bump is two steps — rewrite self-references to@vX+1first, then tag (CONTRIBUTING.md).
Eight repo-scoped skills are committed. They live in .agents/skills/, are symlinked
into .claude/skills/, and are pinned by content hash in
skills-lock.json. All are vendored from upstream — do not
hand-edit a vendored SKILL.md; the next update overwrites it and the hash stops
matching.
npx skills checkis not read-only — despite the name it fetches upstream and rewrites theSKILL.mdfiles andskills-lock.jsonin place, so it dirties the working tree. Run it deliberately, on its own branch, and review the diff and the changed hashes as a real content change; never run it mid-PR expecting a report.
Invoke the relevant one when the task matches:
| Skill | Upstream | Use when |
|---|---|---|
github-actions-docs |
xixu-me/skills | Authoring or editing a workflow / action.yml — keeps YAML aligned with current GitHub Actions syntax (composite, reusable, TypeScript action patterns). The default for most work in this repo. |
github-actions-templates |
wshobson/agents | Scaffolding a new workflow from a known-good shape, rather than editing an existing one. |
code-review |
mattpocock/skills | Reviewing the TypeScript under gforce-gha-src/ for quality and correctness. |
requesting-code-review |
obra/superpowers | Preparing a change for review, before opening the PR. |
receiving-code-review |
obra/superpowers | Responding to review feedback on a PR. |
dx-org-manage |
forcedotcom/sf-skills | Running scratch-org or snapshot operations against a real org by hand — reproducing what sf-org-scratch-create and the validate job do, when debugging why they fail. |
dx-org-permission-set-assign |
forcedotcom/sf-skills | Assigning permission sets to org users — the step reusable-sf-pr-validate performs inside its scratch org. |
dx-pkg-post-install-configure |
forcedotcom/sf-skills | Post-install configuration of a managed package — what a consumer does after sf-package-install lands a version. |
The three dx-* skills execute SF CLI operations against a live org. They are here
because this repo's composite actions wrap those same commands, so the skills are how
you reproduce a failing pipeline step interactively. They are not a way to change
pipeline behaviour: an action's behaviour lives in its action.yml.
Global tooling available in every session: lean-ctx (prefer ctx_* MCP tools for reads/search/shell — token-compressed), superpowers process skills, and graphify (no graph built for this repo).