Skip to content

Issue Management

Relevant source files

This document explains the issue tracking workflow for TajsMod, including the structured issue templates and automated triage system. It covers how bug reports and feature requests are standardized through GitHub Issue Forms, and how the automated labeling workflow processes them.

For general contribution guidelines and code style, see Contributing Guidelines. For information about the release process, see Building and Distribution.


TajsMod uses GitHub Issue Forms to enforce structured issue reporting. All issues are automatically triaged and labeled by a GitHub Actions workflow that parses form fields and applies appropriate labels.

Key Components:

  • Bug Report Form: 11 required fields capturing version info, reproduction steps, frequency, and environment
  • Feature Request Form: 8 required fields capturing problem statement, solution, scope, and constraints
  • Automated Triage: issue-triage.yml workflow that labels issues on creation/edit/reopen
flowchart TD

User["👤 User/Contributor"]
NewIssue["New Issue Button"]
BugTemplate["bug_report.yml<br>11 Required Fields"]
FeatureTemplate["feature_request.yml<br>8 Required Fields"]
ConfigYml["config.yml<br>Template Routing"]
IssueCreated["GitHub Issue Created<br>Markdown Body"]
IssueEvent["Trigger: opened/edited/reopened"]
Workflow["issue-triage.yml<br>GitHub Actions"]
Parser["Parse Issue Body<br>Extract Form Fields"]
Labeler["Apply Labels<br>Based on Mappings"]
Category["Category Labels:<br>ui, qol, performance, etc"]
Scope["Scope Labels:<br>scope:small/medium/large"]
Impact["Impact Labels:<br>impact:performance, opt-in"]
Repro["Reproduction:<br>repro:always/intermittent"]
Special["Special:<br>needs-triage, crash, regression"]
Labeled["Labeled Issue<br>Ready for Review"]
Triage["Manual Triage<br>By Maintainer"]

NewIssue --> ConfigYml
BugTemplate --> IssueCreated
FeatureTemplate --> IssueCreated
IssueEvent --> Workflow
Labeler --> Category
Labeler --> Scope
Labeler --> Impact
Labeler --> Repro
Labeler --> Special
Category --> Labeled
Scope --> Labeled
Impact --> Labeled
Repro --> Labeled
Special --> Labeled

subgraph subGraph5 ["Issue Tracker"]
    Labeled
    Triage
    Labeled --> Triage
end

subgraph subGraph4 ["Label Categories"]
    Category
    Scope
    Impact
    Repro
    Special
end

subgraph subGraph3 ["Automated Triage"]
    Workflow
    Parser
    Labeler
    Workflow --> Parser
    Parser --> Labeler
end

subgraph subGraph2 ["Submitted Issue"]
    IssueCreated
    IssueEvent
    IssueCreated --> IssueEvent
end

subgraph subGraph1 ["Template Selection"]
    BugTemplate
    FeatureTemplate
    ConfigYml
    ConfigYml --> BugTemplate
    ConfigYml --> FeatureTemplate
end

subgraph subGraph0 ["Issue Entry Points"]
    User
    NewIssue
    User --> NewIssue
end

Sources: .github/ISSUE_TEMPLATE/config.yml L1-L10

.github/workflows/issue-triage.yml L1-L144


The bug report form is defined in .github/ISSUE_TEMPLATE/bug_report.yml L1-L273

and enforces comprehensive bug documentation.

FieldIDTypePurposeValidation
Taj’s Mod versionmod_versioninputTracks which release has the bugRequired
Game versiongame_versioninputIdentifies base game compatibilityRequired
CategorycategorydropdownCategorizes bug typeRequired (7 options)
Describe the bugdescriptiontextareaPrimary bug descriptionRequired
Steps to reproducereproduction_stepstextareaReproduction procedureRequired
Actual behavioractualtextareaWhat actually happenedRequired
How often does it occur?frequencydropdownReproduction frequencyRequired (5 options)
Did this work in an older version?regressiondropdownRegression detectionRequired (3 options)
Other installed modsother_modstextareaConflict identificationRequired
EnvironmentenvironmenttextareaSystem specificationsRequired
ConfirmationsconfirmationscheckboxesQuality checklist3 required checkboxes
flowchart TD

