Documents
AI-Driven Issue Management
AI-Driven Issue Management
Type
Topic
Status
Published
Created
Apr 22, 2026
Updated
Apr 24, 2026
Created by
Dosu Bot
Updated by
Dosu Bot

AI-Driven Issue Management#

better-stale-bot is an AI-powered GitHub issue management bot built on GitHub Agentic Workflows. Unlike timer-based tools (e.g., actions/stale) that mechanically label every quiet issue, it uses Claude to read each thread end-to-end, classify whether the issue looks resolved, and draft issue-specific stale comments — all in the detected language of the issue title .

All AI logic lives in a single instruction file: .github/workflows/better-stale-bot.md. That markdown file is compiled (via gh aw compile) into a locked YAML workflow (better-stale-bot.lock.yml) that GitHub Actions executes on a configurable schedule (default: daily) .

Why better-stale-bot#

Maintainers should be able to run this kind of automation directly in their repo, inspect the policy in plain text, and change the behavior without adopting a hosted service. better-stale-bot was pulled from Dosu's hosted product, rewritten as standalone, and open sourced so teams can own their stale-issue logic end-to-end.

Comparison with actions/stale#

actions/stalebetter-stale-bot
Decision logicTimer-basedAgent reads and summarizes the thread
Comment bodyStatic templateIssue-specific summary and next steps
LanguageWhatever template you writeLanguage of the issue title
Processing orderTime-basedLow-engagement issues first
Resolved detectionNoneClassifies resolved vs. unresolved
Re-engagementConfigurable activity rulesRemoves Stale on qualifying non-bot activity
Write limitsWorkflow configurationAgentic Workflow safe outputs
Audit trailGitHub Actions logsGitHub Actions logs plus agent reasoning

Migration from Dosu Hosted Stale Bot#

If you're migrating from Dosu's hosted stale bot service to better-stale-bot, note these default setting differences:

SettingDosu stale bot defaultsbetter-stale-bot defaults
days-before-stale9060
days-before-close77
Per-run caps2530
Exempt labelsnoneagentic-workflows, pinned, security, help wanted

These values can be customized in the workflow configuration to match your previous setup.

How It Works#

Each run executes two jobs in a single workflow run:

  • Job (a): Labeling potentially stale issues — scores inactive issues (Bucket B) by engagement, reads their threads end-to-end, summarizes the discussion, classifies resolution status, and applies the Stale label with a context-aware comment.
  • Job (b): Handling already-stale issues — processes issues already carrying the Stale label (Bucket A); closes them if the grace period (days-before-close) has elapsed with no qualifying non-bot activity, or removes the Stale label if qualifying activity resumed.

Five-Step AI Workflow#

The model follows five ordered steps on every run, all defined in better-stale-bot.md:

Step 1 — Retrieve & Categorize (lines 57–74)#

Issues are split into two buckets :

  • Bucket A — issues already carrying the Stale label (candidates for closure or label removal)
  • Bucket B — issues without Stale that have been inactive for at least days-before-stale full days (default 60)

Issues with exempt labels (agentic-workflows, pinned, security, help wanted) are skipped entirely .

Step 2 — Rank Bucket B by Engagement (lines 76–94)#

To avoid mass-labeling high-activity threads, each Bucket B issue gets a weighted engagement score :

engagement_score = (3 × distinct_users) + (2 × total_comments_and_reactions) + (1 × whole_weeks_since_last_updated)

Issues are sorted ascending — lowest score (quietest thread) is processed first. The model must show the full substituted arithmetic before acting on any issue, providing an auditable trail .

Step 3 — Summarize, Classify & Comment (lines 96–127)#

For each selected issue the model :

  1. Writes a 2–3 sentence issue summary
  2. Summarizes the comment thread
  3. Classifies resolution status: RESOLVED: <one-line summary> or UNRESOLVED
  4. Generates a stale comment in the language of the issue title (see Multilingual Comment Generation)
  5. Posts the comment (add-comment) and applies Stale (add-labels)

