<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ignacio Joaquin Sanga Olmos</title>
    <description>The latest articles on DEV Community by Ignacio Joaquin Sanga Olmos (@elnachto).</description>
    <link>https://dev.to/elnachto</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4151312%2Fde34d978-4615-4bbd-8126-dc0e94363493.jpg</url>
      <title>DEV Community: Ignacio Joaquin Sanga Olmos</title>
      <link>https://dev.to/elnachto</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/elnachto"/>
    <language>en</language>
    <item>
      <title>Building laya-triage, part 2: today's issues, a new model, and OpenAI's Decisions API</title>
      <dc:creator>Ignacio Joaquin Sanga Olmos</dc:creator>
      <pubDate>Wed, 07 Oct 2026 16:28:17 +0000</pubDate>
      <link>https://dev.to/elnachto/building-laya-triage-part-2-todays-issues-a-new-model-and-openais-decisions-api-4m46</link>
      <guid>https://dev.to/elnachto/building-laya-triage-part-2-todays-issues-a-new-model-and-openais-decisions-api-4m46</guid>
      <description>&lt;p&gt;In the first post I shared laya-triage, a GitHub Action that labels new issues as bug, feature, question or docs with a fine-tuned &lt;a href="https://github.com/NandhaKishorM/laya" rel="noopener noreferrer"&gt;Laya&lt;/a&gt; model that runs inside the Actions runner. No API key, and issue text never leaves GitHub.&lt;/p&gt;

&lt;p&gt;v1.0 scored 88.8% on the NLBSE'23 benchmark, and I was happy with that. Then I tested it on issues people are writing today, and it dropped to 79.8%. This post is about closing part of that gap, what I added in v1.2, and what happened when I measured it against OpenAI's new Decisions API.&lt;/p&gt;

&lt;p&gt;I'm a systems engineering student still learning this field, so take it as notes from someone figuring things out, with every number measured and published in the repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmarks age
&lt;/h2&gt;

&lt;p&gt;NLBSE'23 is a great benchmark, but most of its issues are a few years old. To check how the model handles today's repositories, I collected 10,026 closed issues from 2025 and 2026, across 288 active repositories with more than 1,000 stars. I kept only issues labeled by a maintainer, not by the author or a template, and none of those repositories were used for training.&lt;/p&gt;

&lt;p&gt;On that set, v1.0 got 79.8%. Same model, nine points lower.&lt;/p&gt;

&lt;h2&gt;
  
  
  What worked, and what didn't
&lt;/h2&gt;

&lt;p&gt;My first idea was to fine-tune v1.0 on 127,140 recent issues from other repositories. It improved recent issues to 81.9%, but it lost almost a point on NLBSE'23. The model was forgetting what it already knew.&lt;/p&gt;

&lt;p&gt;So I trained v1.1 from scratch on both: the original million NLBSE'23 issues plus the recent ones, together. It kept 88.8% on NLBSE'23 and reached 82.3% on recent issues.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzgu3rjzcyebr1afat53v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzgu3rjzcyebr1afat53v.png" alt="Accuracy on recent issues by training data" width="800" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The biggest change was in questions. v1.0 recognized 43.7% of them; v1.1 recognizes 58.3%. Questions are the hardest class, because many read like bug reports ("it doesn't work when I...").&lt;/p&gt;

&lt;h2&gt;
  
  
  v1.2: things maintainers asked for
&lt;/h2&gt;

&lt;p&gt;v1.2 keeps the v1.1 models and adds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Backlog mode.&lt;/strong&gt; Run it once by hand and it labels the open issues you already have. Only the ones it's confident about, and it never comments on old issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run summaries.&lt;/strong&gt; Every run writes a table with its decisions to the workflow summary, so you can review them without reading logs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repo memory (experimental).&lt;/strong&gt; When the model hesitates between two types, the 20 most similar closed issues of your repository vote. It helps a little (82.3% to 82.7%), so it's off by default until it's tested on more real repositories.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More label names&lt;/strong&gt;, contributed by someone during Hacktoberfest, so &lt;code&gt;defect&lt;/code&gt; or &lt;code&gt;usage&lt;/code&gt; map to the right type.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Then OpenAI released a Decisions API
&lt;/h2&gt;