ModVer["mod_version<br>v0.0.14"]
GameVer["game_version<br>2.0.17"]
Category["category<br>Visual/QoL/Performance/etc"]
Frequency["frequency<br>Every time/Often/Sometimes/Rarely/Once"]
Regression["regression<br>Yes/No/Not sure"]
Description["description<br>What happened + expected"]
Steps["reproduction_steps<br>Step-by-step procedure"]
Expected["expected<br>What should happen"]
Actual["actual<br>What did happen"]
OtherMods["other_mods<br>List of enabled mods"]
Environment["environment<br>OS/CPU/GPU/RAM/Display"]
Media["media<br>Screenshots/video (optional)"]
Logs["logs<br>Log files (optional)"]
ConflictChecks["conflict_checks<br>Tested with only TajsMod"]
Confirmations["confirmations<br>Searched/Latest/Enough info"]

ModVer --> Category
GameVer --> Category
Category --> Description
Frequency --> Description
Regression --> Description
Actual --> OtherMods
Logs --> ConflictChecks

subgraph subGraph4 ["Quality Control"]
    ConflictChecks
    Confirmations
    ConflictChecks --> Confirmations
end

subgraph subGraph3 ["Context & Environment"]
    OtherMods
    Environment
    Media
    Logs
    OtherMods --> Environment
    Environment --> Media
    Media --> Logs
end

subgraph subGraph2 ["Bug Description"]
    Description
    Steps
    Expected
    Actual
    Description --> Steps
    Steps --> Expected
    Steps --> Actual
end

subgraph subGraph1 ["Bug Classification"]
    Category
    Frequency
    Regression
end

subgraph subGraph0 ["Version Tracking"]
    ModVer
    GameVer
end

Sources: .github/ISSUE_TEMPLATE/bug_report.yml L25-L273

The category field maps to automated labels (see Automated Triage section):

  • Visual / UI: UI rendering, layout, styling issues
  • QoL / Utility: Quality-of-life features not working as expected
  • Performance: FPS drops, lag, memory issues
  • Accessibility: Input handling, readability, usability
  • Gameplay (opt-in): Bugs in opt-in gameplay modifiers (node limits, cheats)
  • Modding / API / Integration: Conflicts with other mods or mod loader
  • Other: Uncategorized issues

Sources: .github/ISSUE_TEMPLATE/bug_report.yml L44-L57

The frequency field determines reproduction reliability labels:

User SelectionApplied LabelInterpretation
Every timerepro:always100% reproducible
Often ( > 50% )repro:intermittentFrequently reproducible
Sometimesrepro:intermittentOccasionally reproducible
Rarelyrepro:intermittentHard to reproduce
Oncerepro:intermittentSingle occurrence

Sources: .github/ISSUE_TEMPLATE/bug_report.yml L124-L135

.github/workflows/issue-triage.yml L73-L79


The feature request form is defined in .github/ISSUE_TEMPLATE/feature_request.yml L1-L210

and enforces structured feature proposals.

FieldIDTypePurposeValidation
What would you like to add/change?summarytextareaOne-sentence summaryRequired
What problem does this solve?motivationtextareaProblem statement & use caseRequired
What should happen?proposed_solutiontextareaDetailed solution descriptionRequired
CategorycategorydropdownFeature categorizationRequired (7 options)
How big is this?scopedropdownEstimated complexityRequired (4 options)
How do we know it’s done?acceptance_criteriatextareaDefinition of doneRequired
ConsiderationsconstraintscheckboxesConstraint identificationOptional (6 options)
ConfirmationsconfirmationscheckboxesQuality checklist3 required checkboxes

The scope field maps to complexity labels:

User SelectionApplied LabelTypical Work
Small (tweak / small option)scope:smallSingle-file change, simple toggle
Medium (new setting / moderate logic)scope:mediumMulti-file feature, settings UI
Large (multi-part feature; needs planning)scope:largeNew subsystem, extensive integration
Not sure(no label)Requires maintainer assessment

Sources: .github/ISSUE_TEMPLATE/feature_request.yml L94-L102

.github/workflows/issue-triage.yml L58-L62

The constraints field allows multiple selections that map to impact labels:

flowchart TD