Step 4 — Close or Reactivate Bucket A (lines 128–137)#

For Bucket A issues :

  • Close: if at least days-before-close (default 7) full days have passed since stale_label_applied_at with no qualifying non-bot activity. Closed with state_reason: NOT_PLANNED — never COMPLETED (stale closure is not a resolution) .
  • Remove Stale: if qualifying non-bot activity has occurred after stale_label_applied_at; removed silently, no additional comment posted .

Step 5 — Persist Run State (lines 139–150)#

A JSON summary is written to cache-memory at /tmp/gh-aw/cache-memory/stale-bot-state.json recording what was labeled, closed, and un-staled. Subsequent runs read this file to skip recently handled issues .

Cache Memory#

Between runs, cache-memory stores a short run summary. This happens in Step 5 of the workflow, where the agent persists a JSON summary of actions taken (what was labeled, closed, or un-staled).

The instructions explicitly tell the agent to read the cache at the start of later runs, allowing it to avoid blind reprocessing of issues that were recently handled.

Multilingual Comment Generation#

Comment language is driven entirely through prompting — no locale configuration is needed. The model detects the primary language from the issue title and uses it for all generated text; when multiple languages are present in the thread, the title language wins .

Before emitting, the model self-validates that the language matches; if not, it regenerates the comment in the correct language .

Every stale comment must follow a four-part structure (translated naturally into the target language) :

  1. Opening — First-person bot statement marking the issue stale; optionally @mentions the author
  2. Issue summary — What the issue is about, what was discussed, and whether it looks resolved or still open
  3. Next steps — Invites renewed activity; states days-before-close in plain language (e.g. "in 7 days") — no vague timing allowed
  4. Thanks — Single closing line of appreciation

Style is empathetic and concise; emoji are omitted unless the existing thread already uses them .

Safety, Rate Limits & Configuration#

Safe outputs cap how many write operations the bot may perform per run . Caps are defined only in the YAML frontmatter; after editing them, gh aw compile must be re-run .

GuardrailDefault
ScheduleDaily
Inactivity before stale label60 days
Grace period before close7 days
Max comments per run30
Max labels added per run30
Max labels removed per run30
Max issues closed per run30
Close reasonNOT_PLANNED
Pull requestsOff by default

Safe Output Types#

better-stale-bot uses the following safe-output types, each of which can be configured to constrain what the agent can do:

Note: The following list describes all safe-output types available in the GitHub Agentic Workflows platform. However, better-stale-bot only uses a subset of these: add-comment, add-labels, remove-labels, close-issue, and noop. The other types (update-issue, hide-comment, assign-to-user, unassign-from-user, create-issue) are available in the platform but not configured in the better-stale-bot workflow.

  • add-comment — Posts comments on issues. Supports max to limit how many comments per run, target to specify which issue(s) ("triggering", "*", or a number), hide-older-comments to collapse older bot comments, and footer control.
  • add-labels — Adds labels to issues. Supports an allowed list to restrict which labels can be added, blocked patterns to forbid specific labels, and max to cap total additions per run.
  • remove-labels — Removes labels from issues. Supports allowed list and blocked patterns.
  • close-issue — Closes issues with optional comment and state reason. Supports target (issue selector), required-labels (only close if present), and state-reason (completed, not_planned, or duplicate).
  • update-issue — Updates issue fields such as title, body, or state.
  • hide-comment — Minimizes comments on issues.
  • assign-to-user / unassign-from-user — Manages issue assignments.
  • create-issue — Creates new issues. Supports expires, group, and close-older-issues options.
  • noop — Required when no action is taken. MUST be called when no GitHub action is needed to prevent silent workflow failure.

All safe-output types support cross-repository operations via target-repo and allowed-repos. Every output includes a hidden workflow-id marker for searchability: <!-- gh-aw-workflow-id: WORKFLOW_NAME -->.