&lt;p&gt;On September 29 OpenAI announced a Decisions API: you give it a question and a fixed list of answers, and it returns one answer with probabilities. It's the same kind of tool as Laya or TypeSafe's Jev, so I measured it the same way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the same question, word for word, that laya-triage was trained with;&lt;/li&gt;
&lt;li&gt;the exact 5,000 NLBSE'23 issues Jev answered;&lt;/li&gt;
&lt;li&gt;the recent-issues set, used once, with nothing tuned on it;&lt;/li&gt;
&lt;li&gt;the 2026 set and 14 languages.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;laya-triage v1.2&lt;/th&gt;
&lt;th&gt;Jev&lt;/th&gt;
&lt;th&gt;OpenAI Decisions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;NLBSE'23&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;88.8%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;84.4%&lt;/td&gt;
&lt;td&gt;83.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recent issues&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;82.3%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;78.1%&lt;/td&gt;
&lt;td&gt;78.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2026 set, macro F1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.758&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.660&lt;/td&gt;
&lt;td&gt;0.602&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14 languages, avg. without English&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;85.8%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;85.1%&lt;/td&gt;
&lt;td&gt;82.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost of the recent-issues run&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;td&gt;$0.30&lt;/td&gt;
&lt;td&gt;$0.46&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The Decisions API is still in beta, so these numbers may change. I measured it on October 6, 2026.&lt;/p&gt;

&lt;p&gt;The number I find most useful isn't accuracy, though. It's what happens out of every 100 new issues:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Figg3pw65y5ywfztq55ya.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Figg3pw65y5ywfztq55ya.png" alt="Out of every 100 new issues" width="800" height="680"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All three get about 77 right on recent issues. The difference is the rest: the hosted APIs label almost everything, so 20 or 21 issues get a wrong label. laya-triage only labels when its confidence is at least 0.60, so it puts a wrong label on 12 and leaves 11 for a maintainer with &lt;code&gt;needs-triage&lt;/code&gt;. For a bot that writes in your repository, being wrong less often matters more than labeling everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A benchmark score is a starting point.&lt;/strong&gt; 88.8% on a known benchmark became 79.8% on today's repositories. Measuring on fresh data changed what I worked on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A small, specialized model can hold its own.&lt;/strong&gt; OpenAI's model is general: it can decide almost anything. laya-triage was trained for one question with more than a million examples. On that one question, the specialist does better.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Knowing when to stop matters.&lt;/strong&gt; Calibrated confidence lets the action say "I'm not sure" instead of guessing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Measure once and publish everything.&lt;/strong&gt; I decide on a validation split and use the test set only once. The scripts and raw results are all in &lt;a href="https://github.com/elnachto/laya-triage/tree/main/bench" rel="noopener noreferrer"&gt;&lt;code&gt;bench/&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Prefer to watch? There's a one-minute setup video in the &lt;a href="https://github.com/elnachto/laya-triage#quick-start" rel="noopener noreferrer"&gt;README&lt;/a&gt;. The short version:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Triage
on:
  issues:
    types: [opened]
permissions:
  contents: read
  issues: write
jobs:
  triage:
    runs-on: ubuntu-latest
    steps:
      - uses: elnachto/laya-triage@v1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It starts in dry-run mode, so it only shows what it would do until you switch it on.&lt;/p&gt;

&lt;p&gt;Next, I want to look at duplicate issues and pull requests. If you try laya-triage on your repository, I'd really like to hear how it does, and especially where it gets things wrong.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/elnachto/laya-triage" rel="noopener noreferrer"&gt;github.com/elnachto/laya-triage&lt;/a&gt;&lt;/p&gt;