Performance["Could impact performance<br>CPU/GPU/memory"]
Conflicts["Could conflict with<br>other mods"]
Keybind["Needs a keybind /<br>input mapping"]
OptIn["Should be opt-in<br>default off"]
Multiplayer["Might affect multiplayer /<br>co-op behavior"]
I18n["Might need localization /<br>translations"]
PerfLabel["impact:performance"]
ConflictLabel["impact:conflicts"]
KeybindLabel["needs:keybind"]
OptInLabel["opt-in"]
MultiLabel["multiplayer"]
I18nLabel["i18n"]

Performance --> PerfLabel
Conflicts --> ConflictLabel
Keybind --> KeybindLabel
OptIn --> OptInLabel
Multiplayer --> MultiLabel
I18n --> I18nLabel

subgraph subGraph1 ["Applied Labels"]
    PerfLabel
    ConflictLabel
    KeybindLabel
    OptInLabel
    MultiLabel
    I18nLabel
end

subgraph subGraph0 ["Constraint Checkboxes"]
    Performance
    Conflicts
    Keybind
    OptIn
    Multiplayer
    I18n
end

Sources: .github/ISSUE_TEMPLATE/feature_request.yml L111-L127

.github/workflows/issue-triage.yml L64-L71


The .github/workflows/issue-triage.yml L1-L144

workflow automatically labels issues when they are opened, edited, or reopened.

on:
issues:
types: [opened, edited, reopened]

The workflow runs on three events:

  • opened: New issue created
  • edited: Issue body modified
  • reopened: Closed issue reopened

Sources: .github/workflows/issue-triage.yml L3-L5

The workflow uses JavaScript to parse the Markdown issue body and extract Issue Form field values:

flowchart TD

IssueBody["Issue Body<br>Markdown with ### Headers"]
GetSection["getSection label<br>Regex: ###\s+label\s*<br>+"]
GetSingleLine["getSingleLine label<br>Extract first non-empty line"]
GetChecked["getCheckedOptions label<br>Find - [x] lines"]
Category["Category dropdown value"]
Scope["Scope dropdown value"]
Frequency["Frequency dropdown value"]
Regression["Regression dropdown value"]
Constraints["Checked constraint options[]"]
CategoryMap["categoryMap<br>Visual/UI → [ui]"]
ScopeMap["scopeMap<br>Small → [scope:small]"]
ConstraintsMap["constraintsMap<br>Performance → [impact:performance]"]
FrequencyMap["bugFrequencyMap<br>Every time → [repro:always]"]
DesiredLabels["desired = Set<br>All applicable labels"]

IssueBody --> GetSection
GetSingleLine --> Category
GetSingleLine --> Scope
GetSingleLine --> Frequency
GetSingleLine --> Regression
GetChecked --> Constraints
Category --> CategoryMap
Scope --> ScopeMap
Frequency --> FrequencyMap
Constraints --> ConstraintsMap
CategoryMap --> DesiredLabels
ScopeMap --> DesiredLabels
FrequencyMap --> DesiredLabels
ConstraintsMap --> DesiredLabels

subgraph subGraph4 ["Label Set"]
    DesiredLabels
end

subgraph subGraph3 ["Label Mappings"]
    CategoryMap
    ScopeMap
    ConstraintsMap
    FrequencyMap
end

subgraph subGraph2 ["Extracted Data"]
    Category
    Scope
    Frequency
    Regression
    Constraints
end

subgraph subGraph1 ["Parser Functions"]
    GetSection
    GetSingleLine
    GetChecked
    GetSection --> GetSingleLine
    GetSection --> GetChecked
end

subgraph Input ["Input"]
    IssueBody
end

Sources: .github/workflows/issue-triage.yml L22-L44

The workflow defines three parser functions to extract form field values:

getSection(label): Extracts content between ### label and the next ### or end of body

const re = new RegExp(`###\\s+${escapeRegExp(label)}\\s*\\n+([\\s\\S]*?)(?=\\n###\\s+|$)`, "i");

getSingleLine(label): Gets the first non-empty line from a section (for dropdown values)

return section.split("\n").map(l => l.trim()).find(Boolean) || "";

getCheckedOptions(label): Finds all checked checkboxes in a section

