Skip to content

Issue Triage Workflow Design

Workflow and domain design for the github-issue-triage entity loop.

Layer Document
Platform Multi-Branch Loops Design
Caller shell Loop Caller Reusable Design (entity)
Spec Issue Triage Entity Loops
Boundaries Entity Caller Responsibility Separation
Invariants Loop Engineering Design

Artifacts: on-loop-github-issue-triage.yaml · skill github-issue-triage · detect_issue.sh · ci-loop-caller-entity.yaml

Shared caller keys: Loop Caller Inputs Reference (entity subset).

Purpose

On Issue / issue_comment events, classify the Issue when confident, apply allowlisted triage labels, and post analysis or clarifying questions as comments (L1). Does not open PRs.

Supported use cases

  • issues opened/reopened/labeled → entity detect + L1 agent (label removal does not re-trigger triage)
    • labeled intake is limited to needs-triage, triage:needs-info, and triage:ready. Classification labels the agent applies itself stay out, and autofix belongs to Autofix Design. triage:ready reaches detect only for the dispatch hook — the agent is still skipped for it
    • Bot senders are refused in the job if, so agent-applied labels never re-enter the queue (see Intake Gating)
  • issue_comment created by a non-bot author while triage:needs-info is present (human answers while awaiting info)
  • workflow_dispatch with issue_number for manual re-triage

Out of scope

Deferred dogfood

Live workflow_dispatch dry-run requires repository secrets (AGENT_TOKEN, optional bot app). Treat end-to-end Actions dogfood as deferred until secrets are available; local verification is Bats + actionlint.

Caller inputs

Keys are passed in on-loop-github-issue-triage.yaml via with: on ci-loop-caller-entity.yaml. Entity subset of Loop Caller Inputs Reference.

Input / JSON key Description Dogfood value
agent_maker_instructions Domain maker task (triage skill) Inline in caller workflow
agent_maker_max_turns Max maker turns per attempt 100
agent_maker_model Maker model ID claude-sonnet-5
agent_maker_effort Maker reasoning effort. Only engines with an effort flag (claude) consume it medium
agent_maker_skill_name Skill package github-issue-triage
agent_loop_max_attempts Max Agent→Verify cycles 3
agent_checker_instructions APPROVE/REJECT rubric (allowlisted labels only) Inline in caller workflow
agent_checker_max_turns Max checker turns 100
agent_checker_model Checker model ID claude-opus-5
agent_checker_effort Checker reasoning effort. Only engines with an effort flag (claude) consume it medium
agent_checker_skill_name Checker skill loop-verifier
allowlist File edit allowlist (empty = no file edits) ""
branch_state .loop/* persistence branch main
budget_max_runs_per_day Daily run cap 20
budget_max_tokens_per_day Daily token cap 1000000
delivery Platform delivery (none — L1 comments/labels only) none
denylist Denylist globs ""
detect_script Domain detect script .agents/skills/github-issue-triage/scripts/detect_issue.sh
dispatch_hook_script Trusted post-detect hook (autofix dispatch) .agents/skills/github-issue-triage/scripts/hooks/on_detect_dispatch.sh
engine AI engine claude
environment GitHub Environment for env-scoped secrets default
level Autonomy (L1 — no PR) L1
loop_name Loop identifier github-issue-triage
may_edit Agent worktree edit gate false
no_changes_verdict Verdict when no file diff APPROVE
write_target Agent artifact type report

Domain detect environment (detect_domain_env_json)

{} on webhook paths. workflow_dispatch may pass ISSUE_NUMBER:

detect_domain_env_json: ${{ github.event_name == 'workflow_dispatch' && format('{{"ISSUE_NUMBER":{0}}}', toJSON(inputs.issue_number)) || '{}' }}

Detect script env (explicit or hydrated from GITHUB_EVENT_PATH): ISSUE_NUMBER, ISSUE_TITLE, ISSUE_BODY, ISSUE_LABELS_JSON, ISSUE_EVENT_NAME, ISSUE_EVENT_ACTION, ISSUE_COMMENT_ID, ISSUE_ACTOR, ISSUE_ACTOR_TYPE, ISSUE_COMMENT_USER_TYPE.

Caller shape

on-loop-github-issue-triage.yaml
  loop → uses ci-loop-caller-entity.yaml
           detect  → loop-entity-detect
                       (detect_issue.sh reads GITHUB_EVENT_PATH;
                        workflow_dispatch may pass ISSUE_NUMBER via detect_domain_env_json)
           execute → ci-loop-agent (issues: write; finalize-l1 run-log; finalize_enabled=false so no PR)
           record-skip → budget | circuit_breaker

No caller prepare job — event mapping lives in the skill detect script (E17).

Detect contract

Skip when actor or comment author is Bot, or when triage:failed is present (E7). When skip=false, emit result.handoff_key = entity:issue:<N> (S1).

Skill contract

See .apm/packages/github/.apm/skills/github-issue-triage/SKILL.md and references/category-*.md.