Skip to content
Draft
13 changes: 13 additions & 0 deletions .plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,19 @@
"workflows"
]
},
{
"name": "github-actions",
"source": "./github-actions",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Critical: wrong source path — will break skill loading.

Every other entry in this file uses ./skills/<name> (e.g. ./skills/agent-creator, ./skills/github-pr-review). This entry uses ./github-actions, which resolves to a non-existent .plugin/github-actions/ directory.

Suggested change
"source": "./github-actions",
"source": "./skills/github-actions",

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Respectfully pushing back on this one. The file declares metadata.pluginRoot: "./skills" at the top, and every existing entry uses ./<name> (e.g. ./github, ./github-pr-review, ./gitlab, ./agent-creator). They all resolve to ./skills/<name> via pluginRoot. Changing this entry to ./skills/github-actions would actually break it — it would resolve to ./skills/skills/github-actions, inconsistent with every other plugin in the file.

The current ./github-actions is consistent with the existing convention. Happy to change it if the convention itself is being updated, but a one-off change here would be the outlier.

"description": "Create, debug, and test GitHub Actions workflows and custom actions. Use when building CI/CD pipelines, automating workflows, or troubleshooting GitHub Actions.",
"category": "integration",
"keywords": [
"github-actions",
"workflows",
"ci-cd",
"automation",
"actions"
]
},
{
"name": "github-pr-review",
"source": "./github-pr-review",
Expand Down
189 changes: 189 additions & 0 deletions skills/github-actions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
# GitHub Actions Skill
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Important: missing plugin scaffolding — skill won't load in Claude/Codex environments.

Every skill in this repository ships three additional items alongside and . The skill is the only one missing them.

Compare with any peer skill (, , ):

The and files are symlinks pointing to . They let Claude and Codex discover the skill automatically when the repo is cloned locally.

The should contain:

Without this scaffolding the skill loads fine in the OpenHands marketplace, but is invisible to Claude and Codex environments that rely on those dotfile symlinks for auto-discovery.


A skill focused on **effectiveness** when working with GitHub Actions — monitoring runs, reading logs, and developing actions with confidence rather than guessing.

## Overview
Comment thread
juanmichelini marked this conversation as resolved.

This skill provides guidance for:
- Creating and structuring workflows
- Building custom composite and reusable actions
- Testing actions locally (before burning CI minutes) and in CI
- Debugging failed workflows from real evidence (logs), not assumptions
- Avoiding common pitfalls around permissions, secrets, and fork PRs

## When to Use This Skill

- Creating new GitHub Actions workflows
- Building custom composite or reusable actions
- Debugging workflow failures
- Setting up CI/CD pipelines
- Troubleshooting permission or secret issues
- Testing actions before merging to main

## Cost Awareness

Every workflow run consumes CI minutes (billed minutes on private repos, shared capacity on public ones).
Plan before you push:

- Prefer one targeted commit that exercises the change over multiple speculative pushes
- Use `workflow_dispatch` with inputs to manually trigger only what you need
- Use `paths:` filters and `if:` conditions so jobs only run when relevant
- Run with `act` locally before opening a PR when feasible
- Cancel obsolete runs with `concurrency:` groups (don't pay for runs you've already invalidated)
- Use the smallest matrix that proves the change works; expand only if needed

## Develop With Confidence: The Loop

Don't change → push → hope. Use this loop:

1. **Read** the existing workflow / action carefully. Note triggers, permissions, inputs, env, and secrets.
2. **Reproduce locally** with `act` when possible (see below).
3. **Add visibility** — debug steps that print non-secret inputs, refs, and intermediate state.
4. **Push a single focused commit**, then watch the run live.
5. **Read the full failed-job log** (not just the summary) before editing.
6. **Form a hypothesis from the log**, change the smallest thing that tests it, push, watch again.

## Monitoring Runs With `gh`

```bash
# Watch the most recent run from the current branch in real time
gh run watch

# Watch a specific run
gh run watch <run-id>

# Auto-refresh PR checks until they finish (every 10s)
gh pr checks <pr-number> --watch --interval 10

# List recent runs for the repo / branch
gh run list --branch <branch> --limit 10

# Get the run ID for the latest run on a branch
gh run list --branch <branch> --limit 1 --json databaseId --jq '.[0].databaseId'
```

## Reading Logs (Don't Guess)

```bash
# Full log for a run
gh run view <run-id> --log

# Just the failed steps (much shorter)
gh run view <run-id> --log-failed

# Log for a specific job (useful for matrix builds)
gh run view <run-id> --log --job <job-id>

# List jobs for a run to find the job ID
gh run view <run-id> --json jobs --jq '.jobs[] | {id, name, conclusion}'

# Rerun only the failed jobs (avoid paying to rerun green ones)
gh run rerun <run-id> --failed
```

When a step fails, look for:
- The exact command that exited non-zero (above the `##[error]` line)
- The shell — bash on Linux, `pwsh` on Windows runners — error messages differ
- Values printed by your debug step; compare against what the workflow *thought* it was passing in

## Adding Visibility to Actions

When creating a new action or hitting a tricky bug, add debug steps. Don't leave them in indefinitely — remove or guard them with `if: runner.debug == '1'` once the issue is understood.

```yaml
steps:
# Print non-secret inputs and context at the start
- name: Debug - inputs and context
if: runner.debug == '1' || inputs.debug == 'true'
run: |
echo "Event: ${{ github.event_name }}"
echo "Ref: ${{ github.ref }}"
echo "SHA: ${{ github.sha }}"
echo "Actor: ${{ github.actor }}"
echo "PWD: $(pwd)"
echo "Input.my-param: ${{ inputs.my-param }}"
echo "Files:"
ls -la

# ... your real steps ...

# Verify outcome before the job ends
- name: Debug - verify outputs
if: always() && (runner.debug == '1' || inputs.debug == 'true')
run: |
echo "Generated files:"
ls -la dist/ || true
echo "Last exit code: $?"
```

To enable `runner.debug == '1'` for a single run, re-run the workflow with **"Enable debug logging"** checked, or set the repo secret `ACTIONS_RUNNER_DEBUG=true`.

**Never** echo `${{ secrets.* }}` — GitHub masks them, but encoded forms (base64, hex, JSON-wrapped) can leak through.

## Testing Locally With `act`

`act` ([nektos/act](https://github.com/nektos/act)) runs workflows in Docker locally (Docker must be installed and running). Use it to iterate without burning CI minutes.

```bash
# Run the default push event
act

# Simulate a pull_request event
act pull_request

# Run a specific job
act -j build

# Pass secrets
act -s GITHUB_TOKEN="$GITHUB_TOKEN"

# Use a larger image closer to GitHub's runner
act -P ubuntu-latest=catthehacker/ubuntu:full-latest
```

Caveats: `act` does not perfectly emulate GitHub's runners. Things that may differ: pre-installed tools, `GITHUB_TOKEN` permissions, OIDC, the `secrets.GITHUB_TOKEN` value, and macOS/Windows runners. Treat green-on-`act` as a strong signal, not a guarantee.

## Testing Custom Actions Requires Merge to Main

A repository-local custom action referenced as `uses: ./.github/actions/my-action` works from any branch, but:

- A custom action published as `uses: owner/repo/action@ref` must have the action's files **on `ref`** to be resolvable
- `@main` or `@v1` must already exist when the workflow that consumes it runs
- This is why a brand-new action typically must land on `main` first, then be consumed from feature branches that reference `@main` (or a tag)

If you need to iterate on an action and its consumer together, point `uses:` at a SHA on your branch, or develop the action via the local `./.github/actions/…` path until it's stable.

## Common Pitfalls

1. **Custom action not found from a PR** — the action's ref doesn't exist yet. Merge to `main` (or push a tag), then consume.
2. **`GITHUB_TOKEN` permissions** — defaults can be read-only. Set `permissions:` explicitly at the workflow or job level.
3. **`pull_request` vs `pull_request_target`** — `pull_request` runs in the fork's context (no secrets); `pull_request_target` runs with repo secrets against the base — **dangerous** if you check out PR code and execute it. Don't.
4. **Secrets in fork PRs** — even non-`*_target` workflows hide secrets from forks. Don't design workflows that require secrets to run on community PRs.
5. **New trigger types don't take effect until merged** — a `schedule:` or `workflow_dispatch:` trigger added in a PR only fires after merge; `pull_request`-triggered workflows do run on the PR that introduces them.
6. **Path filters are OR, not AND** — any matching path triggers; you can't require all paths.
7. **Matrix `fail-fast: true`** (default) cancels other matrix legs on first failure — turn off when you need full coverage.
8. **Artifacts** — files don't persist between jobs unless uploaded via `actions/upload-artifact` and downloaded in the consuming job.
9. **`env:` scope** — env at workflow, job, and step levels all exist. Step-level shadows job-level shadows workflow-level. Surprises follow if you forget.
10. **Pin versions** — use `@v4` (or better, a SHA) rather than `@main`. Floating refs break builds when upstream changes.

## Best Practices

1. **Pin action versions** — `@v4` or SHA, not `@main`
2. **Least privilege** — set `permissions:` to the minimum needed
3. **Debug steps when introducing or debugging** — remove or gate them with `runner.debug` afterward
4. **Cache dependencies** — `actions/cache` saves real minutes
5. **Concurrency** — cancel obsolete runs:
```yaml
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
```
6. **Timeouts** — set `timeout-minutes:` on jobs that can hang
7. **Fail loudly** — `set -euo pipefail` in non-trivial bash steps
8. **Document non-obvious triggers/inputs** at the top of the workflow file

## Related

- [GitHub Actions documentation](https://docs.github.com/en/actions)
- [`act` — run actions locally](https://github.com/nektos/act)
- [`gh run` CLI reference](https://cli.github.com/manual/gh_run)
44 changes: 44 additions & 0 deletions skills/github-actions/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
name: github-actions
description: Create, debug, and test GitHub Actions workflows and custom actions. Use when building CI/CD pipelines, automating workflows, or troubleshooting GitHub Actions.
triggers:
- github actions
- github workflow
- actions workflow
- gh actions
- .github/workflows
---

# GitHub Actions Guide

## Critical Rules

**Custom Action Deployment:**
- New custom actions MUST be merged to the main branch before they can be used
- After the initial merge, they should be tested from feature branches

**Debug Steps:**
Add debug steps that print non-secret parameters when:
- Creating a new action, OR
- Troubleshooting a particularly tricky issue

Comment thread
juanmichelini marked this conversation as resolved.
(Not required for every workflow - use when needed)
Comment thread
juanmichelini marked this conversation as resolved.

## Effectiveness Principles

Actions cost CI minutes. Be deliberate, not iterative:

1. **Monitor, don't poll** - use `gh run watch` / `gh pr checks --watch` to follow runs live
2. **Read logs, don't guess** - fetch the failed job's log before changing code
3. **Print actual values** - debug steps reveal the real `inputs`/`github` context, not your assumptions
4. **Test locally first** - `act` runs workflows on your machine and avoids burning CI minutes
5. **Plan the smallest reproduction** - one job, minimal matrix, narrow trigger before scaling up

See [README.md](README.md) for the full debugging workflow, `gh` commands, and YAML debug-step examples.

## Key Gotchas

1. **Secrets unavailable in fork PRs** - `pull_request` has no secrets for forks; `pull_request_target` does but **never check out or execute fork PR code inside it** (RCE with write permissions)
2. **Pin action versions** - Use `@v4` or SHA, not `@main` (prevents breaking changes)
3. **Explicit permissions** - Set `permissions:` block for GITHUB_TOKEN operations
4. **Artifacts for job-to-job data** - Files don't persist between jobs without `upload-artifact`/`download-artifact`
Comment thread
juanmichelini marked this conversation as resolved.