return section.split("\n")
.filter(l => /^-\s*\[[xX]\]\s+/.test(l))
.map(l => l.replace(/^-\s*\[[xX]\]\s+/, "").trim());

Sources: .github/workflows/issue-triage.yml L24-L44

The workflow maintains four mapping objects that convert form field values to labels:

Category Map (.github/workflows/issue-triage.yml L47-L55

):

const categoryMap = {
"Visual / UI": ["ui"],
"QoL / Utility": ["qol"],
"Performance": ["performance"],
"Accessibility": ["accessibility"],
"Gameplay (opt-in)": ["gameplay"],
"Modding / API / Integration": ["modding"],
"Other": []
};

Scope Map (.github/workflows/issue-triage.yml L57-L62

):

const scopeMap = {
"Small (tweak / small option)": ["scope:small"],
"Medium (new setting / moderate logic)": ["scope:medium"],
"Large (multi-part feature; needs planning)": ["scope:large"],
"Not sure": []
};

Constraints Map (.github/workflows/issue-triage.yml L64-L71

):

const constraintsMap = {
"Could impact performance (CPU/GPU/memory)": ["impact:performance"],
"Could conflict with other mods": ["impact:conflicts"],
"Needs a keybind / input mapping": ["needs:keybind"],
"Should be opt-in (default off)": ["opt-in"],
"Might affect multiplayer / co-op behavior": ["multiplayer"],
"Might need localization / translations": ["i18n"]
};

Bug Frequency Map (.github/workflows/issue-triage.yml L73-L79

):

const bugFrequencyMap = {
"Every time": ["repro:always"],
"Often ( > 50% )": ["repro:intermittent"],
"Sometimes": ["repro:intermittent"],
"Rarely": ["repro:intermittent"],
"Once": ["repro:intermittent"]
};

The workflow maintains a set of “managed” labels that it has permission to add or remove. Labels not in this set are preserved and not touched by the automation:

const managed = new Set([
"needs-triage",
...Object.values(categoryMap).flat(),
...Object.values(scopeMap).flat(),
...Object.values(constraintsMap).flat(),
...Object.values(bugFrequencyMap).flat(),
"regression",
"crash"
]);

Label Preservation Logic:

  1. Fetch existing labels on the issue
  2. Keep all labels not in the managed set (e.g., bug, enhancement, manual labels)
  3. Replace all managed labels with newly computed labels
  4. Apply the merged set via github.rest.issues.setLabels()

This allows maintainers to add custom labels that won’t be removed by the automation.

Sources: .github/workflows/issue-triage.yml L82-L143

Beyond form field mappings, the workflow applies additional labels based on issue content:

Regression Detection (.github/workflows/issue-triage.yml L116-L117

):

const regression = getSingleLine("Did this work in an older version?");
if (regression === "Yes") desired.add("regression");

Crash Detection (.github/workflows/issue-triage.yml L121

):

if (lower.includes("crash") || lower.includes("crashed") || lower.includes("fatal"))
desired.add("crash");

I18n Detection (.github/workflows/issue-triage.yml L122

):

if (lower.includes("translation") || lower.includes("localization") || lower.includes("i18n"))
desired.add("i18n");

Needs Triage (.github/workflows/issue-triage.yml L96

):

if (action === "opened" || action === "reopened") desired.add("needs-triage");

The needs-triage label is only added for new or reopened issues, not on edits.

Sources: .github/workflows/issue-triage.yml L96-L122


The complete label taxonomy used by the automated triage system:

LabelSourceMeaning
uiBug Report, Feature RequestVisual or UI-related issue
qolBug Report, Feature RequestQuality-of-life feature or bug
performanceBug Report, Feature RequestPerformance, FPS, or memory issue
accessibilityBug Report, Feature RequestInput handling, readability, usability
gameplayBug Report, Feature RequestGameplay modifier (opt-in features)
moddingBug Report, Feature RequestMod integration or API issue

Sources: .github/workflows/issue-triage.yml L47-L55

LabelMeaningTypical Effort
scope:smallSmall tweak or simple optionHours to 1 day
scope:mediumNew setting or moderate logic1-3 days
scope:largeMulti-part feature requiring planning1+ weeks

