Use when designing event routing, preventing cascades, composing workflows, or choosing between label-based vs dispatch-based triggers for GitHub agent workflows.
From awfulnpx claudepluginhub xiaolai/awful-for-claude --plugin awfulThis skill uses the workspace's default tool permissions.
Executes pre-written implementation plans: critically reviews, follows bite-sized steps exactly, runs verifications, tracks progress with checkpoints, uses git worktrees, stops on blockers.
Guides idea refinement into designs: explores context, asks questions one-by-one, proposes approaches, presents sections for approval, writes/review specs before coding.
Dispatches parallel agents to independently tackle 2+ tasks like separate test failures or subsystems without shared state or dependencies.
GitHub's event system is the backbone of awful workflows. Understanding the key patterns enables reliable, non-looping agent automation.
The most powerful routing primitive in GitHub: issues.labeled fires with the label name available for filtering.
on:
issues:
types: [labeled]
jobs:
triage:
if: github.event.label.name == 'needs-triage'
Labels let you build a pure event-driven routing table: each label maps to exactly one agent response.
When an agent in workflow A needs to trigger workflow B without using a label:
# Workflow A sends signal
- name: trigger downstream
run: |
gh api repos/${{ github.repository }}/dispatches \
--field event_type=agent-completed \
--field client_payload='{"issue":${{ github.event.issue.number }}}'
# Workflow B listens
on:
repository_dispatch:
types: [agent-completed]
Use sparingly — prefer labels when the routing is user-visible.
For sequential agent pipelines where B must always follow A:
on:
workflow_run:
workflows: ["Triage Agent"]
types: [completed]
Limitation: workflow_run only fires for workflows on the default branch.
issue_comment events let users direct agents from issue/PR threads:
on:
issue_comment:
types: [created]
jobs:
handle:
if: |
github.event.issue.pull_request != null &&
startsWith(github.event.comment.body, '/review')
Always validate command format strictly before routing — comment bodies are untrusted.
Periodic tasks (stale cleanup, weekly reports) use cron expressions:
on:
schedule:
- cron: '0 9 * * 1' # Monday 9am UTC
Cron jobs run on the default branch. They cannot be tied to specific issues/PRs; agents must query state themselves.
Loops are the most common failure mode in agent workflows. Three layers of defense.
Every write-capable workflow must check:
if: github.actor != 'github-actions[bot]'
This prevents: agent adds label → label event fires → agent adds label → ...
For workflows that may be triggered by other bots (dependabot, renovate), expand the guard:
if: |
github.actor != 'github-actions[bot]' &&
github.actor != 'dependabot[bot]'
Agents apply labels with the awful: prefix. Routing conditions match on plain labels only:
bug, priority-high, needs-triage → triggers agentawful:triaged, awful:needs-attention → does NOT trigger agentThis creates a clean separation between signal labels (human intent) and state labels (agent output).
Prevents duplicate runs for the same issue/PR:
concurrency:
group: awful-${{ github.event.issue.number || github.event.pull_request.number }}
cancel-in-progress: false
cancel-in-progress: false queues rather than cancels — ensures the second run still happens after the first completes, but never runs two simultaneously.
One event triggers multiple independent agents. Each agent has its own workflow file:
issues.opened
→ triage-agent.yml (classify, label)
→ auto-assign.yml (find owner, assign)
→ welcome-agent.yml (if first-timer)
Fan-out is implicit in GitHub Actions — multiple workflows can listen to the same event. No explicit coordination needed.
Agent A output triggers Agent B via label:
issues.opened → triage-agent adds label:needs-specialist
→ issues.labeled:needs-specialist → specialist-agent
→ specialist-agent adds label:awful:specialist-reviewed
Design pipelines to terminate — every path must reach a state with no further triggers.
Agent proposes, human approves:
issues.labeled:needs-fix → fix-proposer-agent
→ fix-proposer creates PR
→ human reviews and merges (or closes)
Use comment slash commands (/approve, /reject) to give humans structured control points.
Scheduled agent checks state and acts:
cron:daily → stale-agent
→ scans all open issues
→ issues warning comments
→ closes after 7-day grace period
Sweeps must be idempotent — they may find the same issues multiple times.
Agent A adds label:X → Agent B removes label:X → Agent A adds label:X...
Prevention: never remove a label as a trigger signal. Use separate labels for input vs output.
A single action creates many events, each triggering a workflow:
Agent creates 10 labels → 10 label events → 10 workflow runs
Prevention: batch label operations when possible. Add bot actor guard to all triggered workflows.
No depth limit on chain reactions — agent A → B → C → D → ... → out of resources.
Prevention: design pipelines with explicit terminal states. Document the max depth in the blueprint.
Agent modifies repo files directly without a review buffer:
agent edits src/main.py directly → pushes to main
Prevention: agents should create PRs, not push directly. In gh-aw format, use safe-outputs to restrict operations.