Note: The noop safe output is critical. If the agent finishes without calling any safe-output tool, the workflow fails silently.

Staged Mode#

Users can preview what safe outputs a workflow would create without actually executing them by adding staged: true to the safe-outputs: block in the YAML frontmatter. This is useful for testing better-stale-bot before letting it label or close issues.

Replaying Safe Outputs#

If the safe_outputs job fails (e.g., transient API error or threat detection blocking), users can replay safe outputs from a previous run using the Agentic Maintenance workflow by providing the failed run URL.

Workflow Structure#

Policy defaults are set in the ## Configuration table of better-stale-bot.md :

ParameterDefault
days-before-stale60
days-before-close7

Policy settings like days-before-stale, days-before-close, exempt labels, and instruction logic are in the markdown body and can be changed without recompilation. Engine choice, safe-output max caps, permissions, and schedule are in the YAML frontmatter and require gh aw compile better-stale-bot after any change.

Engine Configuration#

Engine: Claude Haiku by default (engine: { id: claude, model: haiku }), requiring ANTHROPIC_API_KEY as a repo secret. All six supported engines are available — change the engine: field in frontmatter and recompile .

EngineRequired SecretNotes
GitHub Copilot CLICOPILOT_GITHUB_TOKENFine-grained PAT with Copilot Requests permission. Resource owner must be personal account, not org. Default choice for most users; supports the broadest gh-aw feature set.
Claude by Anthropic (default)ANTHROPIC_API_KEYAPI key from Anthropic Console. Choose when you want stronger control over turn limits (max-turns) for long reasoning sessions.
OpenAI CodexOPENAI_API_KEYRuntime uses CODEX_API_KEY if present, falls back to OPENAI_API_KEY
Google Gemini CLIGEMINI_API_KEYAPI key from Google AI Studio. Available through GH Agentic Workflows platform but not extensively tested with better-stale-bot.
Crush (experimental)COPILOT_GITHUB_TOKENRequires same PAT as Copilot. Experimental engine available in platform; better-stale-bot primarily tested with Copilot, Claude, and Codex.
OpenCode (experimental)COPILOT_GITHUB_TOKENRequires same PAT as Copilot. Experimental engine available in platform; better-stale-bot primarily tested with Copilot, Claude, and Codex.

An invalid model slug may be resolved to the provider's default model; verify which model was actually used via the Agent Summary → Token Usage view.

Timeout configuration: Each workflow run is bounded by timeout controls at multiple levels:

  • timeout-minutes: job-level wall clock (default 20 min)
  • tools.timeout: per tool-call limit in seconds (Claude default 60s, Codex default 120s)
  • max-turns: iteration budget (Claude only)
  • max-continuations: autopilot run budget (Copilot only)

Hallucination guard: The model is explicitly instructed not to infer details absent from the issue thread, and all generated summaries and classifications must be factual and deterministic .

Engine Defaults#

The workflow defaults to Claude Haiku as defined in the YAML frontmatter:

engine:
  id: claude
  model: haiku

The template also schedules a daily run:

on:
  schedule:
    - cron: '0 0 * * *' # daily

Customization#

You can rename the workflow file (both .md and .lock.yml) to match your repo's conventions.

Changes to the YAML frontmatter require recompilation — this includes:

  • Engine and model selection
  • Safe-outputs max limits
  • Schedule (on:)

Changes to the markdown body take effect on the next run without recompilation — this includes:

  • Policy settings (days-before-stale, days-before-close)
  • Exempt labels
  • AI instructions and prompts

AI Engine Examples#

# GitHub Copilot (default for most users)
engine: copilot

# Claude Haiku (default in this template)
engine:
  id: claude
  model: haiku

# Claude (defaults to Sonnet)
engine: claude

# OpenAI Codex
engine: codex