</description>
      <category>github</category>
      <category>ai</category>
      <category>machinelearning</category>
      <category>opensource</category>
    </item>
    <item>
      <title>laya-triage is in Hacktoberfest: free, local AI triage for GitHub issues</title>
      <dc:creator>Ignacio Joaquin Sanga Olmos</dc:creator>
      <pubDate>Thu, 01 Oct 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/elnachto/laya-triage-is-in-hacktoberfest-free-local-ai-triage-for-github-issues-1l8f</link>
      <guid>https://dev.to/elnachto/laya-triage-is-in-hacktoberfest-free-local-ai-triage-for-github-issues-1l8f</guid>
      <description>&lt;p&gt;Every popular repository has the same problem: new issues pile up faster than maintainers can read them, and many end up mislabeled or go unaddressed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;laya-triage&lt;/strong&gt; is a GitHub Action that reads each new issue and labels it as a bug, feature request, question, or documentation problem. If a bug report is almost empty, it asks the author for the missing details. It runs a fine-tuned open-weight model inside your own GitHub Actions runner: no API key, no cost, and the issue text never leaves GitHub.&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/elnachto/laya-triage" rel="noopener noreferrer"&gt;https://github.com/elnachto/laya-triage&lt;/a&gt;&lt;br&gt;
🛒 &lt;strong&gt;Marketplace:&lt;/strong&gt; &lt;a href="https://github.com/marketplace/actions/laya-triage" rel="noopener noreferrer"&gt;https://github.com/marketplace/actions/laya-triage&lt;/a&gt;&lt;br&gt;
🤗 &lt;strong&gt;Models:&lt;/strong&gt; &lt;a href="https://huggingface.co/elnachto/laya-triage-en" rel="noopener noreferrer"&gt;https://huggingface.co/elnachto/laya-triage-en&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Try it in one minute
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;.github/workflows/triage.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Triage&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;issues&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;opened&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
  &lt;span class="na"&gt;issues&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;triage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;elnachto/laya-triage@v1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It starts in dry-run mode, so it prints decisions only in the workflow log. When you like what you see, set &lt;code&gt;dry-run: "false"&lt;/code&gt;. There are more ready-to-copy workflows in &lt;a href="https://github.com/elnachto/laya-triage/tree/main/docs/examples" rel="noopener noreferrer"&gt;&lt;code&gt;docs/examples/&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it was built
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fine-tuning:&lt;/strong&gt; I fine-tuned the open &lt;a href="https://github.com/NandhaKishorM/laya" rel="noopener noreferrer"&gt;Laya&lt;/a&gt; decision model on 1 million real issues from the NLBSE'23 benchmark, on my own GPU.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;My own dataset:&lt;/strong&gt; I collected recent issues (2025–2026) from thousands of active repositories and kept only the labels a maintainer applied, not the ones added automatically by issue templates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Honest measurement:&lt;/strong&gt; separate exams that were never used for tuning.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;88.8%&lt;/strong&gt; accuracy on NLBSE'23, within the margin of the RoBERTa research baseline (89.1%).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;79.8%&lt;/strong&gt; on 10,026 recent issues from 288 active repositories, ahead of Jev (78.1%), a paid commercial API.&lt;/li&gt;
&lt;li&gt;It adapts to each repository: it reuses your existing label names (&lt;code&gt;type: bug&lt;/code&gt;, &lt;code&gt;kind/feature&lt;/code&gt;…) and learns how common each issue type is from the issues you labeled in the last year.&lt;/li&gt;
&lt;li&gt;It never overrides a label you or your issue template already set.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to jump in
&lt;/h2&gt;

&lt;p&gt;Some &lt;code&gt;good first issue&lt;/code&gt; tasks are still open, and none of them needs a GPU:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a CI workflow for the template tests.&lt;/li&gt;
&lt;li&gt;Unit tests for the repository-adaptation logic.&lt;/li&gt;
&lt;li&gt;Translate the README to Spanish.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most valuable contribution of all: &lt;strong&gt;install it in your repo and tell me when it gets a label wrong&lt;/strong&gt; (there’s an issue form for that). Those reports are the training data for the next model.&lt;/p&gt;

&lt;p&gt;Please read the &lt;a href="https://github.com/elnachto/laya-triage/blob/main/CONTRIBUTING.md" rel="noopener noreferrer"&gt;contributing guide&lt;/a&gt; and leave a comment on an issue prior to beginning. A big thank you to the first contributors who have already submitted pull requests! Happy Hacktoberfest 🎃&lt;/p&gt;

</description>
      <category>hacktoberfest</category>
      <category>opensource</category>
      <category>ai</category>
      <category>github</category>
    </item>
  </channel>
</rss>
