Implement GitOps workflows with ArgoCD and Flux for automated, declarative Kubernetes...
npx skills add andrewneilson/github-actions-skill
Or install specific skill: npx add-skill https://github.com/andrewneilson/github-actions-skill
# Description
Write and modify GitHub Actions workflows and custom actions. Use when working with .github/workflows files, CI/CD pipelines, workflow triggers, jobs, steps, secrets, runners, or creating custom actions. Covers workflow syntax, expressions, contexts, events, and deployment.
# SKILL.md
name: github-actions
description: Write and modify GitHub Actions workflows and custom actions. Use when working with .github/workflows files, CI/CD pipelines, workflow triggers, jobs, steps, secrets, runners, or creating custom actions. Covers workflow syntax, expressions, contexts, events, and deployment.
allowed-tools: Read Edit Write Grep Glob Bash
GitHub Actions Skill
This skill helps write and modify GitHub Actions workflows and custom actions.
Workflow Basics
Workflows are YAML files stored in .github/workflows/. They define automated processes triggered by events.
Minimal Workflow Structure
name: CI # Optional: Display name
on: push # Trigger event(s)
jobs:
build: # Job ID (must be unique)
runs-on: ubuntu-latest # Runner environment
steps:
- uses: actions/checkout@v5 # Use an action
- run: echo "Hello" # Run a command
Triggers (on:)
Common Events
on: push # Any push
on: [push, pull_request] # Multiple events
on:
push:
branches: [main, 'releases/**'] # Branch filter
paths: ['src/**'] # Path filter
pull_request:
types: [opened, synchronize] # Activity types
workflow_dispatch: # Manual trigger
inputs:
environment:
description: 'Deploy target'
required: true
type: choice
options: [dev, staging, prod]
schedule:
- cron: '0 0 * * *' # Daily at midnight UTC
Key Events Reference
| Event | Use Case |
|---|---|
push |
Commits pushed to branches/tags |
pull_request |
PR opened, updated, closed |
pull_request_target |
PR from fork (runs in base context) |
workflow_dispatch |
Manual trigger with inputs |
workflow_call |
Reusable workflow |
schedule |
Cron-based scheduling |
release |
Release published/created |
workflow_run |
After another workflow completes |
Jobs
Job Dependencies and Outputs
jobs:
build:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.value }}
steps:
- id: version
run: echo "value=1.0.0" >> "$GITHUB_OUTPUT"
deploy:
needs: build # Depends on build job
runs-on: ubuntu-latest
steps:
- run: echo "Deploying ${{ needs.build.outputs.version }}"
Job Conditions
jobs:
deploy:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
Matrix Strategy
jobs:
test:
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
node: [18, 20]
exclude:
- os: windows-latest
node: 18
include:
- os: ubuntu-latest
node: 20
coverage: true
runs-on: ${{ matrix.os }}
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
Steps
Using Actions
steps:
- uses: actions/checkout@v5 # Public action (owner/repo@ref)
- uses: actions/checkout@8f4b7f84... # Pin to commit SHA (most secure)
- uses: ./.github/actions/my-action # Local action
- uses: docker://alpine:3.8 # Docker image
Running Commands
steps:
- run: npm install
- run: |
echo "Multi-line"
echo "commands"
shell: bash
working-directory: ./app
Step Conditions
steps:
- run: echo "Always runs"
if: always()
- run: echo "On failure"
if: failure()
- run: echo "Main branch only"
if: github.ref == 'refs/heads/main'
- run: echo "Not cancelled"
if: ${{ !cancelled() }}
Expressions and Contexts
Expression Syntax
Use ${{ expression }} to evaluate expressions. In if: conditions, ${{ }} is optional.
Common Contexts
| Context | Description |
|---|---|
github.* |
Workflow run info (ref, sha, actor, repository) |
env.* |
Environment variables |
vars.* |
Repository/org variables |
secrets.* |
Secrets |
steps.<id>.outputs.* |
Step outputs |
needs.<job>.outputs.* |
Job outputs |
matrix.* |
Matrix values |
runner.* |
Runner info (os, arch) |
Useful Expressions
# Context access
${{ github.event_name }}
${{ github.ref_name }}
${{ github.sha }}
${{ github.actor }}
# Conditionals
${{ github.ref == 'refs/heads/main' }}
${{ contains(github.event.head_commit.message, '[skip ci]') }}
${{ startsWith(github.ref, 'refs/tags/') }}
# Default values
${{ github.head_ref || github.run_id }}
# JSON manipulation
${{ toJSON(github.event) }}
${{ fromJSON(needs.job1.outputs.matrix) }}
Built-in Functions
| Function | Example |
|---|---|
contains(search, item) |
contains(github.event.issue.labels.*.name, 'bug') |
startsWith(str, value) |
startsWith(github.ref, 'refs/tags/') |
endsWith(str, value) |
endsWith(github.repository, '-demo') |
format(str, ...) |
format('Hello {0}', github.actor) |
join(array, sep) |
join(matrix.os, ', ') |
toJSON(value) |
toJSON(steps.test.outputs) |
fromJSON(str) |
fromJSON(needs.setup.outputs.matrix) |
hashFiles(path) |
hashFiles('**/package-lock.json') |
Secrets and Variables
Accessing Secrets
steps:
- run: echo "Token: $TOKEN"
env:
TOKEN: ${{ secrets.MY_TOKEN }}
- uses: some-action@v1
with:
api-key: ${{ secrets.API_KEY }}
Environment Variables
env: # Workflow-level
NODE_ENV: production
jobs:
build:
env: # Job-level
CI: true
steps:
- run: echo $MY_VAR
env: # Step-level
MY_VAR: value
Setting Outputs
steps:
- id: set-output
run: echo "result=success" >> "$GITHUB_OUTPUT"
- run: echo "${{ steps.set-output.outputs.result }}"
Runners
GitHub-Hosted Runners
| Label | OS | CPUs | RAM |
|---|---|---|---|
ubuntu-latest |
Ubuntu 24.04 | 4 (public) / 2 (private) | 16GB / 7GB |
windows-latest |
Windows Server 2025 | 4 / 2 | 16GB / 7GB |
macos-latest |
macOS 15 (arm64) | 3 | 7GB |
Self-Hosted Runners
runs-on: [self-hosted, linux, x64]
Permissions
permissions:
contents: read
pull-requests: write
id-token: write # Required for OIDC
# Or disable all
permissions: {}
Concurrency
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
Artifacts and Caching
Upload/Download Artifacts
- uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/
- uses: actions/download-artifact@v4
with:
name: build-output
Dependency Caching
- uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-
Environments
jobs:
deploy:
environment:
name: production
url: https://example.com
runs-on: ubuntu-latest
OIDC Authentication (AWS)
permissions:
id-token: write
contents: read
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789:role/my-role
aws-region: us-east-1
Reusable Workflows
Calling a Reusable Workflow
jobs:
call-workflow:
uses: owner/repo/.github/workflows/reusable.yml@main
with:
input1: value
secrets:
token: ${{ secrets.TOKEN }}
Creating a Reusable Workflow
on:
workflow_call:
inputs:
environment:
required: true
type: string
secrets:
token:
required: true
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- run: echo "Deploying to ${{ inputs.environment }}"
env:
TOKEN: ${{ secrets.token }}
Common Patterns
Checkout and Setup
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
Conditional on File Changes
on:
push:
paths:
- 'src/**'
- '!src/**/*.md'
Run on Tag Push
on:
push:
tags:
- 'v*'
Troubleshooting
- Workflow not triggering: Check branch/path filters, verify file is in
.github/workflows/ - Permission denied: Add required
permissions:block - Secret not found: Verify secret name matches exactly (case-sensitive)
- Step output empty: Ensure using
>> "$GITHUB_OUTPUT"(not deprecated set-output) - Matrix job failing: Check
exclude/includesyntax and values
References
For detailed information, see:
- references/WORKFLOW-SYNTAX.md - Full workflow syntax reference
- references/EXPRESSIONS.md - Contexts and functions
- references/TRIGGERS.md - Event details and filtering
- references/ACTIONS.md - Creating custom actions
- references/SECURITY.md - Secrets, OIDC, security practices
- references/RUNNERS.md - Runner configuration
- references/PATTERNS.md - AWS deployment and language patterns
# README.md
name: github-actions
description: Write and modify GitHub Actions workflows and custom actions. Use when working with .github/workflows files, CI/CD pipelines, workflow triggers, jobs, steps, secrets, runners, or creating custom actions. Covers workflow syntax, expressions, contexts, events, and deployment.
allowed-tools: Read Edit Write Grep Glob Bash
GitHub Actions Skill
This skill helps write and modify GitHub Actions workflows and custom actions.
Workflow Basics
Workflows are YAML files stored in .github/workflows/. They define automated processes triggered by events.
Minimal Workflow Structure
name: CI # Optional: Display name
on: push # Trigger event(s)
jobs:
build: # Job ID (must be unique)
runs-on: ubuntu-latest # Runner environment
steps:
- uses: actions/checkout@v5 # Use an action
- run: echo "Hello" # Run a command
Triggers (on:)
Common Events
on: push # Any push
on: [push, pull_request] # Multiple events
on:
push:
branches: [main, 'releases/**'] # Branch filter
paths: ['src/**'] # Path filter
pull_request:
types: [opened, synchronize] # Activity types
workflow_dispatch: # Manual trigger
inputs:
environment:
description: 'Deploy target'
required: true
type: choice
options: [dev, staging, prod]
schedule:
- cron: '0 0 * * *' # Daily at midnight UTC
Key Events Reference
| Event | Use Case |
|---|---|
push |
Commits pushed to branches/tags |
pull_request |
PR opened, updated, closed |
pull_request_target |
PR from fork (runs in base context) |
workflow_dispatch |
Manual trigger with inputs |
workflow_call |
Reusable workflow |
schedule |
Cron-based scheduling |
release |
Release published/created |
workflow_run |
After another workflow completes |
Jobs
Job Dependencies and Outputs
jobs:
build:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.value }}
steps:
- id: version
run: echo "value=1.0.0" >> "$GITHUB_OUTPUT"
deploy:
needs: build # Depends on build job
runs-on: ubuntu-latest
steps:
- run: echo "Deploying ${{ needs.build.outputs.version }}"
Job Conditions
jobs:
deploy:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
Matrix Strategy
jobs:
test:
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
node: [18, 20]
exclude:
- os: windows-latest
node: 18
include:
- os: ubuntu-latest
node: 20
coverage: true
runs-on: ${{ matrix.os }}
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
Steps
Using Actions
steps:
- uses: actions/checkout@v5 # Public action (owner/repo@ref)
- uses: actions/checkout@8f4b7f84... # Pin to commit SHA (most secure)
- uses: ./.github/actions/my-action # Local action
- uses: docker://alpine:3.8 # Docker image
Running Commands
steps:
- run: npm install
- run: |
echo "Multi-line"
echo "commands"
shell: bash
working-directory: ./app
Step Conditions
steps:
- run: echo "Always runs"
if: always()
- run: echo "On failure"
if: failure()
- run: echo "Main branch only"
if: github.ref == 'refs/heads/main'
- run: echo "Not cancelled"
if: ${{ !cancelled() }}
Expressions and Contexts
Expression Syntax
Use ${{ expression }} to evaluate expressions. In if: conditions, ${{ }} is optional.
Common Contexts
| Context | Description |
|---|---|
github.* |
Workflow run info (ref, sha, actor, repository) |
env.* |
Environment variables |
vars.* |
Repository/org variables |
secrets.* |
Secrets |
steps.<id>.outputs.* |
Step outputs |
needs.<job>.outputs.* |
Job outputs |
matrix.* |
Matrix values |
runner.* |
Runner info (os, arch) |
Useful Expressions
# Context access
${{ github.event_name }}
${{ github.ref_name }}
${{ github.sha }}
${{ github.actor }}
# Conditionals
${{ github.ref == 'refs/heads/main' }}
${{ contains(github.event.head_commit.message, '[skip ci]') }}
${{ startsWith(github.ref, 'refs/tags/') }}
# Default values
${{ github.head_ref || github.run_id }}
# JSON manipulation
${{ toJSON(github.event) }}
${{ fromJSON(needs.job1.outputs.matrix) }}
Built-in Functions
| Function | Example |
|---|---|
contains(search, item) |
contains(github.event.issue.labels.*.name, 'bug') |
startsWith(str, value) |
startsWith(github.ref, 'refs/tags/') |
endsWith(str, value) |
endsWith(github.repository, '-demo') |
format(str, ...) |
format('Hello {0}', github.actor) |
join(array, sep) |
join(matrix.os, ', ') |
toJSON(value) |
toJSON(steps.test.outputs) |
fromJSON(str) |
fromJSON(needs.setup.outputs.matrix) |
hashFiles(path) |
hashFiles('**/package-lock.json') |
Secrets and Variables
Accessing Secrets
steps:
- run: echo "Token: $TOKEN"
env:
TOKEN: ${{ secrets.MY_TOKEN }}
- uses: some-action@v1
with:
api-key: ${{ secrets.API_KEY }}
Environment Variables
env: # Workflow-level
NODE_ENV: production
jobs:
build:
env: # Job-level
CI: true
steps:
- run: echo $MY_VAR
env: # Step-level
MY_VAR: value
Setting Outputs
steps:
- id: set-output
run: echo "result=success" >> "$GITHUB_OUTPUT"
- run: echo "${{ steps.set-output.outputs.result }}"
Runners
GitHub-Hosted Runners
| Label | OS | CPUs | RAM |
|---|---|---|---|
ubuntu-latest |
Ubuntu 24.04 | 4 (public) / 2 (private) | 16GB / 7GB |
windows-latest |
Windows Server 2025 | 4 / 2 | 16GB / 7GB |
macos-latest |
macOS 15 (arm64) | 3 | 7GB |
Self-Hosted Runners
runs-on: [self-hosted, linux, x64]
Permissions
permissions:
contents: read
pull-requests: write
id-token: write # Required for OIDC
# Or disable all
permissions: {}
Concurrency
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
Artifacts and Caching
Upload/Download Artifacts
- uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/
- uses: actions/download-artifact@v4
with:
name: build-output
Dependency Caching
- uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-
Environments
jobs:
deploy:
environment:
name: production
url: https://example.com
runs-on: ubuntu-latest
OIDC Authentication (AWS)
permissions:
id-token: write
contents: read
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789:role/my-role
aws-region: us-east-1
Reusable Workflows
Calling a Reusable Workflow
jobs:
call-workflow:
uses: owner/repo/.github/workflows/reusable.yml@main
with:
input1: value
secrets:
token: ${{ secrets.TOKEN }}
Creating a Reusable Workflow
on:
workflow_call:
inputs:
environment:
required: true
type: string
secrets:
token:
required: true
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- run: echo "Deploying to ${{ inputs.environment }}"
env:
TOKEN: ${{ secrets.token }}
Common Patterns
Checkout and Setup
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
Conditional on File Changes
on:
push:
paths:
- 'src/**'
- '!src/**/*.md'
Run on Tag Push
on:
push:
tags:
- 'v*'
Troubleshooting
- Workflow not triggering: Check branch/path filters, verify file is in
.github/workflows/ - Permission denied: Add required
permissions:block - Secret not found: Verify secret name matches exactly (case-sensitive)
- Step output empty: Ensure using
>> "$GITHUB_OUTPUT"(not deprecated set-output) - Matrix job failing: Check
exclude/includesyntax and values
References
For detailed information, see:
- references/WORKFLOW-SYNTAX.md - Full workflow syntax reference
- references/EXPRESSIONS.md - Contexts and functions
- references/TRIGGERS.md - Event details and filtering
- references/ACTIONS.md - Creating custom actions
- references/SECURITY.md - Secrets, OIDC, security practices
- references/RUNNERS.md - Runner configuration
- references/PATTERNS.md - AWS deployment and language patterns
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.