You can also use a coding agent to edit the workflow. The create.md spec provides the full format for agentic authoring.

No-Op Posted as an Issue#

The exempt label list includes agentic-workflows by default. This exempts the [aw] No-Op Runs issue, which agentic-workflows creates to report workflows that call noop (no GitHub action taken).

To disable noop issue reporting entirely, add the following to the YAML frontmatter:

safe-outputs:
  noop:
    report-as-issue: false

Tips / Billing#

LLM usage is charged by your chosen engine. Cost scales with:

  • The model selected (haiku vs. sonnet, for example)
  • How many issues a run touches
  • The amount of thread context read

To inspect token usage:

  • GitHub Actions → click on an agentic-workflows workflow run → Agent Summary → scroll to Agentic Conversation and Token Usage
  • Or use gh aw logs and gh aw audit commands

During simple test runs using Claude Haiku 4.5, costs varied between $0.08 to $0.40 per run. This is not representative of all use cases.

Key Files & References#

FilePurpose
.github/workflows/better-stale-bot.mdAll AI instructions, prompts, and policy configuration
.github/workflows/better-stale-bot.lock.ymlCompiled GitHub Actions workflow (auto-generated; do not edit manually)
README.mdInstallation, migration guides, customization, and billing notes

External references:

Migration from GitHub's Stale Bot#

The workflow is issues-only by default. Permissions, tools, safe-outputs, and instructions are all scoped to issues.

To extend support to pull requests:

  1. Widen permissions — Add pull-requests: write to the YAML frontmatter
  2. Grant PR tools — Ensure list-pull-requests, get-pull-request, and other PR-related tools are available
  3. Add PR safe-outputs — Configure safe-outputs that target PRs (e.g., close-pull-request)
  4. Update instructions — Edit the markdown body to include PR-specific logic and bucket definitions

Repository Layout#

The better-stale-bot repository uses a two-copy distribution model to separate the distribution template from the active workflow:

  • workflows/ — Distribution template directory. This is the canonical source that users install from. When running gh aw add-wizard dosu-ai/better-stale-bot/better-stale-bot or manually downloading the workflow, the file comes from this location. This directory contains the clean, ready-to-distribute version of better-stale-bot.md.

  • .github/workflows/ — Active workflow directory. This is where the workflow actually runs within the better-stale-bot repository itself. It contains both the better-stale-bot.md source file and the compiled better-stale-bot.lock.yml. This copy is used for testing and validating changes to the workflow before distribution.

For contributors: Changes should be made to .github/workflows/better-stale-bot.md first, tested in the repository, and then synced to workflows/better-stale-bot.md before distribution. The two copies must stay synchronized.

Installation & Setup#

Prerequisites: better-stale-bot requires the gh CLI with the gh-aw extension installed, and an AI account with Copilot, Claude, or Codex.

This is the simplest approach. The add-wizard command handles secret setup, downloads the workflow, compiles it, and opens a PR — all interactively.

# 1. Authenticate with GitHub
gh auth login

# 2. Install the gh-aw CLI extension
gh extension install github/gh-aw

# 3. Run add-wizard (downloads from workflows/ directory, sets secrets, opens a PR)
# Optional: add --skip-secret flag to skip secret configuration
gh aw add-wizard dosu-ai/better-stale-bot/better-stale-bot

# 4. Pull the changes locally
git pull

Option B: Manual Setup (Alternative)#

For users who prefer more control over each step:

# 1. Install gh-aw
gh auth login
gh extension install github/gh-aw

# 2. Add your engine secret in repo Settings → Secrets and variables → Actions
# (ANTHROPIC_API_KEY for Claude, COPILOT_GITHUB_TOKEN for Copilot, OPENAI_API_KEY for Codex)

# 3. Download from workflows/ directory, compile, and push
mkdir -p .github/workflows
curl -fsSL https://raw.githubusercontent.com/dosu-ai/better-stale-bot/main/workflows/better-stale-bot.md \
  -o .github/workflows/better-stale-bot.md
