chrismdp / issue-to-pull-request

An issue becomes a pull request

Public ·
Version 16 of 23
  1. #23 · chrismdp · · 0.8Latest
  2. #22 · chrismdp · · 0.6
  3. #21 · chrismdp · · 0.6
  4. #20 · chrismdp · · 0.6
  5. #19 · chrismdp · · 0.6
  6. #18 · chrismdp · · 0.6
  7. #17 · chrismdp · · 0.6
  8. #16 · chrismdp · · 0.4Showing
  9. #15 · chrismdp · · 0.4
  10. #14 · chrismdp · · 0.4
  11. #13 · chrismdp · · 0.4
  12. #12 · chrismdp · · 0.4
  13. #11 · chrismdp · · 0.4
  14. #10 · chrismdp · · 0.4
  15. #9 · chrismdp · · 0.4
  16. #8 · chrismdp · · 0.3
  17. #7 · chrismdp · · 0.3
  18. #6 · chrismdp · · 0.3
  19. #5 · chrismdp · · 0.3
  20. #4 · chrismdp · · 0.3
  21. #3 · chrismdp · · 0.3
  22. #2 · chrismdp · · 0.3
  23. #1 · chrismdp · · 0.3
Fork

workflow.yaml

workflow.yaml is AWML 0.4, as it was pushed. The registry draws, checks and fits it converted to AWML 0.8.

# An issue the maintainer labels build becomes a change on main. The
# repository is public, so everything here sits in one scope: anyone may read the issues, the
# threads and the branches. What matters is who may act. Only people with write access, and the
# repository's own app, can add a label, so the label is the decision. Claude drafts with a
# read-only token. Once the checks pass, two fresh Claude sessions that didn't write the change
# review it, one for bugs and one for security, against REVIEW.md. An Important finding sends the
# change back to Claude to fix, as another try. When the reviews are clear, a third fresh session
# classifies the change's risk, and the repository's app opens the pull request. A code rule then
# decides whether the change is straightforward, by rules the maintainer wrote down, and the
# classifier can send a change to review but never skip one. If it is straightforward, the app sets
# it to merge by itself. If not, the person who added the label reviews and merges
# it from their own account, which is their yes. Either way main's own rule holds the merge until CI
# has passed on the branch. Answering new issues with options is left out: it reads the
# maintainer's private notes, so it stays an interactive session.
#
# The app pushes, opens and merges, because GitHub starts other workflows from what an app does but
# not from what the Actions token does. So CI runs on every pull request and shows on it, and a
# merge starts CI on main and the rebase workflow, as a person's merge would.
#
# A change that alters what a drawing or a page shows is redrawn and pictured before it opens: the
# check job redraws the examples into the change, and takes before and after pictures of what
# changed, as images, or as a short animation only for something that moves. A picture that looks
# the same before and after is left out, so a change to the renderer shows only the drawings it
# really changed. The app pushes the pictures
# to a branch kept for them, and the pull request shows them. Claude writes the pull request's
# description in Markdown, and it opens with why the change needs review, if it does, then Claude's
# note as written.
#
# The build keeps one comment on the issue saying where it has got to. It posts it as it starts,
# before Claude drafts, and edits it on each retry, when the pull request opens, and when it fails.
# A failure, or a build that changes nothing, is also posted as a new comment, since GitHub sends
# no notification for an edit.
#
# A build can also be started by this workflow when a draft fails its checks or its reviews find
# something Important. It tries three times in all, each time telling Claude why the last try
# failed. After three, a check that still fails is commented on the issue. Findings still open
# after three open the pull request anyway, listed at the top, and it waits for review.
#
# A change that needs review is put in front of the person who added the build label, as a review
# request on the pull request. A retry carries that person's name with it. A build whose label the
# app added, for a failing main, has no such person, so it asks the repository's owner.
#
# The actions implementation runs it on GitHub Actions. GitHub decides whether a label
# starts anything, before any runner exists. A first job posts the status comment, and Claude
# works in the next. The checks run in a third job that can only read, so Claude's code never
# runs where a token can push. The reviews and the classifier run in a fourth job that can only
# read, each its own session. A fifth job, which runs nothing from the change, pushes the branch,
# opens the pull request, applies the rule and sets the merge. None of these jobs shares another's
# access, so Claude can't write the verdict the merge relies on. Claude's session sits inside the
# draft job's block, since it shares that job's access. CI is its own workflow, and GitHub holds
# main's rule.
awml: "0.4"
title: A decision on an issue becomes a change on main
scopes:
  - { id: public, label: "public: anyone who reads the repository", processing: any }
