Changelog¶
All notable changes of the issue assistant. The complete notes of every version, with each pull request, are on the releases page. Versions follow Semantic Versioning; a change of a template that repositories must install again is a new minor version, and one that breaks their settings a new major version.
Unreleased¶
Features¶
ISSUE_ASSISTANT_FIXTUREmay now name a file with a discussion, so you can try the first answer to a question in Discussions on one that exists nowhere, as you could with an issue. Write the discussion with its comments and their replies as GitHub's GraphQL API gives it, under the keydiscussion;contextandapplywith the taskdiscussion-answerthen read it instead of one on GitHub, and write nothing.applyanswers it as a run by hand does, whatever its category, but never when it is closed or locked.- Each release of the workflow of the discussions has run before you get it: every pull request of the issue assistant that changes it now runs its jobs on a discussion of a file, as a dry run, as it did for the workflow of the issues. A broken step, permission or condition shows there, not as a missing answer in your repository.
installandchecknow notice a repository that neither Dependabot nor Renovate looks after, whose pins would stay on the release of its set-up and never get a fix:installnames the step in its last line, andcheckwarns, without failing, when there is no.github/dependabot.ymlwith the ecosystemgithub-actionsand no configuration of Renovate. Get started lists the update tool among the requirements and has a new section, Turn on updates, with the few lines for Dependabot.- A repository that starts with the assistant can now have the issues that were already open analyzed too. A maintainer runs
issue-assistant.ymlby hand with the new taskbacklogand0as the issue: it takes the oldest open issues without a first analysis, up tobacklog_per_runof[engine]inconfig.toml, 20 by default, and leaves out those that a new issue would not have had analyzed either, such as a maintainer's own or a muted one. As every run by hand, it starts as a dry run, and the summary shows for each issue its labels, a possible duplicate and the missing information. With the dry run off, it sets the labels alone and posts no comment on the old issues, unless you tick the new inputcomment. The summary names the last issue that it took, after which the next run goes on. The runs on the backlog count toward no daily limit, and only the rolesadminandmaintainstart them. Install the templates of this release to get the task and the new jobbacklogofissue-assistant.yml; Runs by hand shows it. - The daily digest lists the questions in Discussions that wait on the maintainers, where
[discussions] answer_categoriesnames a category: an open question without a marked answer whose last word is not a maintainer's, at once when the asker or someone else wrote last, such as a reply that the first answer didn't help, and after 3 days when nobody answered or nobody marked the assistant's first answer. Before, such a question appeared nowhere, since discussions have no labels, reminders or closings. The monthly quality numbers count the first answers of the 30 days as well: how many the asker marked as the answer, and their 👍 and 👎.
Added¶
- Get started on the website has a part Remove the assistant: the workflows and files to delete, the environment with the engine's secret and the variables, the issues that nothing reminds or closes any more, the setting of GitHub that the set-up cleared, and the notice to reporters.
- The README and the home page show three real first analyses instead of one: a bug in HomeDarts traced into the lines of its code, a feature request in Paperless Sync, and an answer in the reporter's Chinese with a summary in English for the maintainer.
Bug fixes¶
- A read from GitHub now runs again after 2, 4 and 8 seconds whenever the connection broke off for a moment, as it did after a server error, not only after a reset connection or a few timeouts. A connection that GitHub refused or closed early, a name that DNS didn't resolve and a timeout while waiting for GitHub's answer no longer end the step, and with it the daily sweep, at the first try.
- An issue that the morning sweep closed for a missing answer stays open when a maintainer reopens it by hand. Before, it kept
needs-infoandstale, and the next sweep closed it again within hours, without a comment. Now that sweep takes both labels away, addsneeds-triageand leaves the issue to the maintainer; a new question, or/assistant waiting, starts a new waiting as usual. - A pull request that describes the bug with a negation before it names the fix, such as
The cache didn't refresh and this fixes #12orSo it doesn't crash anymore - fixes #12, now fixes the issue: it getsfixed-in-next-releaseand closes with the release. Before, any not, never or n't among the four words before the keyword counted as words against the fix, and the issue stayed open for good. Now only a negation right before the keyword, or with nothing but a filler such as yet, fully or on its own in between, or through an infinitive such asis not meant to close #12, keeps the issue open, and the summary of the sweep names each issue that stays open so. - A reporter who adds the missing answer by editing the text of an issue that closed for a missing answer now gets it reopened, as the questions and the closing comment promise: the issue reopens with
needs-triage, and the assistant follows up on the answer. Before, only a comment reopened it, and the edit went unnoticed, also by the digest, which lists open issues only. A new title or a click on the box of the form alone still reopens nothing. - The comment that closes an issue with a release promises only what happens on that issue. It names the days of
reopen_after_release_daysin which a comment of the reporter reopens it, 30 by default. On a muted issue, where no AI reads such a comment, it no longer says that the issue reopens: it asks the reporter to write for the maintainers. Their comment there, also long after the release, now gives the issueneeds-triage, so that the digest lists it under Waiting on the maintainers and the sweep doesn't lock it until a maintainer answers. Before, it reached the maintainers only as a notification of a closed issue. The new text is in all fourteen languages. - The notice What happens with your issue in
SUPPORT.mdno longer keeps old waiting periods unnoticed.checknow fails when a line of the notice thatinstallwrote names other days than[lifecycle]sets, or still describes the closing with a release or the locking after you turned them off, and runninginstallagain writes the new days into such a line or takes it out. A line that you rewrote in your own words stays as it is. - The check that keeps tokens and keys out of every comment now knows more kinds of them. A key of the Google APIs, the kind of key that the Gemini engine holds, and the tokens of GitLab, Stripe, Hugging Face and Telegram bots refuse the answer wherever they are, as the tokens of GitHub, Anthropic and OpenAI did. So do long runs of one case and digits, which slipped past before: 64 or more characters of hex and 40 or more of Base32 or of lower case and digits. A commit, the fingerprint of a signing key and a digest that names its algorithm, such as
sha256:in the digest of an image orSHA-256:and a space before the checksum of a release, still pass; a digest without its algorithm now refuses the answer, since nothing tells it apart from a key. - The short excerpts of other issues and discussions that the AI searches for duplicates and related issues keep every word of the reporter. The text above the first field of an issue form, such as an error message, no longer goes; a field that comes twice keeps each of its answers; and a
###line in a code block, such as a pasted changelog, stays part of the excerpt's text instead of being read as a field of a form. The labels and the opt-out box of a form read every heading as before, so a code block that a reporter leaves open never hides the box. - A new code scanning alert fails one run of the Findings workflow again, not two or three. The scans of a push end close together, so their Findings runs overlap, and a run that read the record of the reported alerts before the run ahead kept its new one failed for the same alert once more. Now a run looks for a newer record once its turn has come, and when one is there, it names the alerts that its own record lacks with a warning and leaves them to that record: the next run fails for any alert that the newer record doesn't hold.
checknow names a.github/egress-firewall.yamlof the wrong shape as one problem of the set-up and goes on with the other checks, where it ended with a Python traceback before: an empty file, a list in place of the mapping of the template,allowwith a single host in place of a list, and an item ofallowthat is no host name, such as a number or a mapping. A host given as a string afterallow:is no longer read letter by letter. The job event of a run on a runner with Harden-Runner names such a policy with the same lines.- A 👎 on a duplicate notice from an account that no longer exists no longer fails the daily sweep of that issue. GitHub gives such a reaction without a user, and the sweep asked GitHub for the permission of an empty name, which failed the issue in every sweep, so the notice never closed the issue or cleared, and the Lifecycle run stayed red. Such a reaction now objects to nothing, also when the reporter's account is gone as well, and an account that GitHub doesn't know may not push wherever the assistant asks.
- The comments that the assistant writes without the AI, such as the reminder, the closing notice and the notes of a duplicate, a fix or a release, guess the reporter's language better before the first analysis. A Spanish report is no longer taken for Italian, and a short report of one sentence in French, German, Dutch or Italian no longer gets its comments in English: the words that two languages share, such as the "una" of Spanish and Italian, count for neither, each catalog knows more frequent words of its language, and letters that only one language writes count for it, such as ñ for Spanish, ß for German, ã for Portuguese, œ for French and ò for Italian.
- A reporter's comment on an issue that the assistant closed as a duplicate now reaches the maintainers, as the closing comment promises. The issue gets
needs-triageand stays closed, since whether it is a duplicate is the maintainers' call; the digest lists it under Waiting on the maintainers, and the sweep doesn't lock it, until a maintainer answers in a comment. Before, the comment went unnoticed unless a maintainer happened to read GitHub's notification of it. - A comment in German now links the German notice to reporters: the footer of an analysis, a follow-up and a duplicate notice links the first file of
[transparency] filesthat ends in.de.md, such asSUPPORT.de.md, at its heading Was mit deinem Issue geschieht. Before, every comment linked the first file, mostly the English one. A comment in English, or in a language without a notice of its own, links the first file as before. - The AI's text no longer makes headings in a comment by underlining a line with
===or---, or with#inside a quote or a list item: the cleaning now escapes such a line and removes such marks, or escapes them deeper in a list, as it did with#at the start of a line. - The error of a failed check of the network block now links the page Troubleshooting of the website at an address that exists. Before, it led to a page that wasn't found.
- The workflow
issue-lifecycle.ymlthatinstallwrites no longer waits for a workflow named Release integration, which no repository has any more; it starts at the end of the workflow Release, as before. - A feature request no longer hears of a fix and of a problem that persists. When a pull request closes an issue with the label
enhancementor the issue type Feature, and without the labelbug, the comment at the merge says that the pull request implemented it, and the comment at the release asks the reporter to update to use it and to write a comment if something is missing; the AI that reads that comment reopens the issue when what it asked for is still missing or doesn't work. Every other issue keeps the words of a fix. Both kinds read alike in all 14 languages, under the same hidden markers, so the sweeps and the digest read old and new comments alike. - The notes of a release that updates an engine name the engine and its versions, such as "update the Gemini CLI to 0.66.0 (was 0.65.0)", so the pull request that moves your pin says which version of the command line of Codex, Gemini or Copilot your analyses run from then on. The pull requests that update the action of Claude Code or of Codex, which make no release, name their versions in the title too. They said only "update the other engines" before, as in 1.10.6, whose entry in the changelog now names the Gemini CLI 0.66.0 and the Codex CLI 0.166.0. The action of Codex and its command line now come in pull requests of their own.
- The FAQ, the README and How it works name the fifth workflow,
discussion-assistant.yml, which answers discussions with the engine whereanswer_categoriesnames categories, as the starter does. The FAQ said that deleting four workflows turns off everything, which left that one answering. checkandinstallread the issue forms and the workflows right on a computer without PyYAML, where they read YAML withyq: a label such asGerätstaysGeräton Windows, where it turned intoGerätbefore, and one such asÁmbitono longer ends the step with aTypeError. Output ofyqthat is no UTF-8 is now named as a file that isn't valid YAML.- A pull request that fixes more than ten issues now gets
fixed-in-next-releaseonto each of them, up to a hundred, and a release closes an issue only once it ships every fix of up to a hundred pull requests that name it; before, the eleventh and every later one went unnoticed. Where more than a hundred are named, a notice in the summary of the sweep says which part was not read. - Get started now creates the branch policy of the environment by hand for the default branch of the repository, as
install --setupdoes, instead of a fixedmain: a repository onmasterordevelopgot an environment that its runs could not use. - The short excerpts of other issues and discussions that the AI reads now hold only what GitHub shows of their text, as the text of the issue itself always did. An HTML comment without its end below a heading of an issue form now hides the rest of the text there too, and HTML tags go with their attributes, such as the
altof a picture or thetitleof a link, which GitHub never shows as text. - The AI now reads only what GitHub shows of the Markdown of an issue, its comments and the excerpts of other issues and discussions, also without the link reference definitions, such as
[//]: # (a comment), the usual way to write a comment in Markdown, and without footnotes that nothing refers to, which GitHub shows as nothing. A note such as(link definition removed)takes the place of each, and a notice in the log of the run counts them, as it counts the invisible characters. A line that only looks like a definition, such as[ERROR]: Failedwithin a paragraph or in fenced code, stays as GitHub shows it. - A link of the AI's answer to a file or folder of the repository stays a link only when it names a ref that the checkout of the
applyjob has:HEAD, a branch or tag of the repository, or a commit of the default branch's history. A link to any other commit, such as one of a fork, now shows as code, as a link to another site does. The links of the assistant's own references, to the analyzed commit and toHEAD, are as before.
1.10.6 (2026-11-10)¶
Bug fixes¶
- deps: update the Gemini CLI to 0.66.0 (was 0.65.0) and the Codex CLI to 0.166.0 (was 0.164.0) (#311) (759bfb1)
1.10.5 (2026-11-09)¶
Bug fixes¶
- On
ubuntu-24.04-firewall, the default runner of the AI, Harden-Runner no longer starts its agent beside the engine, and each analysis there takes about 15 s less. Its step was skipped there, but GitHub still ran the step before it that installs the agent. The AI on the runner thatISSUE_ASSISTANT_AI_RUNNERnames now runs in a job of its own, Analyze with the AI engine on the runner in reserve, with the same steps behind Harden-Runner, so a run shows that job as skipped beside Analyze with the AI engine. It comes with the next move of the pin, withoutinstall. - The Canary now measures the wait of the AI for its runner also when the variable
ISSUE_ASSISTANT_AI_RUNNERnames the runner in reserve. It looked only atanalyzeonubuntu-24.04-firewall, so with the variable set it reported analyze was skipped and would never notice a runner in reserve that finds no machine, such as a version of Ubuntu that GitHub doesn't have yet. Now it measuresanalyze-in-reservein its place, with the same warning above 10 minutes and failure above 30 and the issue of bot-health, and its summary names the job and gives advice for that runner. Only the Canary of this repository changes; repositories that use the action notice nothing. - A pull request that moves a finding that
.github/findings.tomlaccepts, such as a false positive on a line that now has another number, no longer waits for a person to resolve the review thread of its new alert. After each scan of a pull request of the repository itself, the Findings workflow dismisses the alerts of the pull request thatfindings.tomlof the default branch accepts, which resolves their threads; the other alerts there fail no run, and a fork's pull request keeps its threads for a person. It comes with the next move of the pin, withoutinstall. - A job of the reusable workflows no longer writes to your repository without the block of Harden-Runner. When Harden-Runner has no agent that blocks, because GitHub's outage kept it from downloading the agent, as on 8 November 2026, or StepSecurity's service is unavailable, the jobs
event,apply,sweep,sync-labelsandfindingsran without any block and passed. Now each stops at the new step Make sure that Harden-Runner blocks, with the annotation Harden-Runner doesn't block, before any step reaches a host, and can run again; no step that runs after a failure, such as the cache of the findings, runs without the block. A repository that skips Harden-Runner by the custom propertyskip-harden-runnerof StepSecurity takes the property away. In a private repository without a subscription of StepSecurity, the jobs run as before. It comes with the next move of the pin, withoutinstall.
1.10.4 (2026-11-09)¶
Bug fixes¶
- The jobs of the reusable workflows no longer hang until their timeout, or fail to reach GitHub, on GitHub's runners in
westus2when StepSecurity's service doesn't answer Harden-Runner in time: they run Harden-Runner 2.22.4, which then takes GitHub's DNS experiment out of its way as well. On the runner thatISSUE_ASSISTANT_AI_RUNNERnames,analyzealso makes sure itself, right after Harden-Runner, and stops at once, before the engine runs, when it can't; onubuntu-24.04-firewallnothing changes. It comes with the next move of the pin, withoutinstall. evaluateand the Evaluate workflow no longer fail on a repository without a closed issue to replay, one whose closed issues people never labelled after they were opened or closed as a duplicate, or that the assistant analyzed itself. Such a run now passes without a report, and its notice counts why it left out each closed issue it read, such as those that a bot opened or whose only label came with their form, and says what an issue needs to be replayed. The workflow then skips publishing, so the accuracy page keeps its numbers, and no failure mail goes out for a repository that has nothing to measure.evaluatenow counts the labels that a maintainer, or their coding agent, set as they opened their own issue, such as withgh issue create --label bug: they are the maintainers' choice, so the replay no longer sees them and the AI's answer is scored against them. Until now such an issue counted as one whose only labels came with its form, soevaluateleft out almost every issue of a repository whose maintainer labels his own issues. The labels of the issue form that an issue was opened with still count for nothing:evaluatefinds that form among.github/ISSUE_TEMPLATE/of the checkout by the first field that the text begins with, so it reads YAML with PyYAML oryqnow, ascheckdoes. A maintainer's own issue counts in no measure of the questions for more information, since no maintainer would ask its reporter.
Older releases
1.10.3 (2026-11-08)¶
Bug fixes¶
- The Findings workflow no longer fails after every scan while an alert stays open; it fails once, when the alert opens. It runs after each scan of code scanning on the default branch and every morning, and GitHub mails the maintainer about every failed run, so one open alert made up to four failed runs for each push and one more every morning. Now the job keeps a record of the alerts that it reported, each with the time it opened, in the Actions cache of the default branch: a run fails only for an alert that opened since, also one that a scan finds again after its fix, and the runs after it pass and name the alert as still open, with a warning, until it is fixed or accepted in
.github/findings.toml. Without a record, as in the first run after the update, every open alert fails one run. It comes with the next move of the pin, withoutinstall; besidesapi.github.comandgithub.com, the job reaches GitHub's results service of the cache.
1.10.2 (2026-11-08)¶
Bug fixes¶
- The AI runs only once its runner proves that the network block holds. Before, only the runner in reserve behind Harden-Runner was checked; on
ubuntu-24.04-firewall, the default, nothing noticed when GitHub's egress firewall, a technical preview, didn't enforce.github/egress-firewall.yaml, such as for a job withoutcontents: read, withmode: log, or after a change of the preview. Now, on every runner,analyzeasks forexample.com, a host of no policy, and forapi.github.combefore any step gets the engine's secret, and stops with an error that names the likely causes when the one answers or the other doesn't. This takes about five seconds per analysis, needs noinstall, and comes with the next update of the pin.
1.10.1 (2026-11-07)¶
Bug fixes¶
- The scripts of the maintainers in
scripts/and the Canary and Evaluate workflows ask GitHub for the same version of its REST API as the action,2022-11-28, on every call ofgh api, so they no longer follow whatever version GitHub serves by default; a new call without it fails a test. - A release no longer closes an issue that a pull request only refers to. GitHub links an issue to a pull request also where its description says the opposite, such as
This doesn't close #12orPartly fixes #12, and the assistant took that link for a fix: it labeled the issuefixed-in-next-releaseat the merge and closed it with the release. Now such words keep the issue as it is, open and without the label, and the comment of the release names only the pull requests that fix the issue.Fixes,ClosesandResolvesclose an issue as before, and so does a link made by hand in the box Development of a pull request.
1.10.0 (2026-11-03)¶
Features¶
- A run of the issue assistant by hand takes an instruction now, such as "ask for the logs", which the AI follows in its first analysis or follow-up within its rules, and the box override, with which a maintainer has the assistant answer an issue again past its one comment, when the extra run is worth its cost. Without the override, a run by hand on a task that already has its comment, or on a follow-up that is not due, ends before the AI and costs nothing; until now, every run by hand answered again. The workflow checks who started the run, also through the REST API or a run again: write access starts it, and only the roles
adminandmaintainoverride, and the summary of the run names every override. Install the templates of this release to get the new inputs; Runs by hand shows them.
1.9.1 (2026-11-03)¶
Bug fixes¶
- The Copilot engine works with version 1.0.103 of its command line, which removed the flag
--no-remoteand stops at it. In its place the analysis now passes--sync-session=off, so that a run on a runner stays out of the history of the Copilot account. Remote control takes a command or a flag of its own to start, and the analysis passes neither.
1.9.0 (2026-11-01)¶
Features¶
- The page How accurate is it? can now show real numbers. A new workflow of this repository, Evaluate, runs
evaluateby hand on GitHub's runner with the egress firewall, and a job without an AI takes only the numbers of its report into a pull request, as a table for each repository with the day, the engine, the model and the counts. The new commandaccuracy-pagewrites them, and refuses a report that has anything else in their place. [digest] issue = truein.github/issue-assistant/config.tomlkeeps what the morning sweep says of what waits on whom in one issue as well, which you pin to the top of the Issues tab. The first sweep opens it, each later one edits it without notifying anyone, and there is never a second one. A comment or a command on it starts nothing and the AI never reads it. It is off by default.- The morning digest names good first issue candidates for the maintainers to confirm. Where
.github/labels.tomlhas labels of the new groupcontribution, as the starter'sgood first issueandhelp wantednow do, the first analysis also judges whether someone new to the project could take the issue. It changes no comment and no label: a maintainer who has triaged the issue finds it in the fourth part of the digest and adds the label, and the monthly quality numbers count what became of the candidates. - The footer of every analysis, follow-up, answer and first answer in Discussions now ends with a link to the issue assistant, in the language of the comment, so that someone who likes what they read can find the tool that wrote it. The link mentions nobody, and
[transparency] credit = falsein.github/issue-assistant/config.tomlleaves it out. The README and the set-up guide also offer a badge that shows that a repository uses the assistant. installgives a repository without issue forms a feature request form and an issue chooser, next to the bug report form. The chooser turns blank issues off and sends questions to the discussions where[discussions] answer_categoriesnames a category, vulnerabilities to private reporting and everything else toSUPPORT.md, with links that name the repository itself. A repository that has forms gets nothing new.checkasks for the repository wheninstallcouldn't find it, and names a chooser that is no valid YAML, which GitHub ignores without a word. In Discussions, the answer to a feature request now links the feature request form where the repository has it.- A reporter can say no to the AI: the starter forms of
installhave a box Automated analysis, and a ticked box mutes the issue when it opens, or when the reporter clicks it later. No run of the AI starts on the issue, its text stays out of what the AI reads for other issues, and labels, reminders and the closing with a release go on. The reporter lets the AI in later with/assistant again.[forms] opt_out_fieldnames the field, andcheckvalidates it. A repository with forms of its own adds the field and the line of the notice by hand: Saying no to the AI shows how.
Changes¶
- The code of the action is now a package instead of one long script. Nothing changes for a repository that uses the action or its workflows. Whoever runs a command by hand writes
PYTHONPATH="$dir" python3 -P -m issue_assistant checkinstead ofpython3 "$dir/issue_assistant.py" check, as the getting started guide shows. - The action is now tested on
ubuntu-26.04, whichubuntu-latestmeans since 2026-10-19, and onubuntu-24.04-arm, besideubuntu-24.04. The README names these supported runners.
Bug fixes¶
- On a Python older than 3.12, or without
python3, as in a job of your own onubuntu-22.04or on a self-hosted runner, the action now stops in its first step with an error that names the version it found and how to fix it, instead of a traceback or a run that no test covers. - The short jobs of the reusable workflows no longer hang after their last step, until their timeout, when Harden-Runner is still removing Docker: every job that runs without sudo and containers now waits for that, for up to two minutes, as its last step.
- The checkout of a job of the reusable workflows no longer fails right after Harden-Runner, on an address that the runner had asked for before the block began: every job that blocks now waits until Harden-Runner lets its hosts through, for up to two minutes, and then warns and goes on. On the runner that
ISSUE_ASSISTANT_AI_RUNNERnames,analyzewaits for GitHub's hosts only, so that an engine that you don't use can't hold it up. - The jobs of the reusable workflows no longer hang until their timeout, or fail to reach GitHub, on GitHub's runners in
westus2: they run Harden-Runner 2.22.3, which lets the allowed hosts through there. - On the runner that
ISSUE_ASSISTANT_AI_RUNNERnames,analyzeno longer stops with Harden-Runner let a request to example.com through when the agent of Harden-Runner starts a few seconds late: the step asks for up to a minute until the block holds, and fails as before when it never does.
1.8.0 (2026-10-25)¶
Added¶
- Seven more languages for the assistant's own words: Chinese, Japanese, Korean, Russian, Ukrainian, Polish and Turkish. A reporter who writes in one of them now gets the thanks, the headings, the questions, the reminders, the closings and the notes of a release in their language, with days as they write them, such as 2026年11月2日, 2026년 11월 2일 or 2 ноября 2026 г., instead of English with 2026-11-02 around the AI's words. Russian and Ukrainian name a number of days in the form that the number asks for, as in 1 день, 2 дня and 5 дней. The new catalogs are machine drafts, and native speakers are welcome to improve them.
- The comments without AI, such as a reminder before the first analysis or the notice of a duplicate that a maintainer named, now recognise Chinese, Japanese and Korean, which the guess of the language couldn't see, since Chinese and Japanese leave no space between their words: a Chinese issue got an English reminder. Now the letters that only one language writes count for it, Hangul for Korean, kana for Japanese with the Chinese characters beside them, and Chinese characters alone for Chinese, and Russian and Ukrainian are told apart by the letters that only one of them has. The page What reporters see shows the first analysis and the reminder in Chinese, Japanese and Russian too.
Changed¶
- A patch version of an engine, such as a new release of the Claude Code action from 1.0.248 to 1.0.249, reaches the next release of the issue assistant sooner: it no longer waits for the maintainer once the check of the engine's names, which runs every update of an engine without a key, has passed. A minor or major version of an engine still waits for the maintainer, as before.
1.7.0 (2026-10-25)¶
Added¶
- A runner in reserve for the AI. The analysis runs on
ubuntu-24.04-firewall, GitHub's runner with the egress firewall, which is a technical preview: should GitHub rename or end it, every analysis of a repository waited in the queue for a day, and every later run of the same issue behind it, until a new release. Now the repository variableISSUE_ASSISTANT_AI_RUNNERnames another runner for the AI at once, such asgh variable set ISSUE_ASSISTANT_AI_RUNNER --body ubuntu-24.04. There Harden-Runner blocks every host but those of your.github/egress-firewall.yamlas the first step of the analysis, and the next step stops the job when a request to another host gets through, as in a private repository without a subscription of StepSecurity. The jobeventrefuses a runner where nothing would block, such as a self-hosted one orubuntu-latest, andchecknames it too when your CI passes the variable. With the variable unset, everything runs as before; decision 0019 explains what the fallback gives up. checknow also refuses a host of.github/egress-firewall.yamlthat is no host name in full, such aslocalhostor one with a port, since Harden-Runner takes the same hosts on the fallback runner.- A summary for the maintainers in their own language when the reporter writes in another one. An analysis, a follow-up or a first answer in Discussions that the AI writes in Japanese, Portuguese or any other language than the maintainers' now ends with a folded block, such as For the maintainers, in English: the key facts of the issue in a faithful translation and the gist of the answer, cleaned as every text of the AI. So a maintainer can triage the issue and check what the AI claims without a translator, inside the one comment that the assistant posts. The reporter sees one short, labelled line. A comment in the maintainers' own language has no such block, nor has one on a possible vulnerability. The maintainers read English unless
[maintainers] languageofconfig.tomlnames another catalog, such aslanguage = "de";checkfails on a code without a catalog, such aspt-BR, and names the one that was probably meant.
Changed¶
- A dry run of the lifecycle or the findings, such as one that you start by hand, no longer waits for the morning sweep or another run of its workflow, and no longer takes the place of one that waits: it writes nothing, so it starts at once.
- Every job of the reusable workflows now stops with an explanation when GitHub names no commit of the workflow in the context of the job. Before, the checkout would have taken your repository at its default branch and run its own
action.yml, or failed with a puzzling error. - The reusable workflow of the discussions skips every job when a workflow calls it for another event than a new discussion or a run by hand, instead of failing in its job
event.
Security¶
- Gemini keeps to its tools that read again. The Gemini CLI takes its system settings, which leave it only the tools that read files of the checkout and turn off MCP servers, extensions, agents, skills, hooks, telemetry and checkpoints and set its turns, only from a folder that root owns. On GitHub's runners they were in a folder of the runner's user, so it skipped them with no more than a warning and ran without them. Now
analyzeandevaluatewrite them with sudo into a folder of root's below/etc/issue-assistant, and stop rather than run Gemini without them;evaluateruns Gemini only on Linux, macOS or WSL. A new check, engine contracts, found it: on every update of an engine and every week, it runs the pinned versions of the engines without a key and fails when an input of an engine's action, a flag of its command line or a key of its settings that keeps it to reading is gone, or when Gemini no longer refuses broken settings in the file that it should read. - Gemini and Copilot now run exactly the packages that were checked.
analyzeinstalled the Gemini CLI and the Copilot CLI withnpm installat a pinned version, so npm picked every package below them anew in each run, with the engine's secret in the job: a broken or malicious release of one of their dependencies would have reached every repository at once. Now the issue assistant ships a lock file for each, inengines/, with the SHA-512 hash of every package, andanalyzeinstalls it withnpm ci, which refuses a package with another hash and stops the analysis before anything of it runs. npm runs in a folder of its own, without the scripts of the packages and without the engine's secret. The check engine contracts verifies the signature of npm's registry and the attestations of every package that npm installs from the lock files on GitHub's Ubuntu x64 runner, whereanalyzeruns, whenever they change and every week, and that npm refuses another hash. Renovate keeps the lock files current, and its updates wait for the maintainer. The inputengine-versionof the action is gone, since the lock file names the version; a workflow of your own that still passes it gets a warning from GitHub and runs the locked version.
1.6.1 (2026-10-19)¶
Fixed¶
- The Labels workflow no longer fails when another workflow created a label a moment before, such as the settings bot of Repo Blueprint, which the same push starts when it changes
.github/labels.toml, as the first push of a new repository always does.sync-labelsthen gives the label the color and the description oflabels.toml, as any label that exists, and/assistant mutedoes the same for its label.
1.6.0 (2026-10-19)¶
Added¶
- Updates without
install. The four workflows thatinstallwrites are short now: what starts them, the permissions that their jobs need at most, and one pin of a reusable workflow of the issue assistant, which has the jobs and runs the action of the same release. A release reaches your repository as a pull request of Dependabot or Renovate that moves the pins, and only a release that changes a template needsinstallagain. Runinstallof this release once, as step 1 of the set-up shows; your secret, variables and firewall policy stay as they are..github/actionlint.yamlno longer needs the runnerubuntu-24.04-firewall, which is now in the reusable workflow. - The assistant learns from your corrections. Every first analysis reads what the maintainers corrected of the analyses of the 30 issues analyzed last: the labels you removed or added, the duplicate notices that someone objected to, and the analyses that one of you gave a 👎, and the AI avoids those choices on an issue like them. GitHub keeps all of it, so correcting the issue is all it takes. The AI gets the corrections as data, one line per issue with its number, title and labels; reading them costs one call to GitHub for each issue and a few more, and
[context] max_analyzedinconfig.tomlsets the number of issues,0none. - Three more engines next to Claude: Codex by OpenAI, Gemini by Google and Copilot by GitHub. Set
nameunder[engine]inconfig.tomltocodex,geminiorcopilot, and put its secret into the environmentissue-assistant:OPENAI_API_KEY,GEMINI_API_KEYorCOPILOT_GITHUB_TOKEN, a fine-grained token with the permission Copilot Requests alone and no access to repositories. Gemini starts for free, within the daily limits of the free tier of the Gemini API. Each engine only reads: Codex in the read-only sandbox of its action, and the Gemini CLI and the Copilot CLI, which the action installs and runs itself, with only their tools that read files and without the job's token of GitHub.installwrites the hosts of your engine alone into a new.github/egress-firewall.yaml,checknames each host that your engine needs and your policy lacks, and the notice to reporters names the engine and its vendor.applynow also takes an answer with a sentence before or after its JSON. Runinstallof this release once: the workflowissue-assistant.ymlpasses the secrets of the new engines. - Priorities, owners of areas and issue types, each when you want them, in
.github/labels.toml. With labels of the new grouppriority, such aspriority: high, the AI gives an issue without a priority the one whose description fits, with its reason on the timeline, and never changes one that the issue has or adds back one that someone removed; a possible security report gets none.owners = ["login"]of an area assigns those people to a new issue of the area that nobody is assigned to: when its form chose the area, and after the first analysis; GitHub notifies them, and no comment mentions them; an issue that someone unassigned anyone from stays as it is.issue_type = "Bug"of a kind gives its issues that issue type of your organization, and the type follows the kind while an issue needs triage, to none for a kind without a type; a type that no kind has, such asEpic, stays.checkmakes sure of their spelling, and the Labels workflow warns of an owner whom GitHub can't assign and of an issue type that the repository doesn't have. Without them, nothing changes. - Measure how accurate the assistant is in your repository before you switch it on.
evaluatereplays the first analysis of the closed issues that your maintainers labelled after they were opened or closed as a duplicate, 50 unless--issuesasks for another number, each as it was a minute after it was opened, with the engine's command line on your computer, logged in as you, and writes a Markdown report: the precision and recall of the types, areas, topics and priorities, of the duplicates and of the questions for more information, and a line for each issue. It writes nothing on GitHub. The new page How accurate is it? explains the numbers and will have those of the repositories that use the assistant. - Related issues from sibling repositories. Name up to 5 public repositories that share your users, such as an app and its server, in
[related] repositoriesofconfig.toml, and every first analysis searches their issues too, links those that help under Related once it checked that they exist, and says in one sentence when an issue may belong in one of them, which the summary of the run names as well. Nothing moves or closes on its own: you transfer the issue by hand, and an issue of another repository is never a duplicate. A repository that isn't public is left out with a warning, since its issues would show in a public comment. - A first answer to questions in Discussions. Name the categories in
[discussions] answer_categoriesofconfig.toml, such asanswer_categories = ["Q&A"], and runinstallof this release once: it writes the workflowdiscussion-assistant.yml, and every new discussion of those categories gets an answer of the AI from the code, the documentation, the issues and the other discussions, checked and cleaned as every analysis. The assistant posts one comment and never marks it as the answer, which the asker can do; it stays out of a discussion that a maintainer joined first, and a bug or a feature request gets a link to the form of an issue. The answers count towardmax_per_dayandmax_per_author_per_daytogether with the new issues. Without a category, as before, nothing changes, also for a repository that only moves its pins: the new workflow is the only one that may write to discussions. The starterconfig.tomlof a new set-up namesQ&A, and the notice to reporters thatinstallwrites names the categories.
1.5.0 (2026-10-14)¶
Added¶
- A set-up in four steps, without looking up a hash.
installtakes the commit and the tag of the release from its own clone, sogit clone --depth 1 --branch vX.Y.Zandinstallare enough; it refuses the object of an annotated tag, whichgit ls-remotelists first, with the commit to use instead, and a commit or tag that isn't its checkout, whose templates it writes.install --setupalso creates the environmentissue-assistanton GitHub, for the default branch only, and has the GitHub CLI ask for the engine's secret.installnow writes everything thatcheckasks for: the section What happens with your issue inSUPPORT.md(in German for a file such asSUPPORT.de.md) where it doesn't name the AI yet, the runner of the AI and the ignoredqueuein an existing.github/actionlint.yaml, and, together with the starter labels, a bug report form with an Area field for a repository without issue forms, whose answers the labelsarea: setupandarea: docsmap. Each step looks first, so runninginstallagain changes nothing but the workflows. The README's set-up ends with a step that tries the assistant on an existing issue as a dry run, and turning off GitHub's auto-close of issues by merged pull requests is a step of its own. - When a workflow or the firewall policy doesn't fit,
checknames the commands that write the templates of its release anew. - Your own lifecycle in a new section
[lifecycle]ofconfig.toml: the days until the reminder (remind_after_days, 15) and the closing (close_after_days, 30) of an issue without an answer, until a sure duplicate closes (duplicate_grace_days, 3), the window after a release in which the reporter's comment reopens the issue (reopen_after_release_days, 30), and how often the AI follows up (max_follow_ups, 2). The comments name the days that you set, in English and German, and so does the section What happens with your issue thatinstallwrites.checknames a period that can't work, such as a closing before the reminder, and a description ofneeds-info,staleorpossible-duplicateinlabels.tomlthat names other days. - Exempt issues: the sweep never reminds or closes an issue with a label of
exempt_labels,pinnedandsecurityunless you set others, and, if you like, one assigned to someone (exempt_assignees) or with enough 👍 (exempt_upvotes). - Old threads can lock: with
lock_closed_after_days, the sweep locks issues closed for longer as resolved, with one line that points to a new issue, 25 in a sweep. It never locks before the window after a release is over, an exempt issue, or one that someone unlocked. It is off unless you set it. - A maintainer digest in the summary of the morning sweep: the open issues that wait on the maintainers (triage pending for more than 3 days, a reporter's answer, an objection to a duplicate notice), those that wait on their reporters with the day of the reminder or the closing, and the fixed ones that wait for a release, each a link, the longest waiting first and, among those of a day, the one with the most 👍.
- How well the assistant does, on the first day of each month and in every sweep started by hand: for the 30 days before, the analyses posted, the median time from a new issue to its analysis, how many labels of the AI the maintainers kept and how many they added, what became of the duplicate notices and of the questions to reporters, and the 👍 and 👎 on the analyses. The summary holds numbers and links only, never the text of an issue.
- Slash commands: maintainers steer the assistant from the issue, with a comment whose first line is the command.
/assistant againasks for a new analysis,/assistant askand a question gets the AI's answer from the code, checked as every answer before it is posted,/assistant duplicate #12starts the closing of a duplicate afterduplicate_grace_days(3 by default) and/assistant not-duplicatestops it,/assistant waitingmarks the issue as waiting for its reporter, and/assistant muteand/assistant unmutekeep the AI from starting anything on its own on the issue and let it again. The reporter may saynot-duplicate, and ask once for a new analysis while the issue waits for triage, within the limits of the day. A 👀 on the comment shows that the command was carried out, a 😕 that it was refused, and the run says why. Runinstallagain, which adds the taskmaintainer-questionto Run workflow. - Answers in the reporter's language. Besides English and German, the assistant now writes French, Spanish, Portuguese, Italian and Dutch, with its own words from a catalog for each language in
locales/, including the days of the lifecycle and the dates of reminders, such as 2 novembre 2026. In any other language, the AI writes in it and the headings and the footer stay English, with dates such as 2026-11-02. The reminders, closings and release notes of the sweep keep the language of the analysis, which its hidden marker records, and before an analysis the reporter's own words decide. A new language is one more file inlocales/; the French, Spanish, Portuguese, Italian and Dutch texts are machine drafts that native speakers are welcome to improve. - Each task runs with its own model, turns and budget, from
[engine]inconfig.toml.light_modelruns the replies to one comment, which only say whether a maintainer's comment waits for the reporter or whether a problem persists after a release, on a cheaper model;max_turns(40) bounds a first analysis and a maintainer's question, a follow-up gets half of it and a reply a tenth, where every task had 40 turns before;max_budget_usd($1.00) stops a run at that cost, so that no issue can make one run cost more; andeffortsets how much a model thinks.checkrefuses values that the engine can't run with. The summary of every analysis job shows in one line, numbers only, what the run cost: its turns, time, dollars and tokens, also after a failure, with a warning that names the setting when the run stopped at its turns or its dollars. Install the workflows again to get it.
Changed¶
- The rules of the assistant are the engine's system prompt, apart from its task, instead of the start of one prompt in which the issue's own words competed with them.
contextwrites them into.issue-assistant/rules.md, and its outputpromptkeeps both for the workflows of earlier releases until you install them again. - Every analysis and follow-up says what it is and asks whether it helped. Its footer links How the assistant works, the part What happens with your issue of your
SUPPORT.md, or of the first file of[transparency] files, and asks for a 👍 or 👎 on the comment; the summary of the morning sweep, or of one started by hand, counts them for the analyses and follow-ups of the last 30 days, as numbers only. On a duplicate notice, the footer says that a 👎 also keeps the issue open, as before. - A long analysis keeps its questions in view: more than three links to related issues and files fold into one line below the questions, such as Where to look: 5 links, that opens them. A reminder links the comment with the questions that it reminds of.
- The comments speak of the maintainers, not of one maintainer, and the information needed says that an answer reopens the issue if it closes, not while it is still open.
- An analysis reads a window of the repository instead of every issue and pull request: every open issue, the 1,000 closed issues and the 1,000 discussions that changed last, and for a new issue up to 30 older issues that a search for its errors and the words of its title finds, so that old duplicates are still found. In a repository with tens of thousands of issues, the context stays small and takes a few calls to GitHub instead of hundreds.
[context] max_issuesandmax_discussionsinconfig.tomlset the numbers. Each other issue comes with an excerpt of 400 characters, the pull request that fixed it, and its whole text for the AI to read when the excerpt looks promising. - Deciding whether a maintainer's comment waits for the reporter, or whether the reporter's comment after a release says the problem persists, reads only the issue and that comment, no longer every issue and discussion of the repository.
Fixed¶
- A link to a line of a Markdown file, or of another file that GitHub shows rendered, such as reStructuredText, AsciiDoc, a notebook or an SVG picture, opens the file's source at that line. Before, it opened the rendered page, where a line has no anchor. A path with a backtick stays one piece of code in its link.
- Issues and discussions that the AI names as
#123stay links when they exist, up to ten of them, as the prompt asks it to name them. Before, every number but those of the duplicates and related issues showed as code. - An issue that waits for its reporter closes on the day that its reminder names. The morning sweep starts a few minutes later on some days than on others, and when it started later on the day of the reminder than on the day it named, the issue closed a day late. The waiting now counts days of the calendar, in UTC, and the reminder records its day.
- An answer by an edit of the issue, which the questions offer, ends the waiting also when the event workflow missed it, so the issue no longer closes as unanswered, and a run again of the analysis no longer marks it
needs-info. A second edit after a follow-up gets its own follow-up, as a second comment does. - A new title is no answer. Fixing a typo in it removed
needs-info, stopped the reminder and started a follow-up of the AI with nothing new to read. - A comment of the reporter reopens an issue that closed for a missing answer also when an answer came in while the sweep closed it and took its labels. An issue that closed in another way since its last reopening stays closed.
- No follow-up is posted once a maintainer joined the conversation while the AI wrote it.
- A comment that someone else writes while the AI reads the reporter's comment after a release, such as "still broken for me too", no longer reopens an issue whose reporter just confirmed the fix: the AI judges the comment that started its run, not the newest one, and the issue reopens only for a comment of its reporter. In the same way, only the maintainer's comment that started the run can mark an issue as waiting for its reporter.
1.4.0 (2026-10-14)¶
Added¶
- Try the assistant on an issue that exists nowhere: name a JSON file with the issue and its comments, as GitHub's REST API gives them, in the environment variable
ISSUE_ASSISTANT_FIXTURE, andcontextandapplyread that issue instead of one on GitHub and write nothing, as in a dry run. The project's own Canary analyzes such an issue every week with the engine, on the firewall runner, so that an update of the engine's action, a host that the firewall blocks or an expired secret shows before a release instead of as issues without an answer.
Fixed¶
- A fix that the morning sweep finds at the very end of the 14 days that it looks back closes its issue with the release that shipped it, as every other fix does. Before, the sweep labeled the issue but no longer counted the fix by the time of the label, so the issue waited for the next release, and its comment didn't name the fix. The sweep also no longer reads the issues that a recent merge names and that are closed already, most of them, so a busy repository spends far fewer of the 1,000 requests an hour that its token has, which its other workflows need too.
Security¶
- A table in the AI's text can no longer cut its code in two. GitHub splits every row of a table at each
|, also inside code, so code such as`x|#1 https://example.com`in a row turned into text that referenced an issue and linked to another site, also in a table of one column, in a quote or in a list item. A line such as--|--or:-:, which starts a table below its header, now shows as text, so the AI's text holds no table; the AI is asked not to write tables. A code block that closes with a shorter fence than it opens with, such as~~~~~~and~~~, now counts as text too: GitHub's block ran on past it, into the next part of the comment, until the fence of the next code block closed it, and showed that code as text. A checked issue number right after an@, as in#0@GH-7, becomes code: once#0was code, GitHub read@GH-7as a mention of the user GH-7. A lonewww., which GitHub links to the hostwww, becomes code. A link whose target holds a(, or entities that spell.., such as.., no longer stays a link: GitHub's target runs on past the)that closes a(, and reads the entities, so either could lead out of the repository. New tests found all of these: they judge whole comments by a model of GitHub's rendering of their own, and fuzz them.
1.3.1 (2026-10-13)¶
Fixed¶
- A fixed issue that waited for an answer gets
fixed-in-next-releaseagain also when GitHub fails to list the releases while the morning sweep sees the merge. Since 1.3.0 the sweep asked first whether a release already ships the fix, so such a failure keptneeds-infoorstaleon the issue, and the same sweep could remind its reporter or close it as unanswered. Now the labels come first, and the release closes the issue as before.
1.3.0 (2026-10-13)¶
Changed¶
- The action is ready for the GitHub Marketplace, as Read-only issue assistant, because another action there is already called Issue Assistant, and with a purple badge. Workflows keep using
Dennis-Otto/issue-assistantas before. The README opens with what the assistant does, why an issue can't make its AI write, and three commands that install the latest release; the action, the repository and the website describe it as AI issue triage, and the repository has the topics that people browse, such astriage,claude-codeandprompt-injection. - The website loads only the pictures that it shows: the copy for the other theme is no longer downloaded, so the home page needs about half the data, 650 KB instead of 1.25 MB on a phone. The still pictures are lossless WebP instead of PNG, at less than a third of the size, and keep their place on the page while they load.
- On a phone, the animation of the life of an issue stands upright, with text that is readable, on GitHub and on the website. Readers who asked their system for less motion see a still picture of the first analysis instead. Diagrams on the website scroll sideways on a phone instead of shrinking their text to a few pixels.
- The four workflows changed; run
installagain. Repositories of the repository blueprint get them with its next update. The Findings workflow also starts after the scans of Workflow security and OSV-Scanner on main, so their new findings are accepted or reported at once, not the next morning. The jobs without the AI run onubuntu-24.04instead ofubuntu-latest, the version of the AI's firewall runner, so a new image of Ubuntu never reaches your repository untested. actionlint 1.7.12 doesn't know thequeueof a concurrency group yet: if your repository runs it, let it ignore that message forissue-assistant.yml, as step 9 of the set-up shows.
Security¶
- Strangers can no longer run up the bill of the AI. Every new issue started a paid analysis, every answer of a reporter a follow-up, and every comment of a reporter in the 30 days after a release closed their issue another decision, without any limit and also all at once, so that a flood of issues could cost money or use up a subscription that other repositories share. Now the runs that people who don't maintain the repository start have limits, under
[engine]inconfig.toml: 20 analyses of new issues, follow-ups and replies after a release in the 24 hours before (max_per_day), 3 analyses of the new issues of one reporter (max_per_author_per_day), and 2 comments of the reporter after each release (release_replies). Every new issue counts, also while the first analyses still run, so a flood at once starts no more; a follow-up or a reply after a release counts as it starts, and deleting comments gives a reporter no more of them. Over a limit, an issue keeps its labels andneeds-triagefor the maintainer, and the run notes which limit it reached; maintainers and runs by hand are never limited. Without the settings, the defaults apply, so no repository needs to change anything;checkrefuses a limit that isn't a whole number of 0 or more. - The jobs of the workflows that write,
event,apply,sweep,sync-labelsandfindings, reach only GitHub: Harden-Runner blocks every host butapi.github.comandgithub.com, and no step can use sudo or containers to lift the block. A compromised action or tool in a job with a write token can no longer send it anywhere else. The block holds in public repositories, and in private ones with a subscription or trial of StepSecurity, the maker of Harden-Runner; without one, the jobs run as before. StepSecurity receives the repository, run and job of each of these jobs and the hosts that its steps connect to. The action turns off the telemetry of the GitHub CLI, which would only knock at a blocked host. - One issue can no longer stall the AI analysis of a whole repository. Each analysis reads the text of every issue, and some crafted texts, such as a form heading
###followed by many blanks, or many<!--or<awithout an end, kept the reading busy for hours, so every later analysis ran until its job timed out. The answers of issue forms, HTML comments and tags are now read in time that grows only with the length of a text, at most GitHub's 65,536 characters. The AI reads at most 20,000 characters of each text of its issue, marked "(shortened)" after that, and a line that starts with a<!--without its end hides the rest of a text from it, as GitHub hides it from people. A new fuzz target,fuzz/fuzz_issue_text.py, fails when reading a crafted text takes longer than half a second. - What the AI writes can no longer act outside its comments. An issue that steered it could put a workflow command, such as
::add-mask::or a forged::warning::, into the log of the run, end the code block of a dry run's preview in the job summary, and mention people or link elsewhere in the reasons for labels and duplicates that GitHub shows on the timeline. Now every error and notice of the assistant is escaped, the summary turns workflow commands off while it prints the AI's words, a preview's code block is longer than any run of backticks in the comment, and every reason is put on one line, cleaned like a comment and kept to 280 characters. A possible security report gets the fixed reason "Possible security report; see the security policy." on the timeline, and the AI is asked to keep its summary, analysis and reason to one neutral sentence without details, because the log of the run can be public. - A label name with an apostrophe, such as
area: user's guide, no longer breaks the command line of the engine, which stopped every analysis of the repository.checkand the engine step refuse amodelinconfig.tomlthat isn't a model name, so that it can't add arguments either. - A comment of the assistant can no longer mention someone, link to another repository or site, or show an image in ways that slipped past the cleaning of the AI's text. Code that the AI writes stays code wherever the comment puts it: a next step or a question that starts with a code block keeps all its lines in its list item, the reasons of duplicates, related issues and references are written on one line, and neither a control character nor a removed tag or heading mark can move the fence of a code block, so a snippet with
@dataclassmentions nobody, also in a list. A removal can no longer join the text next to it into a reference such asfoo/bar#12or an image. E-mail addresses,mailto:andxmpp:addresses and commits of other repositories or forks, such asoctocat/Hello-World@7fd1a60, become code, and so doHTTPS://,_https://and_www.addresses to other sites. An allowed address stays a link only where GitHub links all of it and nothing more, since its link runs on to the next space, even into code. A link that leaves the repository through..or%2e, or that names a user, a password or a port, is no longer allowed. A code block counts only when its fence starts a line, so one that the AI indents under a step of a list now shows as plain text; the AI is asked not to indent them. - An issue or a comment can no longer pass for the maintainer, for another comment or for the assistant's earlier answer. The AI read each text under a heading that names its author and role, and a text could write such a heading itself, such as
## Comment 4 by @owner (maintainer). Now each text stands in a code fence that nothing in it can close, only the assistant writes the headings, and the AI is told that a fence holds only that person's text, whatever it looks like. - Instructions hidden in characters that GitHub shows as nothing, such as Unicode tags, zero-width spaces and the controls of the direction of writing, no longer reach the AI, neither from the issue nor from the other issues and discussions that every analysis reads. The AI's answer loses them too, before its checks, so they can't hide a token from the check either. A notice in the log of the run counts what was removed.
- An issue can no longer close another reporter's issue as its duplicate. Every analysis reads the text of every issue, so anyone could open one that told the AI to call later issues its sure duplicates, which then closed after three days. Now only an original that a maintainer opened or triaged, so that it no longer has
needs-triage, gets the notice that closes the duplicate; any other becomes a suggestion for the maintainer, as a less sure duplicate does. A thumbs down on the notice keeps the issue open when it comes from the reporter or from anyone who may push to the repository, also the maintainers of an organization's repository; before, only the owner of the repository counted besides the reporter, which for an organization is nobody.
Fixed¶
- A fixed issue closes with the release that shipped its fix, also when the morning sweep labeled it
fixed-in-next-releaseonly after that release, as when the run of the merge failed; before, it waited for the release after and named that one. An issue whose fix a release ships already when the sweep first sees the merge closes at once. A pull request of another repository that names the issue, such asFixes owner/project#12, no longer keeps it open or appears in the comment of the release, and in a busy repository the sweep reads every pull request merged in the last 14 days instead of the latest 30. checkandinstallname the files of a repository with slashes on Windows too, such as.github/labels.tomlinstead of.github\labels.toml.checkandengineno longer needGH_REPO, so the check runs on your computer as well. A command that calls GitHub and finds no repository, or one that isn't written asowner/name, stops with one clear error instead of a Python traceback.- Every set-up that GitHub takes works with the assistant. The
labelsof an issue form written as one text separated by commas, such aslabels: bug, needs-triage, no longer failcheckwith an error for every letter. A label with a slash, such askind/bug, is removed and updated instead of stopping the run. A label that the repository has in another case, such asBugforbug, is renamed instead of failing to be created, since GitHub ignores the case of label names. An area dropdown withmultiple: trueadds the label of every option that the reporter chose; before, it added none. - Mistakes in the settings are named instead of crashing every command or passing unnoticed. A
labels.tomlorconfig.tomlthat isn't TOML, a section written as a key, such asengine = "claude", or a value of the wrong type, such asmax_per_day = "5", stops with an error that names the file and the key, andchecklists every such problem at once. A key that the assistant doesn't know, such asclose_with_releasesor a section[release], kept its default unnoticed; nowcheckfails on it and names the key that was probably meant, and every other run warns of it.checkalso fails on labels that differ only in case or have more than 50 characters, and on aproject.mdthat still holds the starter's first line, which the AI read before every task. Socheckmay fail after the update where it passed before: fix what it names. - An accepted finding with the
pathtestsno longer dismisses the alerts intestsuite/too: a path covers its file, or the files of its folder. A key offindings.tomlthat the assistant doesn't know, such aspaths, stops the findings command instead of accepting the findings of the rule in every file. - An analysis that links to a submodule or to a symbolic link that leads nowhere no longer fails; the link is left out. A link to a file with a blank or a bracket in its path, such as
docs/user guide (old).md, now leads to the file. - A change of the templates can be released again. The workflows and the firewall policy that
installwrites now live intemplates/, apart from this repository's own copies, which the repository blueprint brings; before, a pull request that changed a template failed the required check of the set-up.installwrites exactly what it wrote before, so no repository needs to install again. - No comment is lost while the assistant works on an issue. The runs of one issue now wait in line, up to 100, first in, first out; before, a second comment during an analysis cancelled the run of the first one, so an answer of the reporter could stay without a follow-up and a "still broken" after a release could leave the issue closed.
- The lifecycle no longer sweeps after every scheduled run of the release workflow, which runs every hour as a safety net and mostly releases nothing; the morning sweep catches a release that such a run made. A run of the lifecycle or the findings whose job has nothing to do takes no runner, and no longer cancels a waiting run that has work to do.
- An analysis that links to an issue, a release or a line on GitHub, or names a path or a class such as
src/main/java/com/example/OAuth2ClientConfiguration.java, is posted again; before, the whole answer was refused as if it held a token, and the run failed. A long run of letters and digits now counts as a key only when it has the+or=of Base64 or its letters read like noise, and never when it is the owner, repository or commit of a link to GitHub or a part of the path of a file that git tracks. Words such astask-runner-…no longer pass for a key that starts withsk-. Known kinds of tokens still refuse an answer wherever they are, and so do the addresses of Slack and Microsoft Teams webhooks now. The security page of the website shows what counts as a secret. - A rate limit or a failure of GitHub no longer changes what the assistant posts. Before, it read such an error as "doesn't exist": an analysis left out the duplicates and related issues that it couldn't look up, the AI read that the project had no release yet, and the discussions were missing from what it read. Now only "not found" means missing, and any other error stops the run with one clear error instead of a Python traceback; its summary lists what the run wrote before and the write that failed. A read that GitHub fails for a moment runs again after 2, 4 and 8 seconds, and a call that a secondary rate limit refused after a minute.
- Running a failed job of the issue assistant again completes it. An analysis or a follow-up now adds its labels before its comment, and
needs-inforight after it, so that an issue never waits for an answer to a question that wasn't posted; before, a failure after the comment lostneeds-info,possible-duplicateand the area labels for good, because a run again found the comment and did nothing, so the reporter was never reminded and a duplicate that the comment announced never closed. A run again now adds the labels that such a comment is missing, without a second comment, and leaves the labels that someone changed since then as they are. - One issue that GitHub fails no longer stops the daily sweep for every issue after it. Each issue and each step runs on its own: a failure is a warning, the others are done, and the run fails at the end so that GitHub tells you. The next sweep completes it without posting a reminder, a closing or a release comment twice, and an issue fixed by a merged pull request always gets its
fixed-in-next-releaselabel and stops waiting for an answer, even when its notice fails.
1.2.2¶
Security¶
- Coverage-guided fuzzing with Atheris now checks the cleaning of the AI's text, in a new Fuzzing workflow. It found a link without a target, images whose target ends in a line break, and a reference followed by an underscore that ends an emphasis. Brackets outside the allowed links are now escaped, so no other link or image can form, and a reference counts whatever follows its number. After the fixes, ten minutes and about 600,000 inputs found nothing.
1.2.1¶
Fixed¶
- The lifecycle also starts when a workflow named Release integration ends, as in ha-autodarts, whose releases are published with the
GITHUB_TOKENand start no workflow themselves.
1.2.0¶
Added¶
- Findings of code scanning. The new Findings workflow and
findingscommand dismiss the alerts of code scanning that.github/findings.tomlaccepts, each with its reason and comment, and fail while any other alert is open. The run names an open alert only by number and link, so nothing about a possible vulnerability reaches a public log or issue.checkvalidates the file, andinstallwrites the workflow and a starter. - Milestones of releases. A fixed issue that a release closes is filed under the milestone of the release, created closed when it is missing, so its page lists what the release fixed.
- The lifecycle also starts when the repository's Release workflow ends, because a release published with the job's
GITHUB_TOKENstarts no workflow.
Security¶
- The cleaning of the engine's text now follows the rules of CommonMark for code and catches what property tests with Hypothesis found against a CommonMark parser: backtick runs of different lengths, code spans cut by a fence or a quote on the next line, mentions and references glued to each other or to code, entities such as
@, HTML that a removal leaves behind,www.addresses, link definitions,GH-references and addresses glued to other text. A mention or a reference that the AI was steered into writing could otherwise have reached GitHub as a real one.
Fixed¶
- An address that Python can't read, such as
http://[, no longer stops the posting of an answer.
1.1.0¶
Added¶
- From the fix to the release. A merged pull request that fixes an issue marks it with the new lifecycle label
fixed-in-next-release, and the issue stays open. The first published release that contains the fix closes it as completed, with a link to the release. If the reporter writes within 30 days that the problem persists, the AI's newrelease-replytask decides, and the issue reopens. The lifecycle workflow now also runs on merged pull requests and published releases. Repositories runinstallagain, add the label to.github/labels.toml, and clear Auto-close issues with merged linked pull requests in their settings. Without releases,close_with_release = falseinconfig.tomlturns it off.
Fixed¶
installnames the firewall policy with forward slashes on Windows too.checksays what to install when neither PyYAML nor yq can read the workflows, instead of failing with a traceback.- The notice about sensitive data says what the issue shows. A secret, such as a token, a key or a password, gets a warning to remove and replace it; other personal data, such as an e-mail address or the address of a private server, gets a note that leaves the choice to the reporter. Placeholders and variable names no longer count, and a follow-up only looks at the new comments.
1.0.1¶
Fixed¶
- The templates are the three issue workflows with which this repository looks after its own issues, so Dependabot keeps their action pins current.
installcopies them with the release's commit hash in the pin of the action;checkcompares with them. Repositories set up with 1.0.0 runinstallagain. - actionlint checks every workflow of this repository again.
1.0.0¶
The issue assistant as its own action, taken from ha-autodarts, for any repository:
- A first analysis of new issues by an AI that only reads, labels with their reason, duplicates with a notice and a delay, follow-ups on answers, and
needs-infofor questions of the maintainer. - Reminders after 15 days, closing after 30 days and reopening on an answer.
- Labels as code in
.github/labels.toml. - The project's own description in
.github/issue-assistant/project.mdand settings inconfig.toml: the engine and its model, the hosts links may lead to, the field of the issue forms that chooses an area, and the files that tell reporters which AI reads their issue. installwrites the workflows and the firewall policy into a repository, andcheckkeeps them equal to the templates.