gh aw compile better-stale-bot
git add .github/ .gitattributes
git commit -m "Add better-stale-bot workflow"
git push

# 4. Run
gh aw run better-stale-bot

Additional Commands#

Configure API key (or other engine secrets):

gh aw secrets set ANTHROPIC_API_KEY

Auto-detect required secrets and prompt interactively:

gh aw secrets bootstrap

Building & Validation#

Compile workflows with optional validation flags:

gh aw compile
gh aw compile --validate
gh aw compile --strict
gh aw compile --zizmor

Validate without generating lock files:

gh aw validate

Auto-fix deprecated fields (preview changes):

gh aw fix

Apply fixes:

gh aw fix --write

Debug logging:

DEBUG=* gh aw compile

Monitoring & Management#

Check if better-stale-bot is enabled and view run info:

gh aw status

Analyze logs with tool usage, network patterns, errors:

gh aw logs

Generate reports on workflow runs:

gh aw audit

View success rates and trends:

gh aw health

Enable or disable the workflow:

gh aw enable
gh aw disable

Update from source with 3-way merge:

gh aw update

Remove the workflow:

gh aw remove

Note: All gh aw commands support fuzzy workflow name matching. If you have multiple workflows, you can specify a partial name and the CLI will interactively prompt you to select the correct one.

Additional Resources#

When Should You Use an AI Stale Bot?#

better-stale-bot is designed for:

  • Open source projects with a long support backlog
  • Developer tools with many bug reports and environment-specific questions
  • Internal platform teams that use GitHub Issues as an intake queue
  • Maintainers who want to close abandoned issues without losing context
  • Teams migrating away from Dosu's hosted stale bot
  • Teams looking for an actions/stale alternative with issue summaries

It is probably not necessary for a small repository with ten open issues.

FAQ#

What is an AI stale bot?#

An AI stale bot uses a language model to read issue threads, summarize the discussion, and determine whether an inactive issue looks resolved or still open. Unlike timer-based tools that apply the same template to every quiet issue, an AI stale bot generates context-specific comments in the language of the issue title.

Is better-stale-bot a replacement for actions/stale?#

Yes. better-stale-bot reads each thread, generates issue-specific summaries, detects whether an issue looks resolved, and writes comments in the language of the issue title. See the Comparison with actions/stale section for a detailed breakdown.

Does better-stale-bot close issues automatically?#

Yes, but only after two conditions are met: (1) the issue has been inactive for days-before-stale (default 60 days) and received the Stale label, and (2) no qualifying non-bot activity occurred during the days-before-close grace period (default 7 days). All write operations are capped by safe-output limits.

Does it work on pull requests?#

Pull requests are off by default. To enable PR support, you must widen permissions in the YAML frontmatter, grant PR-related tools, configure PR safe-outputs, and update the markdown instructions. See the Migration from GitHub's Stale Bot section.

Which AI models does it support?#

better-stale-bot supports six engines: GitHub Copilot CLI, Claude by Anthropic (default), OpenAI Codex, Google Gemini CLI, Crush (experimental), and OpenCode (experimental). You configure the engine in the YAML frontmatter. See the Engine Configuration section for API key requirements.

How much does it cost?#

LLM usage is charged by your chosen engine. Cost scales with the model selected (haiku vs. sonnet), how many issues a run touches, and the amount of thread context read. During simple test runs using Claude Haiku 4.5, costs varied between $0.08 to $0.40 per run. This is not representative of all use cases. See the Tips / Billing section for details on inspecting token usage.

Can I change the stale comment?#

Yes. The stale comment structure, tone, and logic are all defined in the markdown body of the workflow file (.github/workflows/better-stale-bot.md). You can edit the instructions and they will take effect on the next run without recompilation. See the Multilingual Comment Generation and Customization sections.