parts:
  - { id: comment, kind: trigger, label: "The build label is added to an issue", wait: PT1H }
  - { id: dispatch, kind: trigger, label: "A failed try starts the build again" }
  - { id: pushed, kind: trigger, label: "The app pushes the pull request's branch" }
  - { id: token, kind: connector, label: "The repository, through its own Actions token", in: public }
  - { id: app, kind: connector, label: "The repository, through its own GitHub App", in: public }
  - { id: who, kind: code, op: sort, label: "Sort by rule: is the label build?", in: public }
  - { id: started, kind: code, op: do, label: "Post the build's status comment on the issue, or on a retry edit it with the try and why the last one failed", in: public }
  - { id: update, kind: code, op: do, label: "Edit the status comment: the pull request it opened and whether it merges by itself or waits for review, or why the build failed", in: public }
  - { id: status, kind: outside, label: "Post or edit the build's status comment: Allow", in: public }
  - { id: bring, kind: code, op: bring-in, label: "Bring in the issue and the comments of the repository's own people", in: public }
  - { id: repo, kind: context, label: "The spec, guide, code, AGENTS.md and REVIEW.md, which says what failure looks like here", in: public }
  - { id: build, kind: ai, op: draft, label: "Write the change test first", in: public }
  - { id: patch, kind: context, label: "The change, as a patch, with Claude's note and its description for the pull request", in: public }
  - { id: gate, kind: code, op: check, label: "Run the tests, vet, the examples and wasm parity", in: public }
  - { id: render, kind: code, op: do, label: "Redraw the examples the change alters, and picture only those whose picture looks different, before and after", in: public }
  - { id: review, kind: ai, op: check, label: "Review the patch for bugs, with fresh context, keeping only the findings that survive a second look", in: public }
  - { id: secreview, kind: ai, op: check, label: "Review the patch for security, in a separate session", in: public }
  - { id: findings, kind: context, label: "The reviews' record of their findings, each Important, Nit or Pre-existing", in: public }
  - { id: classify, kind: ai, op: sort, label: "Sort by risk: does a person need to look at this change?", in: public }
  - { id: risk, kind: context, label: "The classifier's verdict and its reasons", in: public }
  - { id: pictures, kind: context, label: "The before and after pictures", in: public }
  - { id: media, kind: code, op: do, label: "Push the pictures to the branch kept for them", in: public }
  - { id: mediaout, kind: outside, label: "Push to the pictures branch: Allow", in: public }
  - { id: failed, kind: context, label: "The check's record of why it failed", in: public }
  - { id: tries, kind: code, op: sort, label: "Sort by rule: has it tried three times, and what is still wrong?", in: public }
  - { id: again, kind: code, op: do, label: "Start the build again, with why this try failed or what the reviews found", in: public }
  - { id: report, kind: code, op: do, label: "Comment on the issue with why the build failed", in: public }
  - { id: issuenote, kind: outside, label: "Comment on the issue: Allow", in: public }
  - { id: open, kind: code, op: do, label: "Push a branch and open a pull request that closes the issue", in: public }
  - { id: pr, kind: outside, label: "Open the pull request: Allow", in: public }
  - { id: ci, kind: code, op: check, label: "CI runs every check on the branch", in: public }
  - { id: rules, kind: context, label: "The build rules: what needs a review", in: public }
  - { id: judge, kind: code, op: sort, label: "Sort by rule: does the change touch a path that needs review, delete a test, change over 400 lines, leave a finding open, or did the classifier ask for review?", in: public }
  - { id: automerge, kind: code, op: do, label: "Set the pull request to merge once CI passes, saying in its message why it was straightforward", in: public }
  - { id: ask, kind: code, op: do, label: "Ask the person who added the label to review the pull request", in: public }
  - { id: askout, kind: outside, label: "Request a review: Allow", in: public }
  - { id: merge, kind: person, op: do, label: "Review the pull request and merge it", in: public }
  - { id: account, kind: connector, label: "The repository, through the reviewer's own account", in: public }
  - { id: held, kind: code, op: sort, label: "Sort by main's rule: has CI passed on the branch?", in: public }
  - { id: landauto, kind: code, op: do, label: "Merge the change the app set to merge", in: public }
  - { id: land, kind: code, op: do, label: "Merge the reviewer's change", in: public }
  - { id: mainauto, kind: outside, label: "Merge a straightforward change into main: Allow", in: public }
  - { id: main, kind: outside, label: "Merge a change that needed review into main: Ask", in: public }
  - { id: strangers, kind: comment, label: "Anyone can comment, but the bring-in step passes on only the comments of the owner, members and collaborators, so strangers' text never reaches the draft step. AWML can't mark this yet (awml #5)" }
  - { id: label, kind: comment, label: "Only people with write access and the repository's app can add a label, and GitHub holds that, not a prompt, so a stranger's comment starts nothing. The draft step's token can only read, so it can't push (awml #26)" }
  - { id: verdict, kind: comment, label: "The check runs where the draft step can't reach, and its verdict is in its own record (awml #13, #20)" }
  - { id: terms, kind: comment, label: "Allow, because a merge is undone with git revert, everything in it is already public on its branch, and the maintainer would not be surprised by a change the rule finds straightforward. One the rule sends to review is where they would be, so that merge is Ask. Installs of the plugin pick up either only at a release, which stays the maintainer's yes, though a new install takes main" }
  - { id: escalate, kind: comment, label: "The classifier can send a change to review but can't skip one, and the agent that wrote the change has no say. The rule reads the patch itself: what it touches, its size and whether it deletes a test (awml #20, #26)" }
  - { id: starts, kind: comment, label: "GitHub starts other workflows from the app's pushes, merges and labels, so CI runs on the pull request and a merge starts CI on main and the rebase workflow. The app's key is a secret in each repository it's installed on, and each run's token reaches only its own repository" }
  - { id: noskip, kind: comment, label: "Main's rule holds every merge, the app's and the maintainer's, until CI passes. Only the maintainer may skip it, to push a release; the app may not" }
  - { id: seen, kind: comment, label: "Only a change to what a drawing or a page shows is pictured, and a picture that looks the same before and after is left out, even when the renderer changed. A moving image only for something that moves. GitHub plays only video uploaded through its web page, so a moving change is pictured as an animated image, which it shows inline" }
  - { id: layout, kind: comment, label: "The description opens with why the change needs review, as bullets, with the classifier's reasons and any open findings, then Claude's note as written, then what changed, the decisions the issue didn't settle, the pictures, and the issue it closes" }
  - { id: whoasked, kind: comment, label: "Each retry carries the name of the person who added the label. A build whose label the app added, with no such person, asks the repository's owner" }
  - { id: onecomment, kind: comment, label: "One status comment per build. It carries a hidden marker, so a retry finds it again without passing anything between runs, and a new build label starts a new one" }
  - { id: fresh, kind: comment, label: "The reviewers and the classifier never see the drafting session, and read the patch, not the issue's thread. Their read-only token can't push, comment or merge, and a finding is answered by a fix or by the maintainer" }
  - { id: same, kind: comment, label: "Only this workflow starts a retry, and only for an issue a label already started" }