Sources: .github/workflows/issue-triage.yml L57-L62

Impact/Constraint Labels (Feature Requests Only)

Section titled “Impact/Constraint Labels (Feature Requests Only)”
LabelMeaning
impact:performanceCould affect CPU/GPU/memory usage
impact:conflictsMight conflict with other mods
needs:keybindRequires input mapping configuration
opt-inShould be disabled by default
multiplayerAffects multiplayer or co-op behavior
i18nNeeds localization or translation support

Sources: .github/workflows/issue-triage.yml L64-L71

LabelMeaning
repro:alwaysBug reproduces 100% of the time
repro:intermittentBug reproduces inconsistently

Sources: .github/workflows/issue-triage.yml L73-L79

LabelApplied WhenMeaning
needs-triageIssue opened or reopenedNeeds maintainer review
regression”Did this work in an older version?” = YesPreviously working, now broken
crashBody contains “crash”, “crashed”, or “fatal”Causes crash or fatal error
bugBug report submittedAuto-applied by template config
enhancementFeature request submittedAuto-applied by template config

Sources: .github/workflows/issue-triage.yml L96-L122

.github/ISSUE_TEMPLATE/bug_report.yml L4

.github/ISSUE_TEMPLATE/feature_request.yml L4


sequenceDiagram
  participant User
  participant GitHub Issues
  participant Issue Form Template
  participant GitHub Actions
  participant issue-triage.yml
  participant Issue Tracker

  User->>GitHub Issues: Click "New Issue"
  GitHub Issues->>Issue Form Template: Load bug_report.yml or feature_request.yml
  Issue Form Template->>User: Display form with validations
  User->>Issue Form Template: Fill required fields
  Issue Form Template->>GitHub Issues: Submit (creates Markdown body)
  GitHub Issues->>Issue Tracker: Create issue with labels from template
  Issue Tracker->>GitHub Actions: Trigger on issues:[opened]
  GitHub Actions->>issue-triage.yml: Execute workflow
  issue-triage.yml->>issue-triage.yml: Parse issue body with regex
  issue-triage.yml->>issue-triage.yml: Extract form field values
  issue-triage.yml->>issue-triage.yml: Map values to labels using maps
  issue-triage.yml->>issue-triage.yml: Add special labels (crash, regression)
  issue-triage.yml->>issue-triage.yml: Merge with preserved labels
  issue-triage.yml->>Issue Tracker: setLabels(finalLabels)
  Issue Tracker->>User: Issue labeled and ready for review
  loop [Issue Edited]
    User->>Issue Tracker: Edit issue body
    Issue Tracker->>GitHub Actions: Trigger on issues:[edited]
    GitHub Actions->>issue-triage.yml: Re-run labeling logic
    issue-triage.yml->>Issue Tracker: Update labels
    User->>Issue Tracker: Reopen closed issue
    Issue Tracker->>GitHub Actions: Trigger on issues:[reopened]
    GitHub Actions->>issue-triage.yml: Re-run + add "needs-triage"
    issue-triage.yml->>Issue Tracker: Update labels
  end

Sources: .github/workflows/issue-triage.yml L1-L144

.github/ISSUE_TEMPLATE/bug_report.yml L1-L273

.github/ISSUE_TEMPLATE/feature_request.yml L1-L210


AspectBug ReportFeature Request
Template Filebug_report.ymlfeature_request.yml
Default Labelsbugenhancement
Required Fields118
Version TrackingYes (mod + game versions)No
CategorizationYes (7 categories)Yes (7 categories)
Scope EstimationNoYes (small/medium/large)
Reproduction InfoYes (frequency + regression)No
Impact AssessmentNoYes (6 constraint checkboxes)
Environment InfoYes (OS/CPU/GPU/RAM)No
Acceptance CriteriaNoYes (definition of done)
Conflict ChecksYes (other mods + solo testing)No
Applied Scope LabelsNonescope:small/medium/large
Applied Repro Labelsrepro:always/intermittentNone
Applied Impact LabelsNoneimpact:*, needs:*, opt-in, etc

Sources: .github/ISSUE_TEMPLATE/bug_report.yml L1-L273

.github/ISSUE_TEMPLATE/feature_request.yml L1-L210