lines:
  - { from: comment, to: who, kind: start, label: "the label" }
  - { from: who, to: started, kind: start, label: "[build]" }
  - { from: started, to: bring, kind: start }
  - { from: started, to: status, kind: data }
  - { from: status, to: token, kind: data }
  - { from: automerge, to: update, kind: start, label: "merges by itself" }
  - { from: ask, to: update, kind: start, label: "waits for review" }
  - { from: report, to: update, kind: start, label: "failed" }
  - { from: update, to: status, kind: data }
  - { from: token, to: bring, kind: data, label: "the issue's thread" }
  - { from: bring, to: build, kind: data, label: "the issue and its people's comments" }
  - { from: repo, to: build, kind: data }
  - { from: build, to: patch, kind: data }
  - { from: patch, to: gate, kind: data }
  - { from: dispatch, to: started, kind: start, label: "the issue" }
  - { from: gate, to: render, kind: start, label: "[all pass]" }
  - { from: render, to: review, kind: start }
  - { from: review, to: secreview, kind: start }
  - { from: patch, to: review, kind: data }
  - { from: patch, to: secreview, kind: data }
  - { from: repo, to: review, kind: data }
  - { from: repo, to: secreview, kind: data }
  - { from: secreview, to: classify, kind: start, label: "[no Important finding in either review]" }
  - { from: secreview, to: tries, kind: start, label: "[an Important finding]" }
  - { from: patch, to: classify, kind: data }
  - { from: repo, to: classify, kind: data }
  - { from: findings, to: classify, kind: data }
  - { from: classify, to: risk, kind: data }
  - { from: classify, to: media, kind: start }
  - { from: findings, to: again, kind: data }
  - { from: findings, to: build, kind: data, label: "what the reviews found" }
  - { from: findings, to: judge, kind: data }
  - { from: findings, to: open, kind: data }
  - { from: risk, to: judge, kind: data }
  - { from: risk, to: open, kind: data }
  - { from: patch, to: render, kind: data }
  - { from: render, to: patch, kind: data, label: "the redrawn examples" }
  - { from: render, to: pictures, kind: data }
  - { from: pictures, to: media, kind: data }
  - { from: media, to: mediaout, kind: data }
  - { from: mediaout, to: app, kind: data }
  - { from: media, to: open, kind: start, label: "the pictures' links" }
  - { from: gate, to: tries, kind: start, label: "[a check fails]" }
  - { from: tries, to: again, kind: start, label: "[fewer than three]" }
  - { from: tries, to: report, kind: start, label: "[three, a check fails]" }
  - { from: tries, to: media, kind: start, label: "[three, findings open]" }
  - { from: failed, to: again, kind: data }
  - { from: again, to: started, kind: start, label: "the issue and why it failed" }
  - { from: failed, to: build, kind: data, label: "why the last try failed" }
  - { from: failed, to: report, kind: data }
  - { from: report, to: issuenote, kind: data }
  - { from: issuenote, to: token, kind: data }
  - { from: patch, to: open, kind: data }
  - { from: open, to: pr, kind: data }
  - { from: pr, to: app, kind: data }
  - { from: pushed, to: ci, kind: start, label: "the branch" }
  - { from: open, to: judge, kind: start, label: "[opened]" }
  - { from: patch, to: judge, kind: data }
  - { from: rules, to: judge, kind: data }
  - { from: judge, to: automerge, kind: start, label: "[straightforward]" }
  - { from: judge, to: ask, kind: start, label: "[needs a review]" }
  - { from: ask, to: askout, kind: data }
  - { from: askout, to: token, kind: data }
  - { from: ask, to: merge, kind: start, label: "the review request" }
  - { from: account, to: merge, kind: data, label: "the pull request and CI's result" }
  - { from: automerge, to: held, kind: start, label: "the merge, set" }
  - { from: merge, to: held, kind: start, label: "the merge" }
  - { from: ci, to: held, kind: start, label: "the result" }
  - { from: held, to: landauto, kind: start, label: "[passed, set by the app]" }
  - { from: held, to: land, kind: start, label: "[passed, by the reviewer]" }
  - { from: landauto, to: mainauto, kind: data }
  - { from: land, to: main, kind: data }
  - { from: mainauto, to: app, kind: data }
  - { from: main, to: account, kind: data }
  - { from: strangers, to: bring, kind: tie }
  - { from: label, to: comment, kind: tie }
  - { from: verdict, to: gate, kind: tie }
  - { from: terms, to: mainauto, kind: tie }
  - { from: escalate, to: judge, kind: tie }
  - { from: starts, to: app, kind: tie }
  - { from: noskip, to: held, kind: tie }
  - { from: same, to: dispatch, kind: tie }
  - { from: fresh, to: review, kind: tie }
  - { from: onecomment, to: started, kind: tie }
  - { from: whoasked, to: ask, kind: tie }
  - { from: seen, to: render, kind: tie }
  - { from: layout, to: open, kind: tie }
implementations:
  actions:
    label: GitHub Actions
    blocks:
      - { id: github, label: "GitHub: issues, branches, pull requests, and main's rule", parts: [comment, dispatch, pushed, token, status, app, who, repo, patch, findings, risk, pictures, mediaout, failed, pr, issuenote, askout, rules, held, landauto, land, mainauto, account, main] }
      - { id: startjob, label: "Actions job: post the status, running nothing from the issue", platform: actions-code, parts: [started] }
      - { id: draftjob, label: "Actions job: draft, with a read-only token", platform: actions-code, parts: [bring] }
      - { id: agentjob, label: "Claude Code, claude-opus-5-5, on the maintainer's subscription", platform: actions-agent, in: draftjob, parts: [build] }
      - { id: checkjob, label: "Actions job: checks, with a read-only token", platform: actions-code, parts: [gate, render] }
      - { id: reviewjob, label: "Actions job: review and classify, with a read-only token", platform: actions-code, parts: [] }
      - { id: reviewagent, label: "Claude Code, claude-opus-5-5, a fresh session for each review and the classifier", platform: actions-agent, in: reviewjob, parts: [review, secreview, classify] }
      - { id: codejob, label: "Actions job: branch, pull request, merge or retry, running nothing from the change", platform: actions-code, parts: [media, open, update, judge, automerge, ask, tries, again, report] }
      - { id: cijob, label: "Actions job: CI, with a read-only token", platform: actions-code, parts: [ci] }
      - { id: browser, label: "The maintainer's browser", parts: [merge] }